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 | ||
08416252 | 16 | static const char *reserved_field_names[] = { |
8ab83f56 SD |
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 | ||
6212dd29 MH |
157 | /* @buf must has MAX_EVENT_NAME_LEN size */ |
158 | int traceprobe_parse_event_name(const char **pevent, const char **pgroup, | |
159 | char *buf) | |
160 | { | |
161 | const char *slash, *event = *pevent; | |
162 | ||
163 | slash = strchr(event, '/'); | |
164 | if (slash) { | |
165 | if (slash == event) { | |
166 | pr_info("Group name is not specified\n"); | |
167 | return -EINVAL; | |
168 | } | |
169 | if (slash - event + 1 > MAX_EVENT_NAME_LEN) { | |
170 | pr_info("Group name is too long\n"); | |
171 | return -E2BIG; | |
172 | } | |
173 | strlcpy(buf, event, slash - event + 1); | |
174 | *pgroup = buf; | |
175 | *pevent = slash + 1; | |
176 | } | |
177 | if (strlen(event) == 0) { | |
178 | pr_info("Event name is not specified\n"); | |
179 | return -EINVAL; | |
180 | } | |
181 | return 0; | |
182 | } | |
183 | ||
8ab83f56 SD |
184 | #define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) |
185 | ||
186 | static int parse_probe_vars(char *arg, const struct fetch_type *t, | |
a1303af5 | 187 | struct fetch_insn *code, unsigned int flags) |
8ab83f56 | 188 | { |
8ab83f56 | 189 | unsigned long param; |
3d739c1f SRV |
190 | int ret = 0; |
191 | int len; | |
8ab83f56 SD |
192 | |
193 | if (strcmp(arg, "retval") == 0) { | |
a1303af5 | 194 | if (flags & TPARG_FL_RETURN) |
53305928 | 195 | code->op = FETCH_OP_RETVAL; |
8ab83f56 SD |
196 | else |
197 | ret = -EINVAL; | |
3d739c1f SRV |
198 | } else if ((len = str_has_prefix(arg, "stack"))) { |
199 | if (arg[len] == '\0') { | |
53305928 | 200 | code->op = FETCH_OP_STACKP; |
3d739c1f SRV |
201 | } else if (isdigit(arg[len])) { |
202 | ret = kstrtoul(arg + len, 10, ¶m); | |
a1303af5 MH |
203 | if (ret || ((flags & TPARG_FL_KERNEL) && |
204 | param > PARAM_MAX_STACK)) | |
8ab83f56 SD |
205 | ret = -EINVAL; |
206 | else { | |
53305928 MH |
207 | code->op = FETCH_OP_STACK; |
208 | code->param = (unsigned int)param; | |
8ab83f56 SD |
209 | } |
210 | } else | |
211 | ret = -EINVAL; | |
35abb67d | 212 | } else if (strcmp(arg, "comm") == 0) { |
53305928 | 213 | code->op = FETCH_OP_COMM; |
a1303af5 MH |
214 | #ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API |
215 | } else if (((flags & TPARG_FL_MASK) == | |
216 | (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && | |
3d739c1f SRV |
217 | (len = str_has_prefix(arg, "arg"))) { |
218 | if (!isdigit(arg[len])) | |
a1303af5 | 219 | return -EINVAL; |
3d739c1f | 220 | ret = kstrtoul(arg + len, 10, ¶m); |
a1303af5 MH |
221 | if (ret || !param || param > PARAM_MAX_STACK) |
222 | return -EINVAL; | |
223 | code->op = FETCH_OP_ARG; | |
224 | code->param = (unsigned int)param - 1; | |
225 | #endif | |
8ab83f56 SD |
226 | } else |
227 | ret = -EINVAL; | |
228 | ||
229 | return ret; | |
230 | } | |
231 | ||
232 | /* Recursive argument parser */ | |
53305928 MH |
233 | static int |
234 | parse_probe_arg(char *arg, const struct fetch_type *type, | |
235 | struct fetch_insn **pcode, struct fetch_insn *end, | |
a1303af5 | 236 | unsigned int flags) |
8ab83f56 | 237 | { |
53305928 | 238 | struct fetch_insn *code = *pcode; |
8ab83f56 | 239 | unsigned long param; |
bf173ca9 | 240 | long offset = 0; |
8ab83f56 | 241 | char *tmp; |
34fee3a1 | 242 | int ret = 0; |
8ab83f56 | 243 | |
8ab83f56 SD |
244 | switch (arg[0]) { |
245 | case '$': | |
a1303af5 | 246 | ret = parse_probe_vars(arg + 1, type, code, flags); |
8ab83f56 SD |
247 | break; |
248 | ||
249 | case '%': /* named register */ | |
250 | ret = regs_query_register_offset(arg + 1); | |
251 | if (ret >= 0) { | |
53305928 MH |
252 | code->op = FETCH_OP_REG; |
253 | code->param = (unsigned int)ret; | |
8ab83f56 SD |
254 | ret = 0; |
255 | } | |
256 | break; | |
257 | ||
b7e0bf34 | 258 | case '@': /* memory, file-offset or symbol */ |
8ab83f56 | 259 | if (isdigit(arg[1])) { |
bcd83ea6 | 260 | ret = kstrtoul(arg + 1, 0, ¶m); |
8ab83f56 SD |
261 | if (ret) |
262 | break; | |
53305928 MH |
263 | /* load address */ |
264 | code->op = FETCH_OP_IMM; | |
265 | code->immediate = param; | |
b7e0bf34 NK |
266 | } else if (arg[1] == '+') { |
267 | /* kprobes don't support file offsets */ | |
a1303af5 | 268 | if (flags & TPARG_FL_KERNEL) |
b7e0bf34 NK |
269 | return -EINVAL; |
270 | ||
271 | ret = kstrtol(arg + 2, 0, &offset); | |
272 | if (ret) | |
273 | break; | |
274 | ||
53305928 MH |
275 | code->op = FETCH_OP_FOFFS; |
276 | code->immediate = (unsigned long)offset; // imm64? | |
8ab83f56 | 277 | } else { |
b079d374 | 278 | /* uprobes don't support symbols */ |
a1303af5 | 279 | if (!(flags & TPARG_FL_KERNEL)) |
b079d374 NK |
280 | return -EINVAL; |
281 | ||
a6682814 MH |
282 | /* Preserve symbol for updating */ |
283 | code->op = FETCH_NOP_SYMBOL; | |
284 | code->data = kstrdup(arg + 1, GFP_KERNEL); | |
285 | if (!code->data) | |
286 | return -ENOMEM; | |
287 | if (++code == end) | |
288 | return -E2BIG; | |
8ab83f56 | 289 | |
53305928 | 290 | code->op = FETCH_OP_IMM; |
a6682814 | 291 | code->immediate = 0; |
8ab83f56 | 292 | } |
53305928 MH |
293 | /* These are fetching from memory */ |
294 | if (++code == end) | |
295 | return -E2BIG; | |
296 | *pcode = code; | |
297 | code->op = FETCH_OP_DEREF; | |
298 | code->offset = offset; | |
8ab83f56 SD |
299 | break; |
300 | ||
301 | case '+': /* deref memory */ | |
bcd83ea6 | 302 | arg++; /* Skip '+', because kstrtol() rejects it. */ |
91457c01 | 303 | /* fall through */ |
8ab83f56 SD |
304 | case '-': |
305 | tmp = strchr(arg, '('); | |
306 | if (!tmp) | |
53305928 | 307 | return -EINVAL; |
8ab83f56 SD |
308 | |
309 | *tmp = '\0'; | |
bcd83ea6 | 310 | ret = kstrtol(arg, 0, &offset); |
8ab83f56 SD |
311 | if (ret) |
312 | break; | |
313 | ||
314 | arg = tmp + 1; | |
315 | tmp = strrchr(arg, ')'); | |
316 | ||
317 | if (tmp) { | |
f451bc89 | 318 | const struct fetch_type *t2 = find_fetch_type(NULL); |
8ab83f56 | 319 | |
8ab83f56 | 320 | *tmp = '\0'; |
a1303af5 | 321 | ret = parse_probe_arg(arg, t2, &code, end, flags); |
8ab83f56 | 322 | if (ret) |
53305928 MH |
323 | break; |
324 | if (code->op == FETCH_OP_COMM) | |
325 | return -EINVAL; | |
326 | if (++code == end) | |
327 | return -E2BIG; | |
328 | *pcode = code; | |
329 | ||
330 | code->op = FETCH_OP_DEREF; | |
331 | code->offset = offset; | |
8ab83f56 SD |
332 | } |
333 | break; | |
334 | } | |
53305928 MH |
335 | if (!ret && code->op == FETCH_OP_NOP) { |
336 | /* Parsed, but do not find fetch method */ | |
8ab83f56 SD |
337 | ret = -EINVAL; |
338 | } | |
8ab83f56 SD |
339 | return ret; |
340 | } | |
341 | ||
342 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | |
343 | ||
344 | /* Bitfield type needs to be parsed into a fetch function */ | |
345 | static int __parse_bitfield_probe_arg(const char *bf, | |
346 | const struct fetch_type *t, | |
53305928 | 347 | struct fetch_insn **pcode) |
8ab83f56 | 348 | { |
53305928 | 349 | struct fetch_insn *code = *pcode; |
8ab83f56 SD |
350 | unsigned long bw, bo; |
351 | char *tail; | |
352 | ||
353 | if (*bf != 'b') | |
354 | return 0; | |
355 | ||
8ab83f56 SD |
356 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
357 | ||
358 | if (bw == 0 || *tail != '@') | |
359 | return -EINVAL; | |
360 | ||
361 | bf = tail + 1; | |
362 | bo = simple_strtoul(bf, &tail, 0); | |
363 | ||
364 | if (tail == bf || *tail != '/') | |
365 | return -EINVAL; | |
53305928 MH |
366 | code++; |
367 | if (code->op != FETCH_OP_NOP) | |
368 | return -E2BIG; | |
369 | *pcode = code; | |
8ab83f56 | 370 | |
53305928 MH |
371 | code->op = FETCH_OP_MOD_BF; |
372 | code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); | |
373 | code->rshift = BYTES_TO_BITS(t->size) - bw; | |
374 | code->basesize = t->size; | |
8ab83f56 SD |
375 | |
376 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | |
377 | } | |
378 | ||
379 | /* String length checking wrapper */ | |
d00bbea9 | 380 | static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
a1303af5 | 381 | struct probe_arg *parg, unsigned int flags) |
8ab83f56 | 382 | { |
40b53b77 MH |
383 | struct fetch_insn *code, *scode, *tmp = NULL; |
384 | char *t, *t2; | |
385 | int ret, len; | |
8ab83f56 SD |
386 | |
387 | if (strlen(arg) > MAX_ARGSTR_LEN) { | |
388 | pr_info("Argument is too long.: %s\n", arg); | |
389 | return -ENOSPC; | |
390 | } | |
391 | parg->comm = kstrdup(arg, GFP_KERNEL); | |
392 | if (!parg->comm) { | |
393 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | |
394 | return -ENOMEM; | |
395 | } | |
40b53b77 | 396 | t = strchr(arg, ':'); |
8ab83f56 | 397 | if (t) { |
40b53b77 MH |
398 | *t = '\0'; |
399 | t2 = strchr(++t, '['); | |
400 | if (t2) { | |
401 | *t2 = '\0'; | |
402 | parg->count = simple_strtoul(t2 + 1, &t2, 0); | |
403 | if (strcmp(t2, "]") || parg->count == 0) | |
404 | return -EINVAL; | |
405 | if (parg->count > MAX_ARRAY_LEN) | |
406 | return -E2BIG; | |
407 | } | |
8ab83f56 | 408 | } |
35abb67d OS |
409 | /* |
410 | * The default type of $comm should be "string", and it can't be | |
411 | * dereferenced. | |
412 | */ | |
413 | if (!t && strcmp(arg, "$comm") == 0) | |
40b53b77 MH |
414 | parg->type = find_fetch_type("string"); |
415 | else | |
416 | parg->type = find_fetch_type(t); | |
8ab83f56 SD |
417 | if (!parg->type) { |
418 | pr_info("Unsupported type: %s\n", t); | |
419 | return -EINVAL; | |
420 | } | |
421 | parg->offset = *size; | |
40b53b77 MH |
422 | *size += parg->type->size * (parg->count ?: 1); |
423 | ||
424 | if (parg->count) { | |
425 | len = strlen(parg->type->fmttype) + 6; | |
426 | parg->fmt = kmalloc(len, GFP_KERNEL); | |
427 | if (!parg->fmt) | |
428 | return -ENOMEM; | |
429 | snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, | |
430 | parg->count); | |
431 | } | |
8ab83f56 | 432 | |
53305928 MH |
433 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); |
434 | if (!code) | |
435 | return -ENOMEM; | |
436 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; | |
437 | ||
438 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | |
a1303af5 | 439 | flags); |
53305928 MH |
440 | if (ret) |
441 | goto fail; | |
442 | ||
443 | /* Store operation */ | |
444 | if (!strcmp(parg->type->name, "string")) { | |
445 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | |
446 | code->op != FETCH_OP_COMM) { | |
447 | pr_info("string only accepts memory or address.\n"); | |
448 | ret = -EINVAL; | |
449 | goto fail; | |
450 | } | |
40b53b77 MH |
451 | if (code->op != FETCH_OP_DEREF || parg->count) { |
452 | /* | |
453 | * IMM and COMM is pointing actual address, those must | |
454 | * be kept, and if parg->count != 0, this is an array | |
455 | * of string pointers instead of string address itself. | |
456 | */ | |
53305928 | 457 | code++; |
40b53b77 MH |
458 | if (code->op != FETCH_OP_NOP) { |
459 | ret = -E2BIG; | |
460 | goto fail; | |
461 | } | |
462 | } | |
53305928 | 463 | code->op = FETCH_OP_ST_STRING; /* In DEREF case, replace it */ |
40b53b77 | 464 | code->size = parg->type->size; |
53305928 MH |
465 | parg->dynamic = true; |
466 | } else if (code->op == FETCH_OP_DEREF) { | |
467 | code->op = FETCH_OP_ST_MEM; | |
468 | code->size = parg->type->size; | |
469 | } else { | |
470 | code++; | |
471 | if (code->op != FETCH_OP_NOP) { | |
472 | ret = -E2BIG; | |
473 | goto fail; | |
474 | } | |
475 | code->op = FETCH_OP_ST_RAW; | |
476 | code->size = parg->type->size; | |
477 | } | |
40b53b77 | 478 | scode = code; |
53305928 MH |
479 | /* Modify operation */ |
480 | if (t != NULL) { | |
481 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | |
482 | if (ret) | |
483 | goto fail; | |
8ab83f56 | 484 | } |
40b53b77 MH |
485 | /* Loop(Array) operation */ |
486 | if (parg->count) { | |
487 | if (scode->op != FETCH_OP_ST_MEM && | |
488 | scode->op != FETCH_OP_ST_STRING) { | |
489 | pr_info("array only accepts memory or address\n"); | |
490 | ret = -EINVAL; | |
491 | goto fail; | |
492 | } | |
493 | code++; | |
494 | if (code->op != FETCH_OP_NOP) { | |
495 | ret = -E2BIG; | |
496 | goto fail; | |
497 | } | |
498 | code->op = FETCH_OP_LP_ARRAY; | |
499 | code->param = parg->count; | |
500 | } | |
53305928 MH |
501 | code++; |
502 | code->op = FETCH_OP_END; | |
503 | ||
504 | /* Shrink down the code buffer */ | |
505 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | |
506 | if (!parg->code) | |
507 | ret = -ENOMEM; | |
508 | else | |
509 | memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); | |
510 | ||
511 | fail: | |
a6682814 MH |
512 | if (ret) { |
513 | for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) | |
514 | if (code->op == FETCH_NOP_SYMBOL) | |
515 | kfree(code->data); | |
516 | } | |
53305928 | 517 | kfree(tmp); |
8ab83f56 SD |
518 | |
519 | return ret; | |
520 | } | |
521 | ||
522 | /* Return 1 if name is reserved or already used by another argument */ | |
d00bbea9 MH |
523 | static int traceprobe_conflict_field_name(const char *name, |
524 | struct probe_arg *args, int narg) | |
8ab83f56 SD |
525 | { |
526 | int i; | |
527 | ||
528 | for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) | |
529 | if (strcmp(reserved_field_names[i], name) == 0) | |
530 | return 1; | |
531 | ||
532 | for (i = 0; i < narg; i++) | |
533 | if (strcmp(args[i].name, name) == 0) | |
534 | return 1; | |
535 | ||
536 | return 0; | |
537 | } | |
538 | ||
d00bbea9 MH |
539 | int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, |
540 | unsigned int flags) | |
541 | { | |
542 | struct probe_arg *parg = &tp->args[i]; | |
543 | char *body; | |
544 | int ret; | |
545 | ||
546 | /* Increment count for freeing args in error case */ | |
547 | tp->nr_args++; | |
548 | ||
549 | body = strchr(arg, '='); | |
550 | if (body) { | |
551 | parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); | |
552 | body++; | |
553 | } else { | |
554 | /* If argument name is omitted, set "argN" */ | |
555 | parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1); | |
556 | body = arg; | |
557 | } | |
558 | if (!parg->name) | |
559 | return -ENOMEM; | |
560 | ||
561 | if (!is_good_name(parg->name)) { | |
562 | pr_info("Invalid argument[%d] name: %s\n", | |
563 | i, parg->name); | |
564 | return -EINVAL; | |
565 | } | |
566 | ||
567 | if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { | |
568 | pr_info("Argument[%d]: '%s' conflicts with another field.\n", | |
569 | i, parg->name); | |
570 | return -EINVAL; | |
571 | } | |
572 | ||
573 | /* Parse fetch argument */ | |
574 | ret = traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags); | |
575 | if (ret) | |
576 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | |
577 | return ret; | |
578 | } | |
579 | ||
8ab83f56 SD |
580 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
581 | { | |
a6682814 MH |
582 | struct fetch_insn *code = arg->code; |
583 | ||
584 | while (code && code->op != FETCH_OP_END) { | |
585 | if (code->op == FETCH_NOP_SYMBOL) | |
586 | kfree(code->data); | |
587 | code++; | |
588 | } | |
53305928 | 589 | kfree(arg->code); |
8ab83f56 SD |
590 | kfree(arg->name); |
591 | kfree(arg->comm); | |
40b53b77 | 592 | kfree(arg->fmt); |
8ab83f56 SD |
593 | } |
594 | ||
a6682814 MH |
595 | int traceprobe_update_arg(struct probe_arg *arg) |
596 | { | |
597 | struct fetch_insn *code = arg->code; | |
598 | long offset; | |
599 | char *tmp; | |
600 | char c; | |
601 | int ret = 0; | |
602 | ||
603 | while (code && code->op != FETCH_OP_END) { | |
604 | if (code->op == FETCH_NOP_SYMBOL) { | |
605 | if (code[1].op != FETCH_OP_IMM) | |
606 | return -EINVAL; | |
607 | ||
ee474b81 | 608 | tmp = strpbrk(code->data, "+-"); |
a6682814 MH |
609 | if (tmp) |
610 | c = *tmp; | |
611 | ret = traceprobe_split_symbol_offset(code->data, | |
612 | &offset); | |
613 | if (ret) | |
614 | return ret; | |
615 | ||
616 | code[1].immediate = | |
617 | (unsigned long)kallsyms_lookup_name(code->data); | |
618 | if (tmp) | |
619 | *tmp = c; | |
620 | if (!code[1].immediate) | |
621 | return -ENOENT; | |
622 | code[1].immediate += offset; | |
623 | } | |
624 | code++; | |
625 | } | |
626 | return 0; | |
627 | } | |
628 | ||
40b53b77 MH |
629 | /* When len=0, we just calculate the needed length */ |
630 | #define LEN_OR_ZERO (len ? len - pos : 0) | |
5bf652aa NK |
631 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
632 | bool is_return) | |
633 | { | |
40b53b77 MH |
634 | struct probe_arg *parg; |
635 | int i, j; | |
5bf652aa | 636 | int pos = 0; |
5bf652aa NK |
637 | const char *fmt, *arg; |
638 | ||
639 | if (!is_return) { | |
640 | fmt = "(%lx)"; | |
641 | arg = "REC->" FIELD_STRING_IP; | |
642 | } else { | |
643 | fmt = "(%lx <- %lx)"; | |
644 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | |
645 | } | |
646 | ||
5bf652aa NK |
647 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
648 | ||
649 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
650 | parg = tp->args + i; |
651 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); | |
652 | if (parg->count) { | |
653 | pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", | |
654 | parg->type->fmt); | |
655 | for (j = 1; j < parg->count; j++) | |
656 | pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", | |
657 | parg->type->fmt); | |
658 | pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); | |
659 | } else | |
660 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", | |
661 | parg->type->fmt); | |
5bf652aa NK |
662 | } |
663 | ||
664 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | |
665 | ||
666 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
667 | parg = tp->args + i; |
668 | if (parg->count) { | |
669 | if (strcmp(parg->type->name, "string") == 0) | |
670 | fmt = ", __get_str(%s[%d])"; | |
671 | else | |
672 | fmt = ", REC->%s[%d]"; | |
673 | for (j = 0; j < parg->count; j++) | |
674 | pos += snprintf(buf + pos, LEN_OR_ZERO, | |
675 | fmt, parg->name, j); | |
676 | } else { | |
677 | if (strcmp(parg->type->name, "string") == 0) | |
678 | fmt = ", __get_str(%s)"; | |
679 | else | |
680 | fmt = ", REC->%s"; | |
5bf652aa | 681 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
40b53b77 MH |
682 | fmt, parg->name); |
683 | } | |
5bf652aa NK |
684 | } |
685 | ||
5bf652aa NK |
686 | /* return the length of print_fmt */ |
687 | return pos; | |
688 | } | |
40b53b77 | 689 | #undef LEN_OR_ZERO |
5bf652aa | 690 | |
0a46c854 | 691 | int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
5bf652aa NK |
692 | { |
693 | int len; | |
694 | char *print_fmt; | |
695 | ||
696 | /* First: called with 0 length to calculate the needed length */ | |
697 | len = __set_print_fmt(tp, NULL, 0, is_return); | |
698 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | |
699 | if (!print_fmt) | |
700 | return -ENOMEM; | |
701 | ||
702 | /* Second: actually write the @print_fmt */ | |
703 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | |
704 | tp->call.print_fmt = print_fmt; | |
705 | ||
706 | return 0; | |
707 | } | |
eeb07b06 MH |
708 | |
709 | int traceprobe_define_arg_fields(struct trace_event_call *event_call, | |
710 | size_t offset, struct trace_probe *tp) | |
711 | { | |
712 | int ret, i; | |
713 | ||
714 | /* Set argument names as fields */ | |
715 | for (i = 0; i < tp->nr_args; i++) { | |
716 | struct probe_arg *parg = &tp->args[i]; | |
40b53b77 MH |
717 | const char *fmt = parg->type->fmttype; |
718 | int size = parg->type->size; | |
719 | ||
720 | if (parg->fmt) | |
721 | fmt = parg->fmt; | |
722 | if (parg->count) | |
723 | size *= parg->count; | |
724 | ret = trace_define_field(event_call, fmt, parg->name, | |
725 | offset + parg->offset, size, | |
eeb07b06 MH |
726 | parg->type->is_signed, |
727 | FILTER_OTHER); | |
728 | if (ret) | |
729 | return ret; | |
730 | } | |
731 | return 0; | |
732 | } |