diff options
Diffstat (limited to 'kernel/trace/trace_probe.c')
-rw-r--r-- | kernel/trace/trace_probe.c | 440 |
1 files changed, 161 insertions, 279 deletions
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c index 412e959709b4..8364a421b4df 100644 --- a/kernel/trace/trace_probe.c +++ b/kernel/trace/trace_probe.c | |||
@@ -35,46 +35,27 @@ const char *reserved_field_names[] = { | |||
35 | FIELD_STRING_FUNC, | 35 | FIELD_STRING_FUNC, |
36 | }; | 36 | }; |
37 | 37 | ||
38 | /* Printing function type */ | ||
39 | #define PRINT_TYPE_FUNC_NAME(type) print_type_##type | ||
40 | #define PRINT_TYPE_FMT_NAME(type) print_type_format_##type | ||
41 | |||
42 | /* Printing in basic type function template */ | 38 | /* Printing in basic type function template */ |
43 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt, cast) \ | 39 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(type, fmt) \ |
44 | static __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ | 40 | __kprobes int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, \ |
45 | const char *name, \ | 41 | const char *name, \ |
46 | void *data, void *ent)\ | 42 | void *data, void *ent) \ |
47 | { \ | 43 | { \ |
48 | return trace_seq_printf(s, " %s=" fmt, name, (cast)*(type *)data);\ | 44 | return trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ |
49 | } \ | 45 | } \ |
50 | static const char PRINT_TYPE_FMT_NAME(type)[] = fmt; | 46 | const char PRINT_TYPE_FMT_NAME(type)[] = fmt; |
51 | |||
52 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, "%x", unsigned int) | ||
53 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "%x", unsigned int) | ||
54 | DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "%lx", unsigned long) | ||
55 | DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "%llx", unsigned long long) | ||
56 | DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d", int) | ||
57 | DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d", int) | ||
58 | DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%ld", long) | ||
59 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%lld", long long) | ||
60 | |||
61 | static inline void *get_rloc_data(u32 *dl) | ||
62 | { | ||
63 | return (u8 *)dl + get_rloc_offs(*dl); | ||
64 | } | ||
65 | 47 | ||
66 | /* For data_loc conversion */ | 48 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8 , "0x%x") |
67 | static inline void *get_loc_data(u32 *dl, void *ent) | 49 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, "0x%x") |
68 | { | 50 | DEFINE_BASIC_PRINT_TYPE_FUNC(u32, "0x%x") |
69 | return (u8 *)ent + get_rloc_offs(*dl); | 51 | DEFINE_BASIC_PRINT_TYPE_FUNC(u64, "0x%Lx") |
70 | } | 52 | DEFINE_BASIC_PRINT_TYPE_FUNC(s8, "%d") |
71 | 53 | DEFINE_BASIC_PRINT_TYPE_FUNC(s16, "%d") | |
72 | /* For defining macros, define string/string_size types */ | 54 | DEFINE_BASIC_PRINT_TYPE_FUNC(s32, "%d") |
73 | typedef u32 string; | 55 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, "%Ld") |
74 | typedef u32 string_size; | ||
75 | 56 | ||
76 | /* Print type function for string type */ | 57 | /* Print type function for string type */ |
77 | static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, | 58 | __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, |
78 | const char *name, | 59 | const char *name, |
79 | void *data, void *ent) | 60 | void *data, void *ent) |
80 | { | 61 | { |
@@ -87,18 +68,7 @@ static __kprobes int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, | |||
87 | (const char *)get_loc_data(data, ent)); | 68 | (const char *)get_loc_data(data, ent)); |
88 | } | 69 | } |
89 | 70 | ||
90 | static const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; | 71 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
91 | |||
92 | #define FETCH_FUNC_NAME(method, type) fetch_##method##_##type | ||
93 | /* | ||
94 | * Define macro for basic types - we don't need to define s* types, because | ||
95 | * we have to care only about bitwidth at recording time. | ||
96 | */ | ||
97 | #define DEFINE_BASIC_FETCH_FUNCS(method) \ | ||
98 | DEFINE_FETCH_##method(u8) \ | ||
99 | DEFINE_FETCH_##method(u16) \ | ||
100 | DEFINE_FETCH_##method(u32) \ | ||
101 | DEFINE_FETCH_##method(u64) | ||
102 | 72 | ||
103 | #define CHECK_FETCH_FUNCS(method, fn) \ | 73 | #define CHECK_FETCH_FUNCS(method, fn) \ |
104 | (((FETCH_FUNC_NAME(method, u8) == fn) || \ | 74 | (((FETCH_FUNC_NAME(method, u8) == fn) || \ |
@@ -111,7 +81,7 @@ DEFINE_FETCH_##method(u64) | |||
111 | 81 | ||
112 | /* Data fetch function templates */ | 82 | /* Data fetch function templates */ |
113 | #define DEFINE_FETCH_reg(type) \ | 83 | #define DEFINE_FETCH_reg(type) \ |
114 | static __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ | 84 | __kprobes void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, \ |
115 | void *offset, void *dest) \ | 85 | void *offset, void *dest) \ |
116 | { \ | 86 | { \ |
117 | *(type *)dest = (type)regs_get_register(regs, \ | 87 | *(type *)dest = (type)regs_get_register(regs, \ |
@@ -122,20 +92,8 @@ DEFINE_BASIC_FETCH_FUNCS(reg) | |||
122 | #define fetch_reg_string NULL | 92 | #define fetch_reg_string NULL |
123 | #define fetch_reg_string_size NULL | 93 | #define fetch_reg_string_size NULL |
124 | 94 | ||
125 | #define DEFINE_FETCH_stack(type) \ | ||
126 | static __kprobes void FETCH_FUNC_NAME(stack, type)(struct pt_regs *regs,\ | ||
127 | void *offset, void *dest) \ | ||
128 | { \ | ||
129 | *(type *)dest = (type)regs_get_kernel_stack_nth(regs, \ | ||
130 | (unsigned int)((unsigned long)offset)); \ | ||
131 | } | ||
132 | DEFINE_BASIC_FETCH_FUNCS(stack) | ||
133 | /* No string on the stack entry */ | ||
134 | #define fetch_stack_string NULL | ||
135 | #define fetch_stack_string_size NULL | ||
136 | |||
137 | #define DEFINE_FETCH_retval(type) \ | 95 | #define DEFINE_FETCH_retval(type) \ |
138 | static __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs,\ | 96 | __kprobes void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ |
139 | void *dummy, void *dest) \ | 97 | void *dummy, void *dest) \ |
140 | { \ | 98 | { \ |
141 | *(type *)dest = (type)regs_return_value(regs); \ | 99 | *(type *)dest = (type)regs_return_value(regs); \ |
@@ -145,150 +103,16 @@ DEFINE_BASIC_FETCH_FUNCS(retval) | |||
145 | #define fetch_retval_string NULL | 103 | #define fetch_retval_string NULL |
146 | #define fetch_retval_string_size NULL | 104 | #define fetch_retval_string_size NULL |
147 | 105 | ||
148 | #define DEFINE_FETCH_memory(type) \ | ||
149 | static __kprobes void FETCH_FUNC_NAME(memory, type)(struct pt_regs *regs,\ | ||
150 | void *addr, void *dest) \ | ||
151 | { \ | ||
152 | type retval; \ | ||
153 | if (probe_kernel_address(addr, retval)) \ | ||
154 | *(type *)dest = 0; \ | ||
155 | else \ | ||
156 | *(type *)dest = retval; \ | ||
157 | } | ||
158 | DEFINE_BASIC_FETCH_FUNCS(memory) | ||
159 | /* | ||
160 | * Fetch a null-terminated string. Caller MUST set *(u32 *)dest with max | ||
161 | * length and relative data location. | ||
162 | */ | ||
163 | static __kprobes void FETCH_FUNC_NAME(memory, string)(struct pt_regs *regs, | ||
164 | void *addr, void *dest) | ||
165 | { | ||
166 | long ret; | ||
167 | int maxlen = get_rloc_len(*(u32 *)dest); | ||
168 | u8 *dst = get_rloc_data(dest); | ||
169 | u8 *src = addr; | ||
170 | mm_segment_t old_fs = get_fs(); | ||
171 | |||
172 | if (!maxlen) | ||
173 | return; | ||
174 | |||
175 | /* | ||
176 | * Try to get string again, since the string can be changed while | ||
177 | * probing. | ||
178 | */ | ||
179 | set_fs(KERNEL_DS); | ||
180 | pagefault_disable(); | ||
181 | |||
182 | do | ||
183 | ret = __copy_from_user_inatomic(dst++, src++, 1); | ||
184 | while (dst[-1] && ret == 0 && src - (u8 *)addr < maxlen); | ||
185 | |||
186 | dst[-1] = '\0'; | ||
187 | pagefault_enable(); | ||
188 | set_fs(old_fs); | ||
189 | |||
190 | if (ret < 0) { /* Failed to fetch string */ | ||
191 | ((u8 *)get_rloc_data(dest))[0] = '\0'; | ||
192 | *(u32 *)dest = make_data_rloc(0, get_rloc_offs(*(u32 *)dest)); | ||
193 | } else { | ||
194 | *(u32 *)dest = make_data_rloc(src - (u8 *)addr, | ||
195 | get_rloc_offs(*(u32 *)dest)); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | /* Return the length of string -- including null terminal byte */ | ||
200 | static __kprobes void FETCH_FUNC_NAME(memory, string_size)(struct pt_regs *regs, | ||
201 | void *addr, void *dest) | ||
202 | { | ||
203 | mm_segment_t old_fs; | ||
204 | int ret, len = 0; | ||
205 | u8 c; | ||
206 | |||
207 | old_fs = get_fs(); | ||
208 | set_fs(KERNEL_DS); | ||
209 | pagefault_disable(); | ||
210 | |||
211 | do { | ||
212 | ret = __copy_from_user_inatomic(&c, (u8 *)addr + len, 1); | ||
213 | len++; | ||
214 | } while (c && ret == 0 && len < MAX_STRING_SIZE); | ||
215 | |||
216 | pagefault_enable(); | ||
217 | set_fs(old_fs); | ||
218 | |||
219 | if (ret < 0) /* Failed to check the length */ | ||
220 | *(u32 *)dest = 0; | ||
221 | else | ||
222 | *(u32 *)dest = len; | ||
223 | } | ||
224 | |||
225 | /* Memory fetching by symbol */ | ||
226 | struct symbol_cache { | ||
227 | char *symbol; | ||
228 | long offset; | ||
229 | unsigned long addr; | ||
230 | }; | ||
231 | |||
232 | static unsigned long update_symbol_cache(struct symbol_cache *sc) | ||
233 | { | ||
234 | sc->addr = (unsigned long)kallsyms_lookup_name(sc->symbol); | ||
235 | |||
236 | if (sc->addr) | ||
237 | sc->addr += sc->offset; | ||
238 | |||
239 | return sc->addr; | ||
240 | } | ||
241 | |||
242 | static void free_symbol_cache(struct symbol_cache *sc) | ||
243 | { | ||
244 | kfree(sc->symbol); | ||
245 | kfree(sc); | ||
246 | } | ||
247 | |||
248 | static struct symbol_cache *alloc_symbol_cache(const char *sym, long offset) | ||
249 | { | ||
250 | struct symbol_cache *sc; | ||
251 | |||
252 | if (!sym || strlen(sym) == 0) | ||
253 | return NULL; | ||
254 | |||
255 | sc = kzalloc(sizeof(struct symbol_cache), GFP_KERNEL); | ||
256 | if (!sc) | ||
257 | return NULL; | ||
258 | |||
259 | sc->symbol = kstrdup(sym, GFP_KERNEL); | ||
260 | if (!sc->symbol) { | ||
261 | kfree(sc); | ||
262 | return NULL; | ||
263 | } | ||
264 | sc->offset = offset; | ||
265 | update_symbol_cache(sc); | ||
266 | |||
267 | return sc; | ||
268 | } | ||
269 | |||
270 | #define DEFINE_FETCH_symbol(type) \ | ||
271 | static __kprobes void FETCH_FUNC_NAME(symbol, type)(struct pt_regs *regs,\ | ||
272 | void *data, void *dest) \ | ||
273 | { \ | ||
274 | struct symbol_cache *sc = data; \ | ||
275 | if (sc->addr) \ | ||
276 | fetch_memory_##type(regs, (void *)sc->addr, dest); \ | ||
277 | else \ | ||
278 | *(type *)dest = 0; \ | ||
279 | } | ||
280 | DEFINE_BASIC_FETCH_FUNCS(symbol) | ||
281 | DEFINE_FETCH_symbol(string) | ||
282 | DEFINE_FETCH_symbol(string_size) | ||
283 | |||
284 | /* Dereference memory access function */ | 106 | /* Dereference memory access function */ |
285 | struct deref_fetch_param { | 107 | struct deref_fetch_param { |
286 | struct fetch_param orig; | 108 | struct fetch_param orig; |
287 | long offset; | 109 | long offset; |
110 | fetch_func_t fetch; | ||
111 | fetch_func_t fetch_size; | ||
288 | }; | 112 | }; |
289 | 113 | ||
290 | #define DEFINE_FETCH_deref(type) \ | 114 | #define DEFINE_FETCH_deref(type) \ |
291 | static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\ | 115 | __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ |
292 | void *data, void *dest) \ | 116 | void *data, void *dest) \ |
293 | { \ | 117 | { \ |
294 | struct deref_fetch_param *dprm = data; \ | 118 | struct deref_fetch_param *dprm = data; \ |
@@ -296,13 +120,26 @@ static __kprobes void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs,\ | |||
296 | call_fetch(&dprm->orig, regs, &addr); \ | 120 | call_fetch(&dprm->orig, regs, &addr); \ |
297 | if (addr) { \ | 121 | if (addr) { \ |
298 | addr += dprm->offset; \ | 122 | addr += dprm->offset; \ |
299 | fetch_memory_##type(regs, (void *)addr, dest); \ | 123 | dprm->fetch(regs, (void *)addr, dest); \ |
300 | } else \ | 124 | } else \ |
301 | *(type *)dest = 0; \ | 125 | *(type *)dest = 0; \ |
302 | } | 126 | } |
303 | DEFINE_BASIC_FETCH_FUNCS(deref) | 127 | DEFINE_BASIC_FETCH_FUNCS(deref) |
304 | DEFINE_FETCH_deref(string) | 128 | DEFINE_FETCH_deref(string) |
305 | DEFINE_FETCH_deref(string_size) | 129 | |
130 | __kprobes void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, | ||
131 | void *data, void *dest) | ||
132 | { | ||
133 | struct deref_fetch_param *dprm = data; | ||
134 | unsigned long addr; | ||
135 | |||
136 | call_fetch(&dprm->orig, regs, &addr); | ||
137 | if (addr && dprm->fetch_size) { | ||
138 | addr += dprm->offset; | ||
139 | dprm->fetch_size(regs, (void *)addr, dest); | ||
140 | } else | ||
141 | *(string_size *)dest = 0; | ||
142 | } | ||
306 | 143 | ||
307 | static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) | 144 | static __kprobes void update_deref_fetch_param(struct deref_fetch_param *data) |
308 | { | 145 | { |
@@ -329,7 +166,7 @@ struct bitfield_fetch_param { | |||
329 | }; | 166 | }; |
330 | 167 | ||
331 | #define DEFINE_FETCH_bitfield(type) \ | 168 | #define DEFINE_FETCH_bitfield(type) \ |
332 | static __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs,\ | 169 | __kprobes void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ |
333 | void *data, void *dest) \ | 170 | void *data, void *dest) \ |
334 | { \ | 171 | { \ |
335 | struct bitfield_fetch_param *bprm = data; \ | 172 | struct bitfield_fetch_param *bprm = data; \ |
@@ -374,58 +211,8 @@ free_bitfield_fetch_param(struct bitfield_fetch_param *data) | |||
374 | kfree(data); | 211 | kfree(data); |
375 | } | 212 | } |
376 | 213 | ||
377 | /* Default (unsigned long) fetch type */ | 214 | static const struct fetch_type *find_fetch_type(const char *type, |
378 | #define __DEFAULT_FETCH_TYPE(t) u##t | 215 | const struct fetch_type *ftbl) |
379 | #define _DEFAULT_FETCH_TYPE(t) __DEFAULT_FETCH_TYPE(t) | ||
380 | #define DEFAULT_FETCH_TYPE _DEFAULT_FETCH_TYPE(BITS_PER_LONG) | ||
381 | #define DEFAULT_FETCH_TYPE_STR __stringify(DEFAULT_FETCH_TYPE) | ||
382 | |||
383 | #define ASSIGN_FETCH_FUNC(method, type) \ | ||
384 | [FETCH_MTD_##method] = FETCH_FUNC_NAME(method, type) | ||
385 | |||
386 | #define __ASSIGN_FETCH_TYPE(_name, ptype, ftype, _size, sign, _fmttype) \ | ||
387 | {.name = _name, \ | ||
388 | .size = _size, \ | ||
389 | .is_signed = sign, \ | ||
390 | .print = PRINT_TYPE_FUNC_NAME(ptype), \ | ||
391 | .fmt = PRINT_TYPE_FMT_NAME(ptype), \ | ||
392 | .fmttype = _fmttype, \ | ||
393 | .fetch = { \ | ||
394 | ASSIGN_FETCH_FUNC(reg, ftype), \ | ||
395 | ASSIGN_FETCH_FUNC(stack, ftype), \ | ||
396 | ASSIGN_FETCH_FUNC(retval, ftype), \ | ||
397 | ASSIGN_FETCH_FUNC(memory, ftype), \ | ||
398 | ASSIGN_FETCH_FUNC(symbol, ftype), \ | ||
399 | ASSIGN_FETCH_FUNC(deref, ftype), \ | ||
400 | ASSIGN_FETCH_FUNC(bitfield, ftype), \ | ||
401 | } \ | ||
402 | } | ||
403 | |||
404 | #define ASSIGN_FETCH_TYPE(ptype, ftype, sign) \ | ||
405 | __ASSIGN_FETCH_TYPE(#ptype, ptype, ftype, sizeof(ftype), sign, #ptype) | ||
406 | |||
407 | #define FETCH_TYPE_STRING 0 | ||
408 | #define FETCH_TYPE_STRSIZE 1 | ||
409 | |||
410 | /* Fetch type information table */ | ||
411 | static const struct fetch_type fetch_type_table[] = { | ||
412 | /* Special types */ | ||
413 | [FETCH_TYPE_STRING] = __ASSIGN_FETCH_TYPE("string", string, string, | ||
414 | sizeof(u32), 1, "__data_loc char[]"), | ||
415 | [FETCH_TYPE_STRSIZE] = __ASSIGN_FETCH_TYPE("string_size", u32, | ||
416 | string_size, sizeof(u32), 0, "u32"), | ||
417 | /* Basic types */ | ||
418 | ASSIGN_FETCH_TYPE(u8, u8, 0), | ||
419 | ASSIGN_FETCH_TYPE(u16, u16, 0), | ||
420 | ASSIGN_FETCH_TYPE(u32, u32, 0), | ||
421 | ASSIGN_FETCH_TYPE(u64, u64, 0), | ||
422 | ASSIGN_FETCH_TYPE(s8, u8, 1), | ||
423 | ASSIGN_FETCH_TYPE(s16, u16, 1), | ||
424 | ASSIGN_FETCH_TYPE(s32, u32, 1), | ||
425 | ASSIGN_FETCH_TYPE(s64, u64, 1), | ||
426 | }; | ||
427 | |||
428 | static const struct fetch_type *find_fetch_type(const char *type) | ||
429 | { | 216 | { |
430 | int i; | 217 | int i; |
431 | 218 | ||
@@ -446,44 +233,52 @@ static const struct fetch_type *find_fetch_type(const char *type) | |||
446 | 233 | ||
447 | switch (bs) { | 234 | switch (bs) { |
448 | case 8: | 235 | case 8: |
449 | return find_fetch_type("u8"); | 236 | return find_fetch_type("u8", ftbl); |
450 | case 16: | 237 | case 16: |
451 | return find_fetch_type("u16"); | 238 | return find_fetch_type("u16", ftbl); |
452 | case 32: | 239 | case 32: |
453 | return find_fetch_type("u32"); | 240 | return find_fetch_type("u32", ftbl); |
454 | case 64: | 241 | case 64: |
455 | return find_fetch_type("u64"); | 242 | return find_fetch_type("u64", ftbl); |
456 | default: | 243 | default: |
457 | goto fail; | 244 | goto fail; |
458 | } | 245 | } |
459 | } | 246 | } |
460 | 247 | ||
461 | for (i = 0; i < ARRAY_SIZE(fetch_type_table); i++) | 248 | for (i = 0; ftbl[i].name; i++) { |
462 | if (strcmp(type, fetch_type_table[i].name) == 0) | 249 | if (strcmp(type, ftbl[i].name) == 0) |
463 | return &fetch_type_table[i]; | 250 | return &ftbl[i]; |
251 | } | ||
464 | 252 | ||
465 | fail: | 253 | fail: |
466 | return NULL; | 254 | return NULL; |
467 | } | 255 | } |
468 | 256 | ||
469 | /* Special function : only accept unsigned long */ | 257 | /* Special function : only accept unsigned long */ |
470 | static __kprobes void fetch_stack_address(struct pt_regs *regs, | 258 | static __kprobes void fetch_kernel_stack_address(struct pt_regs *regs, |
471 | void *dummy, void *dest) | 259 | void *dummy, void *dest) |
472 | { | 260 | { |
473 | *(unsigned long *)dest = kernel_stack_pointer(regs); | 261 | *(unsigned long *)dest = kernel_stack_pointer(regs); |
474 | } | 262 | } |
475 | 263 | ||
264 | static __kprobes void fetch_user_stack_address(struct pt_regs *regs, | ||
265 | void *dummy, void *dest) | ||
266 | { | ||
267 | *(unsigned long *)dest = user_stack_pointer(regs); | ||
268 | } | ||
269 | |||
476 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, | 270 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, |
477 | fetch_func_t orig_fn) | 271 | fetch_func_t orig_fn, |
272 | const struct fetch_type *ftbl) | ||
478 | { | 273 | { |
479 | int i; | 274 | int i; |
480 | 275 | ||
481 | if (type != &fetch_type_table[FETCH_TYPE_STRING]) | 276 | if (type != &ftbl[FETCH_TYPE_STRING]) |
482 | return NULL; /* Only string type needs size function */ | 277 | return NULL; /* Only string type needs size function */ |
483 | 278 | ||
484 | for (i = 0; i < FETCH_MTD_END; i++) | 279 | for (i = 0; i < FETCH_MTD_END; i++) |
485 | if (type->fetch[i] == orig_fn) | 280 | if (type->fetch[i] == orig_fn) |
486 | return fetch_type_table[FETCH_TYPE_STRSIZE].fetch[i]; | 281 | return ftbl[FETCH_TYPE_STRSIZE].fetch[i]; |
487 | 282 | ||
488 | WARN_ON(1); /* This should not happen */ | 283 | WARN_ON(1); /* This should not happen */ |
489 | 284 | ||
@@ -516,7 +311,8 @@ int traceprobe_split_symbol_offset(char *symbol, unsigned long *offset) | |||
516 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | 311 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
517 | 312 | ||
518 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | 313 | static int parse_probe_vars(char *arg, const struct fetch_type *t, |
519 | struct fetch_param *f, bool is_return) | 314 | struct fetch_param *f, bool is_return, |
315 | bool is_kprobe) | ||
520 | { | 316 | { |
521 | int ret = 0; | 317 | int ret = 0; |
522 | unsigned long param; | 318 | unsigned long param; |
@@ -528,13 +324,16 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, | |||
528 | ret = -EINVAL; | 324 | ret = -EINVAL; |
529 | } else if (strncmp(arg, "stack", 5) == 0) { | 325 | } else if (strncmp(arg, "stack", 5) == 0) { |
530 | if (arg[5] == '\0') { | 326 | if (arg[5] == '\0') { |
531 | if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR) == 0) | 327 | if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR)) |
532 | f->fn = fetch_stack_address; | 328 | return -EINVAL; |
329 | |||
330 | if (is_kprobe) | ||
331 | f->fn = fetch_kernel_stack_address; | ||
533 | else | 332 | else |
534 | ret = -EINVAL; | 333 | f->fn = fetch_user_stack_address; |
535 | } else if (isdigit(arg[5])) { | 334 | } else if (isdigit(arg[5])) { |
536 | ret = kstrtoul(arg + 5, 10, ¶m); | 335 | ret = kstrtoul(arg + 5, 10, ¶m); |
537 | if (ret || param > PARAM_MAX_STACK) | 336 | if (ret || (is_kprobe && param > PARAM_MAX_STACK)) |
538 | ret = -EINVAL; | 337 | ret = -EINVAL; |
539 | else { | 338 | else { |
540 | f->fn = t->fetch[FETCH_MTD_stack]; | 339 | f->fn = t->fetch[FETCH_MTD_stack]; |
@@ -552,20 +351,18 @@ static int parse_probe_vars(char *arg, const struct fetch_type *t, | |||
552 | static int parse_probe_arg(char *arg, const struct fetch_type *t, | 351 | static int parse_probe_arg(char *arg, const struct fetch_type *t, |
553 | struct fetch_param *f, bool is_return, bool is_kprobe) | 352 | struct fetch_param *f, bool is_return, bool is_kprobe) |
554 | { | 353 | { |
354 | const struct fetch_type *ftbl; | ||
555 | unsigned long param; | 355 | unsigned long param; |
556 | long offset; | 356 | long offset; |
557 | char *tmp; | 357 | char *tmp; |
558 | int ret; | 358 | int ret = 0; |
559 | |||
560 | ret = 0; | ||
561 | 359 | ||
562 | /* Until uprobe_events supports only reg arguments */ | 360 | ftbl = is_kprobe ? kprobes_fetch_type_table : uprobes_fetch_type_table; |
563 | if (!is_kprobe && arg[0] != '%') | 361 | BUG_ON(ftbl == NULL); |
564 | return -EINVAL; | ||
565 | 362 | ||
566 | switch (arg[0]) { | 363 | switch (arg[0]) { |
567 | case '$': | 364 | case '$': |
568 | ret = parse_probe_vars(arg + 1, t, f, is_return); | 365 | ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); |
569 | break; | 366 | break; |
570 | 367 | ||
571 | case '%': /* named register */ | 368 | case '%': /* named register */ |
@@ -577,7 +374,7 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
577 | } | 374 | } |
578 | break; | 375 | break; |
579 | 376 | ||
580 | case '@': /* memory or symbol */ | 377 | case '@': /* memory, file-offset or symbol */ |
581 | if (isdigit(arg[1])) { | 378 | if (isdigit(arg[1])) { |
582 | ret = kstrtoul(arg + 1, 0, ¶m); | 379 | ret = kstrtoul(arg + 1, 0, ¶m); |
583 | if (ret) | 380 | if (ret) |
@@ -585,7 +382,22 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
585 | 382 | ||
586 | f->fn = t->fetch[FETCH_MTD_memory]; | 383 | f->fn = t->fetch[FETCH_MTD_memory]; |
587 | f->data = (void *)param; | 384 | f->data = (void *)param; |
385 | } else if (arg[1] == '+') { | ||
386 | /* kprobes don't support file offsets */ | ||
387 | if (is_kprobe) | ||
388 | return -EINVAL; | ||
389 | |||
390 | ret = kstrtol(arg + 2, 0, &offset); | ||
391 | if (ret) | ||
392 | break; | ||
393 | |||
394 | f->fn = t->fetch[FETCH_MTD_file_offset]; | ||
395 | f->data = (void *)offset; | ||
588 | } else { | 396 | } else { |
397 | /* uprobes don't support symbols */ | ||
398 | if (!is_kprobe) | ||
399 | return -EINVAL; | ||
400 | |||
589 | ret = traceprobe_split_symbol_offset(arg + 1, &offset); | 401 | ret = traceprobe_split_symbol_offset(arg + 1, &offset); |
590 | if (ret) | 402 | if (ret) |
591 | break; | 403 | break; |
@@ -616,7 +428,7 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
616 | struct deref_fetch_param *dprm; | 428 | struct deref_fetch_param *dprm; |
617 | const struct fetch_type *t2; | 429 | const struct fetch_type *t2; |
618 | 430 | ||
619 | t2 = find_fetch_type(NULL); | 431 | t2 = find_fetch_type(NULL, ftbl); |
620 | *tmp = '\0'; | 432 | *tmp = '\0'; |
621 | dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); | 433 | dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); |
622 | 434 | ||
@@ -624,6 +436,9 @@ static int parse_probe_arg(char *arg, const struct fetch_type *t, | |||
624 | return -ENOMEM; | 436 | return -ENOMEM; |
625 | 437 | ||
626 | dprm->offset = offset; | 438 | dprm->offset = offset; |
439 | dprm->fetch = t->fetch[FETCH_MTD_memory]; | ||
440 | dprm->fetch_size = get_fetch_size_function(t, | ||
441 | dprm->fetch, ftbl); | ||
627 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, | 442 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, |
628 | is_kprobe); | 443 | is_kprobe); |
629 | if (ret) | 444 | if (ret) |
@@ -685,9 +500,13 @@ static int __parse_bitfield_probe_arg(const char *bf, | |||
685 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | 500 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, |
686 | struct probe_arg *parg, bool is_return, bool is_kprobe) | 501 | struct probe_arg *parg, bool is_return, bool is_kprobe) |
687 | { | 502 | { |
503 | const struct fetch_type *ftbl; | ||
688 | const char *t; | 504 | const char *t; |
689 | int ret; | 505 | int ret; |
690 | 506 | ||
507 | ftbl = is_kprobe ? kprobes_fetch_type_table : uprobes_fetch_type_table; | ||
508 | BUG_ON(ftbl == NULL); | ||
509 | |||
691 | if (strlen(arg) > MAX_ARGSTR_LEN) { | 510 | if (strlen(arg) > MAX_ARGSTR_LEN) { |
692 | pr_info("Argument is too long.: %s\n", arg); | 511 | pr_info("Argument is too long.: %s\n", arg); |
693 | return -ENOSPC; | 512 | return -ENOSPC; |
@@ -702,7 +521,7 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |||
702 | arg[t - parg->comm] = '\0'; | 521 | arg[t - parg->comm] = '\0'; |
703 | t++; | 522 | t++; |
704 | } | 523 | } |
705 | parg->type = find_fetch_type(t); | 524 | parg->type = find_fetch_type(t, ftbl); |
706 | if (!parg->type) { | 525 | if (!parg->type) { |
707 | pr_info("Unsupported type: %s\n", t); | 526 | pr_info("Unsupported type: %s\n", t); |
708 | return -EINVAL; | 527 | return -EINVAL; |
@@ -716,7 +535,8 @@ int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |||
716 | 535 | ||
717 | if (ret >= 0) { | 536 | if (ret >= 0) { |
718 | parg->fetch_size.fn = get_fetch_size_function(parg->type, | 537 | parg->fetch_size.fn = get_fetch_size_function(parg->type, |
719 | parg->fetch.fn); | 538 | parg->fetch.fn, |
539 | ftbl); | ||
720 | parg->fetch_size.data = parg->fetch.data; | 540 | parg->fetch_size.data = parg->fetch.data; |
721 | } | 541 | } |
722 | 542 | ||
@@ -837,3 +657,65 @@ out: | |||
837 | 657 | ||
838 | return ret; | 658 | return ret; |
839 | } | 659 | } |
660 | |||
661 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, | ||
662 | bool is_return) | ||
663 | { | ||
664 | int i; | ||
665 | int pos = 0; | ||
666 | |||
667 | const char *fmt, *arg; | ||
668 | |||
669 | if (!is_return) { | ||
670 | fmt = "(%lx)"; | ||
671 | arg = "REC->" FIELD_STRING_IP; | ||
672 | } else { | ||
673 | fmt = "(%lx <- %lx)"; | ||
674 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | ||
675 | } | ||
676 | |||
677 | /* When len=0, we just calculate the needed length */ | ||
678 | #define LEN_OR_ZERO (len ? len - pos : 0) | ||
679 | |||
680 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | ||
681 | |||
682 | for (i = 0; i < tp->nr_args; i++) { | ||
683 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", | ||
684 | tp->args[i].name, tp->args[i].type->fmt); | ||
685 | } | ||
686 | |||
687 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | ||
688 | |||
689 | for (i = 0; i < tp->nr_args; i++) { | ||
690 | if (strcmp(tp->args[i].type->name, "string") == 0) | ||
691 | pos += snprintf(buf + pos, LEN_OR_ZERO, | ||
692 | ", __get_str(%s)", | ||
693 | tp->args[i].name); | ||
694 | else | ||
695 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", | ||
696 | tp->args[i].name); | ||
697 | } | ||
698 | |||
699 | #undef LEN_OR_ZERO | ||
700 | |||
701 | /* return the length of print_fmt */ | ||
702 | return pos; | ||
703 | } | ||
704 | |||
705 | int set_print_fmt(struct trace_probe *tp, bool is_return) | ||
706 | { | ||
707 | int len; | ||
708 | char *print_fmt; | ||
709 | |||
710 | /* First: called with 0 length to calculate the needed length */ | ||
711 | len = __set_print_fmt(tp, NULL, 0, is_return); | ||
712 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | ||
713 | if (!print_fmt) | ||
714 | return -ENOMEM; | ||
715 | |||
716 | /* Second: actually write the @print_fmt */ | ||
717 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | ||
718 | tp->call.print_fmt = print_fmt; | ||
719 | |||
720 | return 0; | ||
721 | } | ||