]>
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 <[email protected]> | |
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 | ||
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. */ |
8ab83f56 SD |
303 | case '-': |
304 | tmp = strchr(arg, '('); | |
305 | if (!tmp) | |
53305928 | 306 | return -EINVAL; |
8ab83f56 SD |
307 | |
308 | *tmp = '\0'; | |
bcd83ea6 | 309 | ret = kstrtol(arg, 0, &offset); |
8ab83f56 SD |
310 | if (ret) |
311 | break; | |
312 | ||
313 | arg = tmp + 1; | |
314 | tmp = strrchr(arg, ')'); | |
315 | ||
316 | if (tmp) { | |
f451bc89 | 317 | const struct fetch_type *t2 = find_fetch_type(NULL); |
8ab83f56 | 318 | |
8ab83f56 | 319 | *tmp = '\0'; |
a1303af5 | 320 | ret = parse_probe_arg(arg, t2, &code, end, flags); |
8ab83f56 | 321 | if (ret) |
53305928 MH |
322 | break; |
323 | if (code->op == FETCH_OP_COMM) | |
324 | return -EINVAL; | |
325 | if (++code == end) | |
326 | return -E2BIG; | |
327 | *pcode = code; | |
328 | ||
329 | code->op = FETCH_OP_DEREF; | |
330 | code->offset = offset; | |
8ab83f56 SD |
331 | } |
332 | break; | |
333 | } | |
53305928 MH |
334 | if (!ret && code->op == FETCH_OP_NOP) { |
335 | /* Parsed, but do not find fetch method */ | |
8ab83f56 SD |
336 | ret = -EINVAL; |
337 | } | |
8ab83f56 SD |
338 | return ret; |
339 | } | |
340 | ||
341 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | |
342 | ||
343 | /* Bitfield type needs to be parsed into a fetch function */ | |
344 | static int __parse_bitfield_probe_arg(const char *bf, | |
345 | const struct fetch_type *t, | |
53305928 | 346 | struct fetch_insn **pcode) |
8ab83f56 | 347 | { |
53305928 | 348 | struct fetch_insn *code = *pcode; |
8ab83f56 SD |
349 | unsigned long bw, bo; |
350 | char *tail; | |
351 | ||
352 | if (*bf != 'b') | |
353 | return 0; | |
354 | ||
8ab83f56 SD |
355 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
356 | ||
357 | if (bw == 0 || *tail != '@') | |
358 | return -EINVAL; | |
359 | ||
360 | bf = tail + 1; | |
361 | bo = simple_strtoul(bf, &tail, 0); | |
362 | ||
363 | if (tail == bf || *tail != '/') | |
364 | return -EINVAL; | |
53305928 MH |
365 | code++; |
366 | if (code->op != FETCH_OP_NOP) | |
367 | return -E2BIG; | |
368 | *pcode = code; | |
8ab83f56 | 369 | |
53305928 MH |
370 | code->op = FETCH_OP_MOD_BF; |
371 | code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); | |
372 | code->rshift = BYTES_TO_BITS(t->size) - bw; | |
373 | code->basesize = t->size; | |
8ab83f56 SD |
374 | |
375 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | |
376 | } | |
377 | ||
378 | /* String length checking wrapper */ | |
d00bbea9 | 379 | static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
a1303af5 | 380 | struct probe_arg *parg, unsigned int flags) |
8ab83f56 | 381 | { |
40b53b77 MH |
382 | struct fetch_insn *code, *scode, *tmp = NULL; |
383 | char *t, *t2; | |
384 | int ret, len; | |
8ab83f56 SD |
385 | |
386 | if (strlen(arg) > MAX_ARGSTR_LEN) { | |
387 | pr_info("Argument is too long.: %s\n", arg); | |
388 | return -ENOSPC; | |
389 | } | |
390 | parg->comm = kstrdup(arg, GFP_KERNEL); | |
391 | if (!parg->comm) { | |
392 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | |
393 | return -ENOMEM; | |
394 | } | |
40b53b77 | 395 | t = strchr(arg, ':'); |
8ab83f56 | 396 | if (t) { |
40b53b77 MH |
397 | *t = '\0'; |
398 | t2 = strchr(++t, '['); | |
399 | if (t2) { | |
400 | *t2 = '\0'; | |
401 | parg->count = simple_strtoul(t2 + 1, &t2, 0); | |
402 | if (strcmp(t2, "]") || parg->count == 0) | |
403 | return -EINVAL; | |
404 | if (parg->count > MAX_ARRAY_LEN) | |
405 | return -E2BIG; | |
406 | } | |
8ab83f56 | 407 | } |
35abb67d OS |
408 | /* |
409 | * The default type of $comm should be "string", and it can't be | |
410 | * dereferenced. | |
411 | */ | |
412 | if (!t && strcmp(arg, "$comm") == 0) | |
40b53b77 MH |
413 | parg->type = find_fetch_type("string"); |
414 | else | |
415 | parg->type = find_fetch_type(t); | |
8ab83f56 SD |
416 | if (!parg->type) { |
417 | pr_info("Unsupported type: %s\n", t); | |
418 | return -EINVAL; | |
419 | } | |
420 | parg->offset = *size; | |
40b53b77 MH |
421 | *size += parg->type->size * (parg->count ?: 1); |
422 | ||
423 | if (parg->count) { | |
424 | len = strlen(parg->type->fmttype) + 6; | |
425 | parg->fmt = kmalloc(len, GFP_KERNEL); | |
426 | if (!parg->fmt) | |
427 | return -ENOMEM; | |
428 | snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, | |
429 | parg->count); | |
430 | } | |
8ab83f56 | 431 | |
53305928 MH |
432 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); |
433 | if (!code) | |
434 | return -ENOMEM; | |
435 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; | |
436 | ||
437 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | |
a1303af5 | 438 | flags); |
53305928 MH |
439 | if (ret) |
440 | goto fail; | |
441 | ||
442 | /* Store operation */ | |
443 | if (!strcmp(parg->type->name, "string")) { | |
444 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | |
445 | code->op != FETCH_OP_COMM) { | |
446 | pr_info("string only accepts memory or address.\n"); | |
447 | ret = -EINVAL; | |
448 | goto fail; | |
449 | } | |
40b53b77 MH |
450 | if (code->op != FETCH_OP_DEREF || parg->count) { |
451 | /* | |
452 | * IMM and COMM is pointing actual address, those must | |
453 | * be kept, and if parg->count != 0, this is an array | |
454 | * of string pointers instead of string address itself. | |
455 | */ | |
53305928 | 456 | code++; |
40b53b77 MH |
457 | if (code->op != FETCH_OP_NOP) { |
458 | ret = -E2BIG; | |
459 | goto fail; | |
460 | } | |
461 | } | |
53305928 | 462 | code->op = FETCH_OP_ST_STRING; /* In DEREF case, replace it */ |
40b53b77 | 463 | code->size = parg->type->size; |
53305928 MH |
464 | parg->dynamic = true; |
465 | } else if (code->op == FETCH_OP_DEREF) { | |
466 | code->op = FETCH_OP_ST_MEM; | |
467 | code->size = parg->type->size; | |
468 | } else { | |
469 | code++; | |
470 | if (code->op != FETCH_OP_NOP) { | |
471 | ret = -E2BIG; | |
472 | goto fail; | |
473 | } | |
474 | code->op = FETCH_OP_ST_RAW; | |
475 | code->size = parg->type->size; | |
476 | } | |
40b53b77 | 477 | scode = code; |
53305928 MH |
478 | /* Modify operation */ |
479 | if (t != NULL) { | |
480 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | |
481 | if (ret) | |
482 | goto fail; | |
8ab83f56 | 483 | } |
40b53b77 MH |
484 | /* Loop(Array) operation */ |
485 | if (parg->count) { | |
486 | if (scode->op != FETCH_OP_ST_MEM && | |
487 | scode->op != FETCH_OP_ST_STRING) { | |
488 | pr_info("array only accepts memory or address\n"); | |
489 | ret = -EINVAL; | |
490 | goto fail; | |
491 | } | |
492 | code++; | |
493 | if (code->op != FETCH_OP_NOP) { | |
494 | ret = -E2BIG; | |
495 | goto fail; | |
496 | } | |
497 | code->op = FETCH_OP_LP_ARRAY; | |
498 | code->param = parg->count; | |
499 | } | |
53305928 MH |
500 | code++; |
501 | code->op = FETCH_OP_END; | |
502 | ||
503 | /* Shrink down the code buffer */ | |
504 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | |
505 | if (!parg->code) | |
506 | ret = -ENOMEM; | |
507 | else | |
508 | memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); | |
509 | ||
510 | fail: | |
a6682814 MH |
511 | if (ret) { |
512 | for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) | |
513 | if (code->op == FETCH_NOP_SYMBOL) | |
514 | kfree(code->data); | |
515 | } | |
53305928 | 516 | kfree(tmp); |
8ab83f56 SD |
517 | |
518 | return ret; | |
519 | } | |
520 | ||
521 | /* Return 1 if name is reserved or already used by another argument */ | |
d00bbea9 MH |
522 | static int traceprobe_conflict_field_name(const char *name, |
523 | struct probe_arg *args, int narg) | |
8ab83f56 SD |
524 | { |
525 | int i; | |
526 | ||
527 | for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) | |
528 | if (strcmp(reserved_field_names[i], name) == 0) | |
529 | return 1; | |
530 | ||
531 | for (i = 0; i < narg; i++) | |
532 | if (strcmp(args[i].name, name) == 0) | |
533 | return 1; | |
534 | ||
535 | return 0; | |
536 | } | |
537 | ||
d00bbea9 MH |
538 | int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, |
539 | unsigned int flags) | |
540 | { | |
541 | struct probe_arg *parg = &tp->args[i]; | |
542 | char *body; | |
543 | int ret; | |
544 | ||
545 | /* Increment count for freeing args in error case */ | |
546 | tp->nr_args++; | |
547 | ||
548 | body = strchr(arg, '='); | |
549 | if (body) { | |
550 | parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); | |
551 | body++; | |
552 | } else { | |
553 | /* If argument name is omitted, set "argN" */ | |
554 | parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1); | |
555 | body = arg; | |
556 | } | |
557 | if (!parg->name) | |
558 | return -ENOMEM; | |
559 | ||
560 | if (!is_good_name(parg->name)) { | |
561 | pr_info("Invalid argument[%d] name: %s\n", | |
562 | i, parg->name); | |
563 | return -EINVAL; | |
564 | } | |
565 | ||
566 | if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { | |
567 | pr_info("Argument[%d]: '%s' conflicts with another field.\n", | |
568 | i, parg->name); | |
569 | return -EINVAL; | |
570 | } | |
571 | ||
572 | /* Parse fetch argument */ | |
573 | ret = traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags); | |
574 | if (ret) | |
575 | pr_info("Parse error at argument[%d]. (%d)\n", i, ret); | |
576 | return ret; | |
577 | } | |
578 | ||
8ab83f56 SD |
579 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
580 | { | |
a6682814 MH |
581 | struct fetch_insn *code = arg->code; |
582 | ||
583 | while (code && code->op != FETCH_OP_END) { | |
584 | if (code->op == FETCH_NOP_SYMBOL) | |
585 | kfree(code->data); | |
586 | code++; | |
587 | } | |
53305928 | 588 | kfree(arg->code); |
8ab83f56 SD |
589 | kfree(arg->name); |
590 | kfree(arg->comm); | |
40b53b77 | 591 | kfree(arg->fmt); |
8ab83f56 SD |
592 | } |
593 | ||
a6682814 MH |
594 | int traceprobe_update_arg(struct probe_arg *arg) |
595 | { | |
596 | struct fetch_insn *code = arg->code; | |
597 | long offset; | |
598 | char *tmp; | |
599 | char c; | |
600 | int ret = 0; | |
601 | ||
602 | while (code && code->op != FETCH_OP_END) { | |
603 | if (code->op == FETCH_NOP_SYMBOL) { | |
604 | if (code[1].op != FETCH_OP_IMM) | |
605 | return -EINVAL; | |
606 | ||
ee474b81 | 607 | tmp = strpbrk(code->data, "+-"); |
a6682814 MH |
608 | if (tmp) |
609 | c = *tmp; | |
610 | ret = traceprobe_split_symbol_offset(code->data, | |
611 | &offset); | |
612 | if (ret) | |
613 | return ret; | |
614 | ||
615 | code[1].immediate = | |
616 | (unsigned long)kallsyms_lookup_name(code->data); | |
617 | if (tmp) | |
618 | *tmp = c; | |
619 | if (!code[1].immediate) | |
620 | return -ENOENT; | |
621 | code[1].immediate += offset; | |
622 | } | |
623 | code++; | |
624 | } | |
625 | return 0; | |
626 | } | |
627 | ||
40b53b77 MH |
628 | /* When len=0, we just calculate the needed length */ |
629 | #define LEN_OR_ZERO (len ? len - pos : 0) | |
5bf652aa NK |
630 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
631 | bool is_return) | |
632 | { | |
40b53b77 MH |
633 | struct probe_arg *parg; |
634 | int i, j; | |
5bf652aa | 635 | int pos = 0; |
5bf652aa NK |
636 | const char *fmt, *arg; |
637 | ||
638 | if (!is_return) { | |
639 | fmt = "(%lx)"; | |
640 | arg = "REC->" FIELD_STRING_IP; | |
641 | } else { | |
642 | fmt = "(%lx <- %lx)"; | |
643 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | |
644 | } | |
645 | ||
5bf652aa NK |
646 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); |
647 | ||
648 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
649 | parg = tp->args + i; |
650 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); | |
651 | if (parg->count) { | |
652 | pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", | |
653 | parg->type->fmt); | |
654 | for (j = 1; j < parg->count; j++) | |
655 | pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", | |
656 | parg->type->fmt); | |
657 | pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); | |
658 | } else | |
659 | pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", | |
660 | parg->type->fmt); | |
5bf652aa NK |
661 | } |
662 | ||
663 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | |
664 | ||
665 | for (i = 0; i < tp->nr_args; i++) { | |
40b53b77 MH |
666 | parg = tp->args + i; |
667 | if (parg->count) { | |
668 | if (strcmp(parg->type->name, "string") == 0) | |
669 | fmt = ", __get_str(%s[%d])"; | |
670 | else | |
671 | fmt = ", REC->%s[%d]"; | |
672 | for (j = 0; j < parg->count; j++) | |
673 | pos += snprintf(buf + pos, LEN_OR_ZERO, | |
674 | fmt, parg->name, j); | |
675 | } else { | |
676 | if (strcmp(parg->type->name, "string") == 0) | |
677 | fmt = ", __get_str(%s)"; | |
678 | else | |
679 | fmt = ", REC->%s"; | |
5bf652aa | 680 | pos += snprintf(buf + pos, LEN_OR_ZERO, |
40b53b77 MH |
681 | fmt, parg->name); |
682 | } | |
5bf652aa NK |
683 | } |
684 | ||
5bf652aa NK |
685 | /* return the length of print_fmt */ |
686 | return pos; | |
687 | } | |
40b53b77 | 688 | #undef LEN_OR_ZERO |
5bf652aa | 689 | |
0a46c854 | 690 | int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
5bf652aa NK |
691 | { |
692 | int len; | |
693 | char *print_fmt; | |
694 | ||
695 | /* First: called with 0 length to calculate the needed length */ | |
696 | len = __set_print_fmt(tp, NULL, 0, is_return); | |
697 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | |
698 | if (!print_fmt) | |
699 | return -ENOMEM; | |
700 | ||
701 | /* Second: actually write the @print_fmt */ | |
702 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | |
703 | tp->call.print_fmt = print_fmt; | |
704 | ||
705 | return 0; | |
706 | } | |
eeb07b06 MH |
707 | |
708 | int traceprobe_define_arg_fields(struct trace_event_call *event_call, | |
709 | size_t offset, struct trace_probe *tp) | |
710 | { | |
711 | int ret, i; | |
712 | ||
713 | /* Set argument names as fields */ | |
714 | for (i = 0; i < tp->nr_args; i++) { | |
715 | struct probe_arg *parg = &tp->args[i]; | |
40b53b77 MH |
716 | const char *fmt = parg->type->fmttype; |
717 | int size = parg->type->size; | |
718 | ||
719 | if (parg->fmt) | |
720 | fmt = parg->fmt; | |
721 | if (parg->count) | |
722 | size *= parg->count; | |
723 | ret = trace_define_field(event_call, fmt, parg->name, | |
724 | offset + parg->offset, size, | |
eeb07b06 MH |
725 | parg->type->is_signed, |
726 | FILTER_OTHER); | |
727 | if (ret) | |
728 | return ret; | |
729 | } | |
730 | return 0; | |
731 | } |