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 | 28 | #define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \ |
56de7630 | 29 | int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\ |
8ab83f56 | 30 | { \ |
56de7630 | 31 | trace_seq_printf(s, fmt, *(type *)data); \ |
d2b0191a | 32 | return !trace_seq_has_overflowed(s); \ |
8ab83f56 | 33 | } \ |
7bfbc63e | 34 | const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; |
8ab83f56 | 35 | |
bdca79c2 MH |
36 | DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u") |
37 | DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") | |
38 | DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u") | |
39 | DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu") | |
17ce3dc7 MH |
40 | DEFINE_BASIC_PRINT_TYPE_FUNC(s8, s8, "%d") |
41 | DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d") | |
42 | DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d") | |
43 | DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld") | |
44 | DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x") | |
45 | DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x") | |
46 | DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") | |
47 | DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") | |
8ab83f56 | 48 | |
60c2e0ce MH |
49 | int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent) |
50 | { | |
51 | trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data); | |
52 | return !trace_seq_has_overflowed(s); | |
53 | } | |
54 | const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS"; | |
55 | ||
8ab83f56 | 56 | /* Print type function for string type */ |
56de7630 | 57 | int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) |
8ab83f56 SD |
58 | { |
59 | int len = *(u32 *)data >> 16; | |
60 | ||
61 | if (!len) | |
56de7630 | 62 | trace_seq_puts(s, "(fault)"); |
8ab83f56 | 63 | else |
56de7630 | 64 | trace_seq_printf(s, "\"%s\"", |
d2b0191a SRRH |
65 | (const char *)get_loc_data(data, ent)); |
66 | return !trace_seq_has_overflowed(s); | |
8ab83f56 SD |
67 | } |
68 | ||
b26c74e1 | 69 | const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
8ab83f56 | 70 | |
f451bc89 MH |
71 | /* Fetch type information table */ |
72 | static const struct fetch_type probe_fetch_types[] = { | |
73 | /* Special types */ | |
74 | __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, | |
75 | "__data_loc char[]"), | |
76 | /* Basic types */ | |
77 | ASSIGN_FETCH_TYPE(u8, u8, 0), | |
78 | ASSIGN_FETCH_TYPE(u16, u16, 0), | |
79 | ASSIGN_FETCH_TYPE(u32, u32, 0), | |
80 | ASSIGN_FETCH_TYPE(u64, u64, 0), | |
81 | ASSIGN_FETCH_TYPE(s8, u8, 1), | |
82 | ASSIGN_FETCH_TYPE(s16, u16, 1), | |
83 | ASSIGN_FETCH_TYPE(s32, u32, 1), | |
84 | ASSIGN_FETCH_TYPE(s64, u64, 1), | |
85 | ASSIGN_FETCH_TYPE_ALIAS(x8, u8, u8, 0), | |
86 | ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0), | |
87 | ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0), | |
88 | ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0), | |
60c2e0ce | 89 | ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0), |
f451bc89 MH |
90 | |
91 | ASSIGN_FETCH_TYPE_END | |
92 | }; | |
93 | ||
94 | static const struct fetch_type *find_fetch_type(const char *type) | |
8ab83f56 SD |
95 | { |
96 | int i; | |
97 | ||
98 | if (!type) | |
99 | type = DEFAULT_FETCH_TYPE_STR; | |
100 | ||
101 | /* Special case: bitfield */ | |
102 | if (*type == 'b') { | |
103 | unsigned long bs; | |
104 | ||
105 | type = strchr(type, '/'); | |
106 | if (!type) | |
107 | goto fail; | |
108 | ||
109 | type++; | |
bcd83ea6 | 110 | if (kstrtoul(type, 0, &bs)) |
8ab83f56 SD |
111 | goto fail; |
112 | ||
113 | switch (bs) { | |
114 | case 8: | |
f451bc89 | 115 | return find_fetch_type("u8"); |
8ab83f56 | 116 | case 16: |
f451bc89 | 117 | return find_fetch_type("u16"); |
8ab83f56 | 118 | case 32: |
f451bc89 | 119 | return find_fetch_type("u32"); |
8ab83f56 | 120 | case 64: |
f451bc89 | 121 | return find_fetch_type("u64"); |
8ab83f56 SD |
122 | default: |
123 | goto fail; | |
124 | } | |
125 | } | |
126 | ||
f451bc89 MH |
127 | for (i = 0; probe_fetch_types[i].name; i++) { |
128 | if (strcmp(type, probe_fetch_types[i].name) == 0) | |
129 | return &probe_fetch_types[i]; | |
34fee3a1 | 130 | } |
8ab83f56 SD |
131 | |
132 | fail: | |
133 | return NULL; | |
134 | } | |
135 | ||
8ab83f56 | 136 | /* Split symbol and offset. */ |
c5d343b6 | 137 | int traceprobe_split_symbol_offset(char *symbol, long *offset) |
8ab83f56 SD |
138 | { |
139 | char *tmp; | |
140 | int ret; | |
141 | ||
142 | if (!offset) | |
143 | return -EINVAL; | |
144 | ||
c5d343b6 | 145 | tmp = strpbrk(symbol, "+-"); |
8ab83f56 | 146 | if (tmp) { |
c5d343b6 | 147 | ret = kstrtol(tmp, 0, offset); |
8ab83f56 SD |
148 | if (ret) |
149 | return ret; | |
8ab83f56 SD |
150 | *tmp = '\0'; |
151 | } else | |
152 | *offset = 0; | |
153 | ||
154 | return 0; | |
155 | } | |
156 | ||
157 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) | |
158 | ||
159 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | |
a1303af5 | 160 | struct fetch_insn *code, unsigned int flags) |
8ab83f56 SD |
161 | { |
162 | int ret = 0; | |
163 | unsigned long param; | |
164 | ||
165 | if (strcmp(arg, "retval") == 0) { | |
a1303af5 | 166 | if (flags & TPARG_FL_RETURN) |
53305928 | 167 | code->op = FETCH_OP_RETVAL; |
8ab83f56 SD |
168 | else |
169 | ret = -EINVAL; | |
170 | } else if (strncmp(arg, "stack", 5) == 0) { | |
171 | if (arg[5] == '\0') { | |
53305928 | 172 | code->op = FETCH_OP_STACKP; |
8ab83f56 | 173 | } else if (isdigit(arg[5])) { |
bcd83ea6 | 174 | ret = kstrtoul(arg + 5, 10, ¶m); |
a1303af5 MH |
175 | if (ret || ((flags & TPARG_FL_KERNEL) && |
176 | param > PARAM_MAX_STACK)) | |
8ab83f56 SD |
177 | ret = -EINVAL; |
178 | else { | |
53305928 MH |
179 | code->op = FETCH_OP_STACK; |
180 | code->param = (unsigned int)param; | |
8ab83f56 SD |
181 | } |
182 | } else | |
183 | ret = -EINVAL; | |
35abb67d | 184 | } else if (strcmp(arg, "comm") == 0) { |
53305928 | 185 | code->op = FETCH_OP_COMM; |
a1303af5 MH |
186 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
187 | } else if (((flags & TPARG_FL_MASK) == | |
188 | (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && | |
189 | strncmp(arg, "arg", 3) == 0) { | |
190 | if (!isdigit(arg[3])) | |
191 | return -EINVAL; | |
192 | ret = kstrtoul(arg + 3, 10, ¶m); | |
193 | if (ret || !param || param > PARAM_MAX_STACK) | |
194 | return -EINVAL; | |
195 | code->op = FETCH_OP_ARG; | |
196 | code->param = (unsigned int)param - 1; | |
197 | #endif | |
8ab83f56 SD |
198 | } else |
199 | ret = -EINVAL; | |
200 | ||
201 | return ret; | |
202 | } | |
203 | ||
204 | /* Recursive argument parser */ | |
53305928 MH |
205 | static int |
206 | parse_probe_arg(char *arg, const struct fetch_type *type, | |
207 | struct fetch_insn **pcode, struct fetch_insn *end, | |
a1303af5 | 208 | unsigned int flags) |
8ab83f56 | 209 | { |
53305928 | 210 | struct fetch_insn *code = *pcode; |
8ab83f56 | 211 | unsigned long param; |
bf173ca9 | 212 | long offset = 0; |
8ab83f56 | 213 | char *tmp; |
34fee3a1 | 214 | int ret = 0; |
8ab83f56 | 215 | |
8ab83f56 SD |
216 | switch (arg[0]) { |
217 | case '$': | |
a1303af5 | 218 | ret = parse_probe_vars(arg + 1, type, code, flags); |
8ab83f56 SD |
219 | break; |
220 | ||
221 | case '%': /* named register */ | |
222 | ret = regs_query_register_offset(arg + 1); | |
223 | if (ret >= 0) { | |
53305928 MH |
224 | code->op = FETCH_OP_REG; |
225 | code->param = (unsigned int)ret; | |
8ab83f56 SD |
226 | ret = 0; |
227 | } | |
228 | break; | |
229 | ||
b7e0bf34 | 230 | case '@': /* memory, file-offset or symbol */ |
8ab83f56 | 231 | if (isdigit(arg[1])) { |
bcd83ea6 | 232 | ret = kstrtoul(arg + 1, 0, ¶m); |
8ab83f56 SD |
233 | if (ret) |
234 | break; | |
53305928 MH |
235 | /* load address */ |
236 | code->op = FETCH_OP_IMM; | |
237 | code->immediate = param; | |
b7e0bf34 NK |
238 | } else if (arg[1] == '+') { |
239 | /* kprobes don't support file offsets */ | |
a1303af5 | 240 | if (flags & TPARG_FL_KERNEL) |
b7e0bf34 NK |
241 | return -EINVAL; |
242 | ||
243 | ret = kstrtol(arg + 2, 0, &offset); | |
244 | if (ret) | |
245 | break; | |
246 | ||
53305928 MH |
247 | code->op = FETCH_OP_FOFFS; |
248 | code->immediate = (unsigned long)offset; // imm64? | |
8ab83f56 | 249 | } else { |
b079d374 | 250 | /* uprobes don't support symbols */ |
a1303af5 | 251 | if (!(flags & TPARG_FL_KERNEL)) |
b079d374 NK |
252 | return -EINVAL; |
253 | ||
a6682814 MH |
254 | /* Preserve symbol for updating */ |
255 | code->op = FETCH_NOP_SYMBOL; | |
256 | code->data = kstrdup(arg + 1, GFP_KERNEL); | |
257 | if (!code->data) | |
258 | return -ENOMEM; | |
259 | if (++code == end) | |
260 | return -E2BIG; | |
8ab83f56 | 261 | |
53305928 | 262 | code->op = FETCH_OP_IMM; |
a6682814 | 263 | code->immediate = 0; |
8ab83f56 | 264 | } |
53305928 MH |
265 | /* These are fetching from memory */ |
266 | if (++code == end) | |
267 | return -E2BIG; | |
268 | *pcode = code; | |
269 | code->op = FETCH_OP_DEREF; | |
270 | code->offset = offset; | |
8ab83f56 SD |
271 | break; |
272 | ||
273 | case '+': /* deref memory */ | |
bcd83ea6 | 274 | arg++; /* Skip '+', because kstrtol() rejects it. */ |
8ab83f56 SD |
275 | case '-': |
276 | tmp = strchr(arg, '('); | |
277 | if (!tmp) | |
53305928 | 278 | return -EINVAL; |
8ab83f56 SD |
279 | |
280 | *tmp = '\0'; | |
bcd83ea6 | 281 | ret = kstrtol(arg, 0, &offset); |
8ab83f56 SD |
282 | if (ret) |
283 | break; | |
284 | ||
285 | arg = tmp + 1; | |
286 | tmp = strrchr(arg, ')'); | |
287 | ||
288 | if (tmp) { | |
f451bc89 | 289 | const struct fetch_type *t2 = find_fetch_type(NULL); |
8ab83f56 | 290 | |
8ab83f56 | 291 | *tmp = '\0'; |
a1303af5 | 292 | ret = parse_probe_arg(arg, t2, &code, end, flags); |
8ab83f56 | 293 | if (ret) |
53305928 MH |
294 | break; |
295 | if (code->op == FETCH_OP_COMM) | |
296 | return -EINVAL; | |
297 | if (++code == end) | |
298 | return -E2BIG; | |
299 | *pcode = code; | |
300 | ||
301 | code->op = FETCH_OP_DEREF; | |
302 | code->offset = offset; | |
8ab83f56 SD |
303 | } |
304 | break; | |
305 | } | |
53305928 MH |
306 | if (!ret && code->op == FETCH_OP_NOP) { |
307 | /* Parsed, but do not find fetch method */ | |
8ab83f56 SD |
308 | ret = -EINVAL; |
309 | } | |
8ab83f56 SD |
310 | return ret; |
311 | } | |
312 | ||
313 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | |
314 | ||
315 | /* Bitfield type needs to be parsed into a fetch function */ | |
316 | static int __parse_bitfield_probe_arg(const char *bf, | |
317 | const struct fetch_type *t, | |
53305928 | 318 | struct fetch_insn **pcode) |
8ab83f56 | 319 | { |
53305928 | 320 | struct fetch_insn *code = *pcode; |
8ab83f56 SD |
321 | unsigned long bw, bo; |
322 | char *tail; | |
323 | ||
324 | if (*bf != 'b') | |
325 | return 0; | |
326 | ||
8ab83f56 SD |
327 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
328 | ||
329 | if (bw == 0 || *tail != '@') | |
330 | return -EINVAL; | |
331 | ||
332 | bf = tail + 1; | |
333 | bo = simple_strtoul(bf, &tail, 0); | |
334 | ||
335 | if (tail == bf || *tail != '/') | |
336 | return -EINVAL; | |
53305928 MH |
337 | code++; |
338 | if (code->op != FETCH_OP_NOP) | |
339 | return -E2BIG; | |
340 | *pcode = code; | |
8ab83f56 | 341 | |
53305928 MH |
342 | code->op = FETCH_OP_MOD_BF; |
343 | code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); | |
344 | code->rshift = BYTES_TO_BITS(t->size) - bw; | |
345 | code->basesize = t->size; | |
8ab83f56 SD |
346 | |
347 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | |
348 | } | |
349 | ||
350 | /* String length checking wrapper */ | |
351 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |
a1303af5 | 352 | struct probe_arg *parg, unsigned int flags) |
8ab83f56 | 353 | { |
40b53b77 MH |
354 | struct fetch_insn *code, *scode, *tmp = NULL; |
355 | char *t, *t2; | |
356 | int ret, len; | |
8ab83f56 SD |
357 | |
358 | if (strlen(arg) > MAX_ARGSTR_LEN) { | |
359 | pr_info("Argument is too long.: %s\n", arg); | |
360 | return -ENOSPC; | |
361 | } | |
362 | parg->comm = kstrdup(arg, GFP_KERNEL); | |
363 | if (!parg->comm) { | |
364 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | |
365 | return -ENOMEM; | |
366 | } | |
40b53b77 | 367 | t = strchr(arg, ':'); |
8ab83f56 | 368 | if (t) { |
40b53b77 MH |
369 | *t = '\0'; |
370 | t2 = strchr(++t, '['); | |
371 | if (t2) { | |
372 | *t2 = '\0'; | |
373 | parg->count = simple_strtoul(t2 + 1, &t2, 0); | |
374 | if (strcmp(t2, "]") || parg->count == 0) | |
375 | return -EINVAL; | |
376 | if (parg->count > MAX_ARRAY_LEN) | |
377 | return -E2BIG; | |
378 | } | |
8ab83f56 | 379 | } |
35abb67d OS |
380 | /* |
381 | * The default type of $comm should be "string", and it can't be | |
382 | * dereferenced. | |
383 | */ | |
384 | if (!t && strcmp(arg, "$comm") == 0) | |
40b53b77 MH |
385 | parg->type = find_fetch_type("string"); |
386 | else | |
387 | parg->type = find_fetch_type(t); | |
8ab83f56 SD |
388 | if (!parg->type) { |
389 | pr_info("Unsupported type: %s\n", t); | |
390 | return -EINVAL; | |
391 | } | |
392 | parg->offset = *size; | |
40b53b77 MH |
393 | *size += parg->type->size * (parg->count ?: 1); |
394 | ||
395 | if (parg->count) { | |
396 | len = strlen(parg->type->fmttype) + 6; | |
397 | parg->fmt = kmalloc(len, GFP_KERNEL); | |
398 | if (!parg->fmt) | |
399 | return -ENOMEM; | |
400 | snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, | |
401 | parg->count); | |
402 | } | |
8ab83f56 | 403 | |
53305928 MH |
404 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); |
405 | if (!code) | |
406 | return -ENOMEM; | |
407 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; | |
408 | ||
409 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | |
a1303af5 | 410 | flags); |
53305928 MH |
411 | if (ret) |
412 | goto fail; | |
413 | ||
414 | /* Store operation */ | |
415 | if (!strcmp(parg->type->name, "string")) { | |
416 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | |
417 | code->op != FETCH_OP_COMM) { | |
418 | pr_info("string only accepts memory or address.\n"); | |
419 | ret = -EINVAL; | |
420 | goto fail; | |
421 | } | |
40b53b77 MH |
422 | if (code->op != FETCH_OP_DEREF || parg->count) { |
423 | /* | |
424 | * IMM and COMM is pointing actual address, those must | |
425 | * be kept, and if parg->count != 0, this is an array | |
426 | * of string pointers instead of string address itself. | |
427 | */ | |
53305928 | 428 | code++; |
40b53b77 MH |
429 | if (code->op != FETCH_OP_NOP) { |
430 | ret = -E2BIG; | |
431 | goto fail; | |
432 | } | |
433 | } | |
53305928 | 434 | code->op = FETCH_OP_ST_STRING; /* In DEREF case, replace it */ |
40b53b77 | 435 | code->size = parg->type->size; |
53305928 MH |
436 | parg->dynamic = true; |
437 | } else if (code->op == FETCH_OP_DEREF) { | |
438 | code->op = FETCH_OP_ST_MEM; | |
439 | code->size = parg->type->size; | |
440 | } else { | |
441 | code++; | |
442 | if (code->op != FETCH_OP_NOP) { | |
443 | ret = -E2BIG; | |
444 | goto fail; | |
445 | } | |
446 | code->op = FETCH_OP_ST_RAW; | |
447 | code->size = parg->type->size; | |
448 | } | |
40b53b77 | 449 | scode = code; |
53305928 MH |
450 | /* Modify operation */ |
451 | if (t != NULL) { | |
452 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | |
453 | if (ret) | |
454 | goto fail; | |
8ab83f56 | 455 | } |
40b53b77 MH |
456 | /* Loop(Array) operation */ |
457 | if (parg->count) { | |
458 | if (scode->op != FETCH_OP_ST_MEM && | |
459 | scode->op != FETCH_OP_ST_STRING) { | |
460 | pr_info("array only accepts memory or address\n"); | |
461 | ret = -EINVAL; | |
462 | goto fail; | |
463 | } | |
464 | code++; | |
465 | if (code->op != FETCH_OP_NOP) { | |
466 | ret = -E2BIG; | |
467 | goto fail; | |
468 | } | |
469 | code->op = FETCH_OP_LP_ARRAY; | |
470 | code->param = parg->count; | |
471 | } | |
53305928 MH |
472 | code++; |
473 | code->op = FETCH_OP_END; | |
474 | ||
475 | /* Shrink down the code buffer */ | |
476 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | |
477 | if (!parg->code) | |
478 | ret = -ENOMEM; | |
479 | else | |
480 | memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); | |
481 | ||
482 | fail: | |
a6682814 MH |
483 | if (ret) { |
484 | for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) | |
485 | if (code->op == FETCH_NOP_SYMBOL) | |
486 | kfree(code->data); | |
487 | } | |
53305928 | 488 | kfree(tmp); |
8ab83f56 SD |
489 | |
490 | return ret; | |
491 | } | |
492 | ||
493 | /* Return 1 if name is reserved or already used by another argument */ | |
494 | int traceprobe_conflict_field_name(const char *name, | |
495 | struct probe_arg *args, int narg) | |
496 | { | |
497 | int i; | |
498 | ||
499 | for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) | |
500 | if (strcmp(reserved_field_names[i], name) == 0) | |
501 | return 1; | |
502 | ||
503 | for (i = 0; i < narg; i++) | |
504 | if (strcmp(args[i].name, name) == 0) | |
505 | return 1; | |
506 | ||
507 | return 0; | |
508 | } | |
509 | ||
8ab83f56 SD |
510 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
511 | { | |
a6682814 MH |
512 | struct fetch_insn *code = arg->code; |
513 | ||
514 | while (code && code->op != FETCH_OP_END) { | |
515 | if (code->op == FETCH_NOP_SYMBOL) | |
516 | kfree(code->data); | |
517 | code++; | |
518 | } | |
53305928 | 519 | kfree(arg->code); |
8ab83f56 SD |
520 | kfree(arg->name); |
521 | kfree(arg->comm); | |
40b53b77 | 522 | kfree(arg->fmt); |
8ab83f56 SD |
523 | } |
524 | ||
a6682814 MH |
525 | int traceprobe_update_arg(struct probe_arg *arg) |
526 | { | |
527 | struct fetch_insn *code = arg->code; | |
528 | long offset; | |
529 | char *tmp; | |
530 | char c; | |
531 | int ret = 0; | |
532 | ||
533 | while (code && code->op != FETCH_OP_END) { | |
534 | if (code->op == FETCH_NOP_SYMBOL) { | |
535 | if (code[1].op != FETCH_OP_IMM) | |
536 | return -EINVAL; | |
537 | ||
ee474b81 | 538 | tmp = strpbrk(code->data, "+-"); |
a6682814 MH |
539 | if (tmp) |
540 | c = *tmp; | |
541 | ret = traceprobe_split_symbol_offset(code->data, | |
542 | &offset); | |
543 | if (ret) | |
544 | return ret; | |
545 | ||
546 | code[1].immediate = | |
547 | (unsigned long)kallsyms_lookup_name(code->data); | |
548 | if (tmp) | |
549 | *tmp = c; | |
550 | if (!code[1].immediate) | |
551 | return -ENOENT; | |
552 | code[1].immediate += offset; | |
553 | } | |
554 | code++; | |
555 | } | |
556 | return 0; | |
557 | } | |
558 | ||
40b53b77 MH |
559 | /* When len=0, we just calculate the needed length */ |
560 | #define LEN_OR_ZERO (len ? len - pos : 0) | |
5bf652aa NK |
561 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
562 | bool is_return) | |
563 | { | |
40b53b77 MH |
564 | struct probe_arg *parg; |
565 | int i, j; | |
5bf652aa | 566 | int pos = 0; |
5bf652aa NK |
567 | const char *fmt, *arg; |
568 | ||
569 | if (!is_return) { | |
570 | fmt = "(%lx)"; | |
571 | arg = "REC->" FIELD_STRING_IP; | |
572 | } else { | |
573 | fmt = "(%lx <- %lx)"; | |
574 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | |
575 | } | |
576 | ||
5bf652aa NK |
577 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
578 | ||
579 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
580 | parg = tp->args + i; |
581 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); | |
582 | if (parg->count) { | |
583 | pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", | |
584 | parg->type->fmt); | |
585 | for (j = 1; j < parg->count; j++) | |
586 | pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", | |
587 | parg->type->fmt); | |
588 | pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); | |
589 | } else | |
590 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", | |
591 | parg->type->fmt); | |
5bf652aa NK |
592 | } |
593 | ||
594 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | |
595 | ||
596 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
597 | parg = tp->args + i; |
598 | if (parg->count) { | |
599 | if (strcmp(parg->type->name, "string") == 0) | |
600 | fmt = ", __get_str(%s[%d])"; | |
601 | else | |
602 | fmt = ", REC->%s[%d]"; | |
603 | for (j = 0; j < parg->count; j++) | |
604 | pos += snprintf(buf + pos, LEN_OR_ZERO, | |
605 | fmt, parg->name, j); | |
606 | } else { | |
607 | if (strcmp(parg->type->name, "string") == 0) | |
608 | fmt = ", __get_str(%s)"; | |
609 | else | |
610 | fmt = ", REC->%s"; | |
5bf652aa | 611 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
40b53b77 MH |
612 | fmt, parg->name); |
613 | } | |
5bf652aa NK |
614 | } |
615 | ||
5bf652aa NK |
616 | /* return the length of print_fmt */ |
617 | return pos; | |
618 | } | |
40b53b77 | 619 | #undef LEN_OR_ZERO |
5bf652aa | 620 | |
0a46c854 | 621 | int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
5bf652aa NK |
622 | { |
623 | int len; | |
624 | char *print_fmt; | |
625 | ||
626 | /* First: called with 0 length to calculate the needed length */ | |
627 | len = __set_print_fmt(tp, NULL, 0, is_return); | |
628 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | |
629 | if (!print_fmt) | |
630 | return -ENOMEM; | |
631 | ||
632 | /* Second: actually write the @print_fmt */ | |
633 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | |
634 | tp->call.print_fmt = print_fmt; | |
635 | ||
636 | return 0; | |
637 | } | |
eeb07b06 MH |
638 | |
639 | int traceprobe_define_arg_fields(struct trace_event_call *event_call, | |
640 | size_t offset, struct trace_probe *tp) | |
641 | { | |
642 | int ret, i; | |
643 | ||
644 | /* Set argument names as fields */ | |
645 | for (i = 0; i < tp->nr_args; i++) { | |
646 | struct probe_arg *parg = &tp->args[i]; | |
40b53b77 MH |
647 | const char *fmt = parg->type->fmttype; |
648 | int size = parg->type->size; | |
649 | ||
650 | if (parg->fmt) | |
651 | fmt = parg->fmt; | |
652 | if (parg->count) | |
653 | size *= parg->count; | |
654 | ret = trace_define_field(event_call, fmt, parg->name, | |
655 | offset + parg->offset, size, | |
eeb07b06 MH |
656 | parg->type->is_signed, |
657 | FILTER_OTHER); | |
658 | if (ret) | |
659 | return ret; | |
660 | } | |
661 | return 0; | |
662 | } |