Commit | Line | Data |
---|---|---|
bcea3f96 | 1 | // SPDX-License-Identifier: GPL-2.0 |
8ab83f56 SD |
2 | /* |
3 | * Common code for probe-based Dynamic events. | |
4 | * | |
8ab83f56 SD |
5 | * This code was copied from kernel/trace/trace_kprobe.c written by |
6 | * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | |
7 | * | |
8 | * Updates to make this generic: | |
9 | * Copyright (C) IBM Corporation, 2010-2011 | |
10 | * Author: Srikar Dronamraju | |
11 | */ | |
72576341 | 12 | #define pr_fmt(fmt) "trace_probe: " fmt |
8ab83f56 SD |
13 | |
14 | #include "trace_probe.h" | |
15 | ||
16 | const char *reserved_field_names[] = { | |
17 | "common_type", | |
18 | "common_flags", | |
19 | "common_preempt_count", | |
20 | "common_pid", | |
21 | "common_tgid", | |
22 | FIELD_STRING_IP, | |
23 | FIELD_STRING_RETIP, | |
24 | FIELD_STRING_FUNC, | |
25 | }; | |
26 | ||
8ab83f56 | 27 | /* Printing in basic type function template */ |
17ce3dc7 MH |
28 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \ |
29 | int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, const char *name, \ | |
3da0f180 | 30 | void *data, void *ent) \ |
8ab83f56 | 31 | { \ |
d2b0191a SRRH |
32 | trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \ |
33 | return !trace_seq_has_overflowed(s); \ | |
8ab83f56 | 34 | } \ |
17ce3dc7 MH |
35 | const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; \ |
36 | NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(tname)); | |
8ab83f56 | 37 | |
bdca79c2 MH |
38 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u") |
39 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") | |
40 | DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u") | |
41 | DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu") | |
17ce3dc7 MH |
42 | DEFINE_BASIC_PRINT_TYPE_FUNC(s8, s8, "%d") |
43 | DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d") | |
44 | DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d") | |
45 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld") | |
46 | DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x") | |
47 | DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x") | |
48 | DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") | |
49 | DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") | |
8ab83f56 | 50 | |
8ab83f56 | 51 | /* Print type function for string type */ |
3da0f180 MH |
52 | int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name, |
53 | void *data, void *ent) | |
8ab83f56 SD |
54 | { |
55 | int len = *(u32 *)data >> 16; | |
56 | ||
57 | if (!len) | |
d2b0191a | 58 | trace_seq_printf(s, " %s=(fault)", name); |
8ab83f56 | 59 | else |
d2b0191a SRRH |
60 | trace_seq_printf(s, " %s=\"%s\"", name, |
61 | (const char *)get_loc_data(data, ent)); | |
62 | return !trace_seq_has_overflowed(s); | |
8ab83f56 | 63 | } |
3da0f180 | 64 | NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string)); |
8ab83f56 | 65 | |
b26c74e1 | 66 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
8ab83f56 | 67 | |
8ab83f56 SD |
68 | #define CHECK_FETCH_FUNCS(method, fn) \ |
69 | (((FETCH_FUNC_NAME(method, u8) == fn) || \ | |
70 | (FETCH_FUNC_NAME(method, u16) == fn) || \ | |
71 | (FETCH_FUNC_NAME(method, u32) == fn) || \ | |
72 | (FETCH_FUNC_NAME(method, u64) == fn) || \ | |
73 | (FETCH_FUNC_NAME(method, string) == fn) || \ | |
74 | (FETCH_FUNC_NAME(method, string_size) == fn)) \ | |
75 | && (fn != NULL)) | |
76 | ||
77 | /* Data fetch function templates */ | |
78 | #define DEFINE_FETCH_reg(type) \ | |
3da0f180 | 79 | void FETCH_FUNC_NAME(reg, type)(struct pt_regs *regs, void *offset, void *dest) \ |
8ab83f56 SD |
80 | { \ |
81 | *(type *)dest = (type)regs_get_register(regs, \ | |
82 | (unsigned int)((unsigned long)offset)); \ | |
3da0f180 MH |
83 | } \ |
84 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(reg, type)); | |
8ab83f56 SD |
85 | DEFINE_BASIC_FETCH_FUNCS(reg) |
86 | /* No string on the register */ | |
87 | #define fetch_reg_string NULL | |
88 | #define fetch_reg_string_size NULL | |
89 | ||
8ab83f56 | 90 | #define DEFINE_FETCH_retval(type) \ |
3da0f180 MH |
91 | void FETCH_FUNC_NAME(retval, type)(struct pt_regs *regs, \ |
92 | void *dummy, void *dest) \ | |
8ab83f56 SD |
93 | { \ |
94 | *(type *)dest = (type)regs_return_value(regs); \ | |
3da0f180 MH |
95 | } \ |
96 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(retval, type)); | |
8ab83f56 SD |
97 | DEFINE_BASIC_FETCH_FUNCS(retval) |
98 | /* No string on the retval */ | |
99 | #define fetch_retval_string NULL | |
100 | #define fetch_retval_string_size NULL | |
101 | ||
8ab83f56 SD |
102 | /* Dereference memory access function */ |
103 | struct deref_fetch_param { | |
104 | struct fetch_param orig; | |
105 | long offset; | |
3925f4a5 HL |
106 | fetch_func_t fetch; |
107 | fetch_func_t fetch_size; | |
8ab83f56 SD |
108 | }; |
109 | ||
110 | #define DEFINE_FETCH_deref(type) \ | |
3da0f180 MH |
111 | void FETCH_FUNC_NAME(deref, type)(struct pt_regs *regs, \ |
112 | void *data, void *dest) \ | |
8ab83f56 SD |
113 | { \ |
114 | struct deref_fetch_param *dprm = data; \ | |
115 | unsigned long addr; \ | |
116 | call_fetch(&dprm->orig, regs, &addr); \ | |
117 | if (addr) { \ | |
118 | addr += dprm->offset; \ | |
3925f4a5 | 119 | dprm->fetch(regs, (void *)addr, dest); \ |
8ab83f56 SD |
120 | } else \ |
121 | *(type *)dest = 0; \ | |
3da0f180 MH |
122 | } \ |
123 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, type)); | |
8ab83f56 SD |
124 | DEFINE_BASIC_FETCH_FUNCS(deref) |
125 | DEFINE_FETCH_deref(string) | |
3925f4a5 | 126 | |
3da0f180 MH |
127 | void FETCH_FUNC_NAME(deref, string_size)(struct pt_regs *regs, |
128 | void *data, void *dest) | |
3925f4a5 HL |
129 | { |
130 | struct deref_fetch_param *dprm = data; | |
131 | unsigned long addr; | |
132 | ||
133 | call_fetch(&dprm->orig, regs, &addr); | |
134 | if (addr && dprm->fetch_size) { | |
135 | addr += dprm->offset; | |
136 | dprm->fetch_size(regs, (void *)addr, dest); | |
137 | } else | |
138 | *(string_size *)dest = 0; | |
139 | } | |
3da0f180 | 140 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(deref, string_size)); |
8ab83f56 | 141 | |
3da0f180 | 142 | static void update_deref_fetch_param(struct deref_fetch_param *data) |
8ab83f56 SD |
143 | { |
144 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | |
145 | update_deref_fetch_param(data->orig.data); | |
146 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | |
147 | update_symbol_cache(data->orig.data); | |
148 | } | |
3da0f180 | 149 | NOKPROBE_SYMBOL(update_deref_fetch_param); |
8ab83f56 | 150 | |
3da0f180 | 151 | static void free_deref_fetch_param(struct deref_fetch_param *data) |
8ab83f56 SD |
152 | { |
153 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | |
154 | free_deref_fetch_param(data->orig.data); | |
155 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | |
156 | free_symbol_cache(data->orig.data); | |
157 | kfree(data); | |
158 | } | |
3da0f180 | 159 | NOKPROBE_SYMBOL(free_deref_fetch_param); |
8ab83f56 SD |
160 | |
161 | /* Bitfield fetch function */ | |
162 | struct bitfield_fetch_param { | |
163 | struct fetch_param orig; | |
164 | unsigned char hi_shift; | |
165 | unsigned char low_shift; | |
166 | }; | |
167 | ||
168 | #define DEFINE_FETCH_bitfield(type) \ | |
3da0f180 MH |
169 | void FETCH_FUNC_NAME(bitfield, type)(struct pt_regs *regs, \ |
170 | void *data, void *dest) \ | |
8ab83f56 SD |
171 | { \ |
172 | struct bitfield_fetch_param *bprm = data; \ | |
173 | type buf = 0; \ | |
174 | call_fetch(&bprm->orig, regs, &buf); \ | |
175 | if (buf) { \ | |
176 | buf <<= bprm->hi_shift; \ | |
177 | buf >>= bprm->low_shift; \ | |
178 | } \ | |
179 | *(type *)dest = buf; \ | |
3da0f180 MH |
180 | } \ |
181 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(bitfield, type)); | |
8ab83f56 SD |
182 | DEFINE_BASIC_FETCH_FUNCS(bitfield) |
183 | #define fetch_bitfield_string NULL | |
184 | #define fetch_bitfield_string_size NULL | |
185 | ||
fbc1963d | 186 | static void |
8ab83f56 SD |
187 | update_bitfield_fetch_param(struct bitfield_fetch_param *data) |
188 | { | |
189 | /* | |
190 | * Don't check the bitfield itself, because this must be the | |
191 | * last fetch function. | |
192 | */ | |
193 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | |
194 | update_deref_fetch_param(data->orig.data); | |
195 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | |
196 | update_symbol_cache(data->orig.data); | |
197 | } | |
198 | ||
fbc1963d | 199 | static void |
8ab83f56 SD |
200 | free_bitfield_fetch_param(struct bitfield_fetch_param *data) |
201 | { | |
202 | /* | |
203 | * Don't check the bitfield itself, because this must be the | |
204 | * last fetch function. | |
205 | */ | |
206 | if (CHECK_FETCH_FUNCS(deref, data->orig.fn)) | |
207 | free_deref_fetch_param(data->orig.data); | |
208 | else if (CHECK_FETCH_FUNCS(symbol, data->orig.fn)) | |
209 | free_symbol_cache(data->orig.data); | |
210 | ||
211 | kfree(data); | |
212 | } | |
213 | ||
35abb67d OS |
214 | void FETCH_FUNC_NAME(comm, string)(struct pt_regs *regs, |
215 | void *data, void *dest) | |
216 | { | |
217 | int maxlen = get_rloc_len(*(u32 *)dest); | |
218 | u8 *dst = get_rloc_data(dest); | |
219 | long ret; | |
220 | ||
221 | if (!maxlen) | |
222 | return; | |
223 | ||
224 | ret = strlcpy(dst, current->comm, maxlen); | |
225 | *(u32 *)dest = make_data_rloc(ret, get_rloc_offs(*(u32 *)dest)); | |
226 | } | |
227 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string)); | |
228 | ||
229 | void FETCH_FUNC_NAME(comm, string_size)(struct pt_regs *regs, | |
230 | void *data, void *dest) | |
231 | { | |
232 | *(u32 *)dest = strlen(current->comm) + 1; | |
233 | } | |
234 | NOKPROBE_SYMBOL(FETCH_FUNC_NAME(comm, string_size)); | |
235 | ||
34fee3a1 NK |
236 | static const struct fetch_type *find_fetch_type(const char *type, |
237 | const struct fetch_type *ftbl) | |
8ab83f56 SD |
238 | { |
239 | int i; | |
240 | ||
241 | if (!type) | |
242 | type = DEFAULT_FETCH_TYPE_STR; | |
243 | ||
244 | /* Special case: bitfield */ | |
245 | if (*type == 'b') { | |
246 | unsigned long bs; | |
247 | ||
248 | type = strchr(type, '/'); | |
249 | if (!type) | |
250 | goto fail; | |
251 | ||
252 | type++; | |
bcd83ea6 | 253 | if (kstrtoul(type, 0, &bs)) |
8ab83f56 SD |
254 | goto fail; |
255 | ||
256 | switch (bs) { | |
257 | case 8: | |
34fee3a1 | 258 | return find_fetch_type("u8", ftbl); |
8ab83f56 | 259 | case 16: |
34fee3a1 | 260 | return find_fetch_type("u16", ftbl); |
8ab83f56 | 261 | case 32: |
34fee3a1 | 262 | return find_fetch_type("u32", ftbl); |
8ab83f56 | 263 | case 64: |
34fee3a1 | 264 | return find_fetch_type("u64", ftbl); |
8ab83f56 SD |
265 | default: |
266 | goto fail; | |
267 | } | |
268 | } | |
269 | ||
34fee3a1 NK |
270 | for (i = 0; ftbl[i].name; i++) { |
271 | if (strcmp(type, ftbl[i].name) == 0) | |
272 | return &ftbl[i]; | |
273 | } | |
8ab83f56 SD |
274 | |
275 | fail: | |
276 | return NULL; | |
277 | } | |
278 | ||
279 | /* Special function : only accept unsigned long */ | |
3da0f180 | 280 | static void fetch_kernel_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
8ab83f56 SD |
281 | { |
282 | *(unsigned long *)dest = kernel_stack_pointer(regs); | |
283 | } | |
3da0f180 | 284 | NOKPROBE_SYMBOL(fetch_kernel_stack_address); |
8ab83f56 | 285 | |
3da0f180 | 286 | static void fetch_user_stack_address(struct pt_regs *regs, void *dummy, void *dest) |
b079d374 NK |
287 | { |
288 | *(unsigned long *)dest = user_stack_pointer(regs); | |
289 | } | |
3da0f180 | 290 | NOKPROBE_SYMBOL(fetch_user_stack_address); |
b079d374 | 291 | |
8ab83f56 | 292 | static fetch_func_t get_fetch_size_function(const struct fetch_type *type, |
34fee3a1 NK |
293 | fetch_func_t orig_fn, |
294 | const struct fetch_type *ftbl) | |
8ab83f56 SD |
295 | { |
296 | int i; | |
297 | ||
34fee3a1 | 298 | if (type != &ftbl[FETCH_TYPE_STRING]) |
8ab83f56 SD |
299 | return NULL; /* Only string type needs size function */ |
300 | ||
301 | for (i = 0; i < FETCH_MTD_END; i++) | |
302 | if (type->fetch[i] == orig_fn) | |
34fee3a1 | 303 | return ftbl[FETCH_TYPE_STRSIZE].fetch[i]; |
8ab83f56 SD |
304 | |
305 | WARN_ON(1); /* This should not happen */ | |
306 | ||
307 | return NULL; | |
308 | } | |
309 | ||
310 | /* Split symbol and offset. */ | |
c5d343b6 | 311 | int traceprobe_split_symbol_offset(char *symbol, long *offset) |
8ab83f56 SD |
312 | { |
313 | char *tmp; | |
314 | int ret; | |
315 | ||
316 | if (!offset) | |
317 | return -EINVAL; | |
318 | ||
c5d343b6 | 319 | tmp = strpbrk(symbol, "+-"); |
8ab83f56 | 320 | if (tmp) { |
c5d343b6 | 321 | ret = kstrtol(tmp, 0, offset); |
8ab83f56 SD |
322 | if (ret) |
323 | return ret; | |
8ab83f56 SD |
324 | *tmp = '\0'; |
325 | } else | |
326 | *offset = 0; | |
327 | ||
328 | return 0; | |
329 | } | |
330 | ||
331 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | |
332 | ||
333 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | |
b079d374 NK |
334 | struct fetch_param *f, bool is_return, |
335 | bool is_kprobe) | |
8ab83f56 SD |
336 | { |
337 | int ret = 0; | |
338 | unsigned long param; | |
339 | ||
340 | if (strcmp(arg, "retval") == 0) { | |
341 | if (is_return) | |
342 | f->fn = t->fetch[FETCH_MTD_retval]; | |
343 | else | |
344 | ret = -EINVAL; | |
345 | } else if (strncmp(arg, "stack", 5) == 0) { | |
346 | if (arg[5] == '\0') { | |
b079d374 NK |
347 | if (strcmp(t->name, DEFAULT_FETCH_TYPE_STR)) |
348 | return -EINVAL; | |
349 | ||
350 | if (is_kprobe) | |
351 | f->fn = fetch_kernel_stack_address; | |
8ab83f56 | 352 | else |
b079d374 | 353 | f->fn = fetch_user_stack_address; |
8ab83f56 | 354 | } else if (isdigit(arg[5])) { |
bcd83ea6 | 355 | ret = kstrtoul(arg + 5, 10, ¶m); |
b079d374 | 356 | if (ret || (is_kprobe && param > PARAM_MAX_STACK)) |
8ab83f56 SD |
357 | ret = -EINVAL; |
358 | else { | |
359 | f->fn = t->fetch[FETCH_MTD_stack]; | |
360 | f->data = (void *)param; | |
361 | } | |
362 | } else | |
363 | ret = -EINVAL; | |
35abb67d OS |
364 | } else if (strcmp(arg, "comm") == 0) { |
365 | if (strcmp(t->name, "string") != 0 && | |
366 | strcmp(t->name, "string_size") != 0) | |
367 | return -EINVAL; | |
368 | f->fn = t->fetch[FETCH_MTD_comm]; | |
8ab83f56 SD |
369 | } else |
370 | ret = -EINVAL; | |
371 | ||
372 | return ret; | |
373 | } | |
374 | ||
375 | /* Recursive argument parser */ | |
376 | static int parse_probe_arg(char *arg, const struct fetch_type *t, | |
d9a16d3a SR |
377 | struct fetch_param *f, bool is_return, bool is_kprobe, |
378 | const struct fetch_type *ftbl) | |
8ab83f56 SD |
379 | { |
380 | unsigned long param; | |
381 | long offset; | |
382 | char *tmp; | |
34fee3a1 | 383 | int ret = 0; |
8ab83f56 | 384 | |
8ab83f56 SD |
385 | switch (arg[0]) { |
386 | case '$': | |
b079d374 | 387 | ret = parse_probe_vars(arg + 1, t, f, is_return, is_kprobe); |
8ab83f56 SD |
388 | break; |
389 | ||
390 | case '%': /* named register */ | |
391 | ret = regs_query_register_offset(arg + 1); | |
392 | if (ret >= 0) { | |
393 | f->fn = t->fetch[FETCH_MTD_reg]; | |
394 | f->data = (void *)(unsigned long)ret; | |
395 | ret = 0; | |
396 | } | |
397 | break; | |
398 | ||
b7e0bf34 | 399 | case '@': /* memory, file-offset or symbol */ |
8ab83f56 | 400 | if (isdigit(arg[1])) { |
bcd83ea6 | 401 | ret = kstrtoul(arg + 1, 0, ¶m); |
8ab83f56 SD |
402 | if (ret) |
403 | break; | |
404 | ||
405 | f->fn = t->fetch[FETCH_MTD_memory]; | |
406 | f->data = (void *)param; | |
b7e0bf34 NK |
407 | } else if (arg[1] == '+') { |
408 | /* kprobes don't support file offsets */ | |
409 | if (is_kprobe) | |
410 | return -EINVAL; | |
411 | ||
412 | ret = kstrtol(arg + 2, 0, &offset); | |
413 | if (ret) | |
414 | break; | |
415 | ||
416 | f->fn = t->fetch[FETCH_MTD_file_offset]; | |
417 | f->data = (void *)offset; | |
8ab83f56 | 418 | } else { |
b079d374 NK |
419 | /* uprobes don't support symbols */ |
420 | if (!is_kprobe) | |
421 | return -EINVAL; | |
422 | ||
8ab83f56 SD |
423 | ret = traceprobe_split_symbol_offset(arg + 1, &offset); |
424 | if (ret) | |
425 | break; | |
426 | ||
427 | f->data = alloc_symbol_cache(arg + 1, offset); | |
428 | if (f->data) | |
429 | f->fn = t->fetch[FETCH_MTD_symbol]; | |
430 | } | |
431 | break; | |
432 | ||
433 | case '+': /* deref memory */ | |
bcd83ea6 | 434 | arg++; /* Skip '+', because kstrtol() rejects it. */ |
8ab83f56 SD |
435 | case '-': |
436 | tmp = strchr(arg, '('); | |
437 | if (!tmp) | |
438 | break; | |
439 | ||
440 | *tmp = '\0'; | |
bcd83ea6 | 441 | ret = kstrtol(arg, 0, &offset); |
8ab83f56 SD |
442 | |
443 | if (ret) | |
444 | break; | |
445 | ||
446 | arg = tmp + 1; | |
447 | tmp = strrchr(arg, ')'); | |
448 | ||
449 | if (tmp) { | |
450 | struct deref_fetch_param *dprm; | |
451 | const struct fetch_type *t2; | |
452 | ||
34fee3a1 | 453 | t2 = find_fetch_type(NULL, ftbl); |
8ab83f56 SD |
454 | *tmp = '\0'; |
455 | dprm = kzalloc(sizeof(struct deref_fetch_param), GFP_KERNEL); | |
456 | ||
457 | if (!dprm) | |
458 | return -ENOMEM; | |
459 | ||
460 | dprm->offset = offset; | |
3925f4a5 HL |
461 | dprm->fetch = t->fetch[FETCH_MTD_memory]; |
462 | dprm->fetch_size = get_fetch_size_function(t, | |
463 | dprm->fetch, ftbl); | |
f3f096cf | 464 | ret = parse_probe_arg(arg, t2, &dprm->orig, is_return, |
d9a16d3a | 465 | is_kprobe, ftbl); |
8ab83f56 SD |
466 | if (ret) |
467 | kfree(dprm); | |
468 | else { | |
469 | f->fn = t->fetch[FETCH_MTD_deref]; | |
470 | f->data = (void *)dprm; | |
471 | } | |
472 | } | |
473 | break; | |
474 | } | |
475 | if (!ret && !f->fn) { /* Parsed, but do not find fetch method */ | |
476 | pr_info("%s type has no corresponding fetch method.\n", t->name); | |
477 | ret = -EINVAL; | |
478 | } | |
479 | ||
480 | return ret; | |
481 | } | |
482 | ||
483 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | |
484 | ||
485 | /* Bitfield type needs to be parsed into a fetch function */ | |
486 | static int __parse_bitfield_probe_arg(const char *bf, | |
487 | const struct fetch_type *t, | |
488 | struct fetch_param *f) | |
489 | { | |
490 | struct bitfield_fetch_param *bprm; | |
491 | unsigned long bw, bo; | |
492 | char *tail; | |
493 | ||
494 | if (*bf != 'b') | |
495 | return 0; | |
496 | ||
497 | bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); | |
498 | if (!bprm) | |
499 | return -ENOMEM; | |
500 | ||
501 | bprm->orig = *f; | |
502 | f->fn = t->fetch[FETCH_MTD_bitfield]; | |
503 | f->data = (void *)bprm; | |
504 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ | |
505 | ||
506 | if (bw == 0 || *tail != '@') | |
507 | return -EINVAL; | |
508 | ||
509 | bf = tail + 1; | |
510 | bo = simple_strtoul(bf, &tail, 0); | |
511 | ||
512 | if (tail == bf || *tail != '/') | |
513 | return -EINVAL; | |
514 | ||
515 | bprm->hi_shift = BYTES_TO_BITS(t->size) - (bw + bo); | |
516 | bprm->low_shift = bprm->hi_shift + bo; | |
517 | ||
518 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | |
519 | } | |
520 | ||
521 | /* String length checking wrapper */ | |
522 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |
d9a16d3a SR |
523 | struct probe_arg *parg, bool is_return, bool is_kprobe, |
524 | const struct fetch_type *ftbl) | |
8ab83f56 SD |
525 | { |
526 | const char *t; | |
527 | int ret; | |
528 | ||
529 | if (strlen(arg) > MAX_ARGSTR_LEN) { | |
530 | pr_info("Argument is too long.: %s\n", arg); | |
531 | return -ENOSPC; | |
532 | } | |
533 | parg->comm = kstrdup(arg, GFP_KERNEL); | |
534 | if (!parg->comm) { | |
535 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | |
536 | return -ENOMEM; | |
537 | } | |
538 | t = strchr(parg->comm, ':'); | |
539 | if (t) { | |
540 | arg[t - parg->comm] = '\0'; | |
541 | t++; | |
542 | } | |
35abb67d OS |
543 | /* |
544 | * The default type of $comm should be "string", and it can't be | |
545 | * dereferenced. | |
546 | */ | |
547 | if (!t && strcmp(arg, "$comm") == 0) | |
548 | t = "string"; | |
34fee3a1 | 549 | parg->type = find_fetch_type(t, ftbl); |
8ab83f56 SD |
550 | if (!parg->type) { |
551 | pr_info("Unsupported type: %s\n", t); | |
552 | return -EINVAL; | |
553 | } | |
554 | parg->offset = *size; | |
555 | *size += parg->type->size; | |
d9a16d3a SR |
556 | ret = parse_probe_arg(arg, parg->type, &parg->fetch, is_return, |
557 | is_kprobe, ftbl); | |
8ab83f56 SD |
558 | |
559 | if (ret >= 0 && t != NULL) | |
560 | ret = __parse_bitfield_probe_arg(t, parg->type, &parg->fetch); | |
561 | ||
562 | if (ret >= 0) { | |
563 | parg->fetch_size.fn = get_fetch_size_function(parg->type, | |
34fee3a1 NK |
564 | parg->fetch.fn, |
565 | ftbl); | |
8ab83f56 SD |
566 | parg->fetch_size.data = parg->fetch.data; |
567 | } | |
568 | ||
569 | return ret; | |
570 | } | |
571 | ||
572 | /* Return 1 if name is reserved or already used by another argument */ | |
573 | int traceprobe_conflict_field_name(const char *name, | |
574 | struct probe_arg *args, int narg) | |
575 | { | |
576 | int i; | |
577 | ||
578 | for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) | |
579 | if (strcmp(reserved_field_names[i], name) == 0) | |
580 | return 1; | |
581 | ||
582 | for (i = 0; i < narg; i++) | |
583 | if (strcmp(args[i].name, name) == 0) | |
584 | return 1; | |
585 | ||
586 | return 0; | |
587 | } | |
588 | ||
589 | void traceprobe_update_arg(struct probe_arg *arg) | |
590 | { | |
591 | if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) | |
592 | update_bitfield_fetch_param(arg->fetch.data); | |
593 | else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | |
594 | update_deref_fetch_param(arg->fetch.data); | |
595 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) | |
596 | update_symbol_cache(arg->fetch.data); | |
597 | } | |
598 | ||
599 | void traceprobe_free_probe_arg(struct probe_arg *arg) | |
600 | { | |
601 | if (CHECK_FETCH_FUNCS(bitfield, arg->fetch.fn)) | |
602 | free_bitfield_fetch_param(arg->fetch.data); | |
603 | else if (CHECK_FETCH_FUNCS(deref, arg->fetch.fn)) | |
604 | free_deref_fetch_param(arg->fetch.data); | |
605 | else if (CHECK_FETCH_FUNCS(symbol, arg->fetch.fn)) | |
606 | free_symbol_cache(arg->fetch.data); | |
607 | ||
608 | kfree(arg->name); | |
609 | kfree(arg->comm); | |
610 | } | |
611 | ||
5bf652aa NK |
612 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
613 | bool is_return) | |
614 | { | |
615 | int i; | |
616 | int pos = 0; | |
617 | ||
618 | const char *fmt, *arg; | |
619 | ||
620 | if (!is_return) { | |
621 | fmt = "(%lx)"; | |
622 | arg = "REC->" FIELD_STRING_IP; | |
623 | } else { | |
624 | fmt = "(%lx <- %lx)"; | |
625 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | |
626 | } | |
627 | ||
628 | /* When len=0, we just calculate the needed length */ | |
629 | #define LEN_OR_ZERO (len ? len - pos : 0) | |
630 | ||
631 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | |
632 | ||
633 | for (i = 0; i < tp->nr_args; i++) { | |
634 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", | |
635 | tp->args[i].name, tp->args[i].type->fmt); | |
636 | } | |
637 | ||
638 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | |
639 | ||
640 | for (i = 0; i < tp->nr_args; i++) { | |
641 | if (strcmp(tp->args[i].type->name, "string") == 0) | |
642 | pos += snprintf(buf + pos, LEN_OR_ZERO, | |
643 | ", __get_str(%s)", | |
644 | tp->args[i].name); | |
645 | else | |
646 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", | |
647 | tp->args[i].name); | |
648 | } | |
649 | ||
650 | #undef LEN_OR_ZERO | |
651 | ||
652 | /* return the length of print_fmt */ | |
653 | return pos; | |
654 | } | |
655 | ||
656 | int set_print_fmt(struct trace_probe *tp, bool is_return) | |
657 | { | |
658 | int len; | |
659 | char *print_fmt; | |
660 | ||
661 | /* First: called with 0 length to calculate the needed length */ | |
662 | len = __set_print_fmt(tp, NULL, 0, is_return); | |
663 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | |
664 | if (!print_fmt) | |
665 | return -ENOMEM; | |
666 | ||
667 | /* Second: actually write the @print_fmt */ | |
668 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | |
669 | tp->call.print_fmt = print_fmt; | |
670 | ||
671 | return 0; | |
672 | } |