aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorNamhyung Kim <namhyung.kim@lge.com>2013-11-26 01:21:04 -0500
committerSteven Rostedt <rostedt@goodmis.org>2014-01-02 16:17:43 -0500
commit5baaa59ef09e8729aef101f7bf7d9d0af00852e3 (patch)
treeadf05e51e33e06d0d9eb9689269364314b754c2c /kernel
parent3925f4a5afa489e905a08edffc36a435a3434a63 (diff)
tracing/probes: Implement 'memory' fetch method for uprobes
Use separate method to fetch from memory. Move existing functions to trace_kprobe.c and make them static. Also add new memory fetch implementation for uprobes. Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Acked-by: Oleg Nesterov <oleg@redhat.com> Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com> Cc: zhangwei(Jovi) <jovi.zhangwei@huawei.com> Cc: Arnaldo Carvalho de Melo <acme@ghostprotocols.net> Signed-off-by: Namhyung Kim <namhyung@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/trace/trace_kprobe.c77
-rw-r--r--kernel/trace/trace_probe.c77
-rw-r--r--kernel/trace/trace_probe.h4
-rw-r--r--kernel/trace/trace_uprobe.c52
4 files changed, 129 insertions, 81 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index d2a4fd2fd8c1..f94a56915e69 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -148,6 +148,83 @@ DEFINE_BASIC_FETCH_FUNCS(stack)
148#define fetch_stack_string NULL 148#define fetch_stack_string NULL
149#define fetch_stack_string_size NULL 149#define fetch_stack_string_size NULL
150 150
151#define DEFINE_FETCH_memory(type) \
152static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
153 void *addr, void *dest) \
154{ \
155 type retval; \
156 if (probe_kernel_address(addr, retval)) \
157 *(type *)dest = 0; \
158 else \
159 *(type *)dest = retval; \
160}
161DEFINE_BASIC_FETCH_FUNCS(memory)
162/*
163 * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
164 * length and relative data location.
165 */
166static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
167 void *addr, void *dest)
168{
169 long ret;
170 int maxlen = get_rloc_len(*(u32 *)dest);
171 u8 *dst = get_rloc_data(dest);
172 u8 *src = addr;
173 mm_segment_t old_fs = get_fs();
174
175 if (!maxlen)
176 return;
177
178 /*
179 * Try to get string again, since the string can be changed while
180 * probing.
181 */
182 set_fs(KERNEL_DS);
183 pagefault_disable();
184
185 do
186 ret = __copy_from_user_inatomic(dst++, src++, 1);
187 while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
188
189 dst[-1] = '\0';
190 pagefault_enable();
191 set_fs(old_fs);
192
193 if (ret < 0) { /* Failed to fetch string */
194 ((u8 *)get_rloc_data(dest))[0] = '\0';
195 *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
196 } else {
197 *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
198 get_rloc_offs(*(u32 *)dest));
199 }
200}
201
202/* Return the length of string -- including null terminal byte */
203static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
204 void *addr, void *dest)
205{
206 mm_segment_t old_fs;
207 int ret, len = 0;
208 u8 c;
209
210 old_fs = get_fs();
211 set_fs(KERNEL_DS);
212 pagefault_disable();
213
214 do {
215 ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
216 len++;
217 } while (c && ret == 0 && len < MAX_STRING_SIZE);
218
219 pagefault_enable();
220 set_fs(old_fs);
221
222 if (ret < 0) /* Failed to check the length */
223 *(u32 *)dest = 0;
224 else
225 *(u32 *)dest = len;
226}
227
151#define DEFINE_FETCH_symbol(type) \ 228#define DEFINE_FETCH_symbol(type) \
152__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \ 229__kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs, \
153 void *data, void *dest) \ 230 void *data, void *dest) \
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index 8d7231d436da..8f7a2b6d389d 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -103,83 +103,6 @@ DEFINE_BASIC_FETCH_FUNCS(retval)
103#define fetch_retval_string NULL 103#define fetch_retval_string NULL
104#define fetch_retval_string_size NULL 104#define fetch_retval_string_size NULL
105 105
106#define DEFINE_FETCH_memory(type) \
107__kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs, \
108 void *addr, void *dest) \
109{ \
110 type retval; \
111 if (probe_kernel_address(addr, retval)) \
112 *(type *)dest = 0; \
113 else \
114 *(type *)dest = retval; \
115}
116DEFINE_BASIC_FETCH_FUNCS(memory)
117/*
118 * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
119 * length and relative data location.
120 */
121__kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
122 void *addr, void *dest)
123{
124 long ret;
125 int maxlen = get_rloc_len(*(u32 *)dest);
126 u8 *dst = get_rloc_data(dest);
127 u8 *src = addr;
128 mm_segment_t old_fs = get_fs();
129
130 if (!maxlen)
131 return;
132
133 /*
134 * Try to get string again, since the string can be changed while
135 * probing.
136 */
137 set_fs(KERNEL_DS);
138 pagefault_disable();
139
140 do
141 ret = __copy_from_user_inatomic(dst++, src++, 1);
142 while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen);
143
144 dst[-1] = '\0';
145 pagefault_enable();
146 set_fs(old_fs);
147
148 if (ret < 0) { /* Failed to fetch string */
149 ((u8 *)get_rloc_data(dest))[0] = '\0';
150 *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest));
151 } else {
152 *(u32 *)dest = make_data_rloc(src - (u8 *)addr,
153 get_rloc_offs(*(u32 *)dest));
154 }
155}
156
157/* Return the length of string -- including null terminal byte */
158__kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
159 void *addr, void *dest)
160{
161 mm_segment_t old_fs;
162 int ret, len = 0;
163 u8 c;
164
165 old_fs = get_fs();
166 set_fs(KERNEL_DS);
167 pagefault_disable();
168
169 do {
170 ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1);
171 len++;
172 } while (c && ret == 0 && len < MAX_STRING_SIZE);
173
174 pagefault_enable();
175 set_fs(old_fs);
176
177 if (ret < 0) /* Failed to check the length */
178 *(u32 *)dest = 0;
179 else
180 *(u32 *)dest = len;
181}
182
183/* Dereference memory access function */ 106/* Dereference memory access function */
184struct deref_fetch_param { 107struct deref_fetch_param {
185 struct fetch_param orig; 108 struct fetch_param orig;
diff --git a/kernel/trace/trace_probe.h b/kernel/trace/trace_probe.h
index 8be84550ceb3..2d5b8f5f5310 100644
--- a/kernel/trace/trace_probe.h
+++ b/kernel/trace/trace_probe.h
@@ -171,10 +171,6 @@ DECLARE_BASIC_FETCH_FUNCS(retval);
171#define fetch_retval_string NULL 171#define fetch_retval_string NULL
172#define fetch_retval_string_size NULL 172#define fetch_retval_string_size NULL
173 173
174DECLARE_BASIC_FETCH_FUNCS(memory);
175DECLARE_FETCH_FUNC(memory, string);
176DECLARE_FETCH_FUNC(memory, string_size);
177
178DECLARE_BASIC_FETCH_FUNCS(symbol); 174DECLARE_BASIC_FETCH_FUNCS(symbol);
179DECLARE_FETCH_FUNC(symbol, string); 175DECLARE_FETCH_FUNC(symbol, string);
180DECLARE_FETCH_FUNC(symbol, string_size); 176DECLARE_FETCH_FUNC(symbol, string_size);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 24ef6a33d93f..bebd2f5d9ea3 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -114,6 +114,58 @@ DEFINE_BASIC_FETCH_FUNCS(stack)
114#define fetch_stack_string NULL 114#define fetch_stack_string NULL
115#define fetch_stack_string_size NULL 115#define fetch_stack_string_size NULL
116 116
117#define DEFINE_FETCH_memory(type) \
118static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\
119 void *addr, void *dest) \
120{ \
121 type retval; \
122 void __user *vaddr = (void __force __user *) addr; \
123 \
124 if (copy_from_user(&retval, vaddr, sizeof(type))) \
125 *(type *)dest = 0; \
126 else \
127 *(type *) dest = retval; \
128}
129DEFINE_BASIC_FETCH_FUNCS(memory)
130/*
131 * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max
132 * length and relative data location.
133 */
134static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs,
135 void *addr, void *dest)
136{
137 long ret;
138 u32 rloc = *(u32 *)dest;
139 int maxlen = get_rloc_len(rloc);
140 u8 *dst = get_rloc_data(dest);
141 void __user *src = (void __force __user *) addr;
142
143 if (!maxlen)
144 return;
145
146 ret = strncpy_from_user(dst, src, maxlen);
147
148 if (ret < 0) { /* Failed to fetch string */
149 ((u8 *)get_rloc_data(dest))[0] = '\0';
150 *(u32 *)dest = make_data_rloc(0, get_rloc_offs(rloc));
151 } else {
152 *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(rloc));
153 }
154}
155
156static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs,
157 void *addr, void *dest)
158{
159 int len;
160 void __user *vaddr = (void __force __user *) addr;
161
162 len = strnlen_user(vaddr, MAX_STRING_SIZE);
163
164 if (len == 0 || len > MAX_STRING_SIZE) /* Failed to check length */
165 *(u32 *)dest = 0;
166 else
167 *(u32 *)dest = len;
168}
117 169
118/* uprobes do not support symbol fetch methods */ 170/* uprobes do not support symbol fetch methods */
119#define fetch_symbol_u8 NULL 171#define fetch_symbol_u8 NULL