]>
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, | |
53305928 | 160 | struct fetch_insn *code, bool is_return, |
b079d374 | 161 | bool is_kprobe) |
8ab83f56 SD |
162 | { |
163 | int ret = 0; | |
164 | unsigned long param; | |
165 | ||
166 | if (strcmp(arg, "retval") == 0) { | |
167 | if (is_return) | |
53305928 | 168 | code->op = FETCH_OP_RETVAL; |
8ab83f56 SD |
169 | else |
170 | ret = -EINVAL; | |
171 | } else if (strncmp(arg, "stack", 5) == 0) { | |
172 | if (arg[5] == '\0') { | |
53305928 | 173 | code->op = FETCH_OP_STACKP; |
8ab83f56 | 174 | } else if (isdigit(arg[5])) { |
bcd83ea6 | 175 | ret = kstrtoul(arg + 5, 10, ¶m); |
b079d374 | 176 | if (ret || (is_kprobe && 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; |
8ab83f56 SD |
186 | } else |
187 | ret = -EINVAL; | |
188 | ||
189 | return ret; | |
190 | } | |
191 | ||
192 | /* Recursive argument parser */ | |
53305928 MH |
193 | static int |
194 | parse_probe_arg(char *arg, const struct fetch_type *type, | |
195 | struct fetch_insn **pcode, struct fetch_insn *end, | |
f451bc89 | 196 | bool is_return, bool is_kprobe) |
8ab83f56 | 197 | { |
53305928 | 198 | struct fetch_insn *code = *pcode; |
8ab83f56 SD |
199 | unsigned long param; |
200 | long offset; | |
201 | char *tmp; | |
34fee3a1 | 202 | int ret = 0; |
8ab83f56 | 203 | |
8ab83f56 SD |
204 | switch (arg[0]) { |
205 | case '$': | |
53305928 MH |
206 | ret = parse_probe_vars(arg + 1, type, code, |
207 | is_return, is_kprobe); | |
8ab83f56 SD |
208 | break; |
209 | ||
210 | case '%': /* named register */ | |
211 | ret = regs_query_register_offset(arg + 1); | |
212 | if (ret >= 0) { | |
53305928 MH |
213 | code->op = FETCH_OP_REG; |
214 | code->param = (unsigned int)ret; | |
8ab83f56 SD |
215 | ret = 0; |
216 | } | |
217 | break; | |
218 | ||
b7e0bf34 | 219 | case '@': /* memory, file-offset or symbol */ |
8ab83f56 | 220 | if (isdigit(arg[1])) { |
bcd83ea6 | 221 | ret = kstrtoul(arg + 1, 0, ¶m); |
8ab83f56 SD |
222 | if (ret) |
223 | break; | |
53305928 MH |
224 | /* load address */ |
225 | code->op = FETCH_OP_IMM; | |
226 | code->immediate = param; | |
b7e0bf34 NK |
227 | } else if (arg[1] == '+') { |
228 | /* kprobes don't support file offsets */ | |
229 | if (is_kprobe) | |
230 | return -EINVAL; | |
231 | ||
232 | ret = kstrtol(arg + 2, 0, &offset); | |
233 | if (ret) | |
234 | break; | |
235 | ||
53305928 MH |
236 | code->op = FETCH_OP_FOFFS; |
237 | code->immediate = (unsigned long)offset; // imm64? | |
8ab83f56 | 238 | } else { |
b079d374 NK |
239 | /* uprobes don't support symbols */ |
240 | if (!is_kprobe) | |
241 | return -EINVAL; | |
242 | ||
8ab83f56 SD |
243 | ret = traceprobe_split_symbol_offset(arg + 1, &offset); |
244 | if (ret) | |
245 | break; | |
246 | ||
53305928 MH |
247 | code->op = FETCH_OP_IMM; |
248 | code->immediate = | |
249 | (unsigned long)kallsyms_lookup_name(arg + 1); | |
250 | if (!code->immediate) | |
251 | return -ENOENT; | |
252 | code->immediate += offset; | |
8ab83f56 | 253 | } |
53305928 MH |
254 | /* These are fetching from memory */ |
255 | if (++code == end) | |
256 | return -E2BIG; | |
257 | *pcode = code; | |
258 | code->op = FETCH_OP_DEREF; | |
259 | code->offset = offset; | |
8ab83f56 SD |
260 | break; |
261 | ||
262 | case '+': /* deref memory */ | |
bcd83ea6 | 263 | arg++; /* Skip '+', because kstrtol() rejects it. */ |
8ab83f56 SD |
264 | case '-': |
265 | tmp = strchr(arg, '('); | |
266 | if (!tmp) | |
53305928 | 267 | return -EINVAL; |
8ab83f56 SD |
268 | |
269 | *tmp = '\0'; | |
bcd83ea6 | 270 | ret = kstrtol(arg, 0, &offset); |
8ab83f56 SD |
271 | if (ret) |
272 | break; | |
273 | ||
274 | arg = tmp + 1; | |
275 | tmp = strrchr(arg, ')'); | |
276 | ||
277 | if (tmp) { | |
f451bc89 | 278 | const struct fetch_type *t2 = find_fetch_type(NULL); |
8ab83f56 | 279 | |
8ab83f56 | 280 | *tmp = '\0'; |
53305928 | 281 | ret = parse_probe_arg(arg, t2, &code, end, is_return, |
f451bc89 | 282 | is_kprobe); |
8ab83f56 | 283 | if (ret) |
53305928 MH |
284 | break; |
285 | if (code->op == FETCH_OP_COMM) | |
286 | return -EINVAL; | |
287 | if (++code == end) | |
288 | return -E2BIG; | |
289 | *pcode = code; | |
290 | ||
291 | code->op = FETCH_OP_DEREF; | |
292 | code->offset = offset; | |
8ab83f56 SD |
293 | } |
294 | break; | |
295 | } | |
53305928 MH |
296 | if (!ret && code->op == FETCH_OP_NOP) { |
297 | /* Parsed, but do not find fetch method */ | |
8ab83f56 SD |
298 | ret = -EINVAL; |
299 | } | |
8ab83f56 SD |
300 | return ret; |
301 | } | |
302 | ||
303 | #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) | |
304 | ||
305 | /* Bitfield type needs to be parsed into a fetch function */ | |
306 | static int __parse_bitfield_probe_arg(const char *bf, | |
307 | const struct fetch_type *t, | |
53305928 | 308 | struct fetch_insn **pcode) |
8ab83f56 | 309 | { |
53305928 | 310 | struct fetch_insn *code = *pcode; |
8ab83f56 SD |
311 | unsigned long bw, bo; |
312 | char *tail; | |
313 | ||
314 | if (*bf != 'b') | |
315 | return 0; | |
316 | ||
8ab83f56 SD |
317 | bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ |
318 | ||
319 | if (bw == 0 || *tail != '@') | |
320 | return -EINVAL; | |
321 | ||
322 | bf = tail + 1; | |
323 | bo = simple_strtoul(bf, &tail, 0); | |
324 | ||
325 | if (tail == bf || *tail != '/') | |
326 | return -EINVAL; | |
53305928 MH |
327 | code++; |
328 | if (code->op != FETCH_OP_NOP) | |
329 | return -E2BIG; | |
330 | *pcode = code; | |
8ab83f56 | 331 | |
53305928 MH |
332 | code->op = FETCH_OP_MOD_BF; |
333 | code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); | |
334 | code->rshift = BYTES_TO_BITS(t->size) - bw; | |
335 | code->basesize = t->size; | |
8ab83f56 SD |
336 | |
337 | return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; | |
338 | } | |
339 | ||
340 | /* String length checking wrapper */ | |
341 | int traceprobe_parse_probe_arg(char *arg, ssize_t *size, | |
f451bc89 | 342 | struct probe_arg *parg, bool is_return, bool is_kprobe) |
8ab83f56 | 343 | { |
53305928 | 344 | struct fetch_insn *code, *tmp = NULL; |
8ab83f56 SD |
345 | const char *t; |
346 | int ret; | |
347 | ||
348 | if (strlen(arg) > MAX_ARGSTR_LEN) { | |
349 | pr_info("Argument is too long.: %s\n", arg); | |
350 | return -ENOSPC; | |
351 | } | |
352 | parg->comm = kstrdup(arg, GFP_KERNEL); | |
353 | if (!parg->comm) { | |
354 | pr_info("Failed to allocate memory for command '%s'.\n", arg); | |
355 | return -ENOMEM; | |
356 | } | |
357 | t = strchr(parg->comm, ':'); | |
358 | if (t) { | |
359 | arg[t - parg->comm] = '\0'; | |
360 | t++; | |
361 | } | |
35abb67d OS |
362 | /* |
363 | * The default type of $comm should be "string", and it can't be | |
364 | * dereferenced. | |
365 | */ | |
366 | if (!t && strcmp(arg, "$comm") == 0) | |
367 | t = "string"; | |
f451bc89 | 368 | parg->type = find_fetch_type(t); |
8ab83f56 SD |
369 | if (!parg->type) { |
370 | pr_info("Unsupported type: %s\n", t); | |
371 | return -EINVAL; | |
372 | } | |
373 | parg->offset = *size; | |
374 | *size += parg->type->size; | |
8ab83f56 | 375 | |
53305928 MH |
376 | code = tmp = kzalloc(sizeof(*code) * FETCH_INSN_MAX, GFP_KERNEL); |
377 | if (!code) | |
378 | return -ENOMEM; | |
379 | code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; | |
380 | ||
381 | ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], | |
f451bc89 | 382 | is_return, is_kprobe); |
53305928 MH |
383 | if (ret) |
384 | goto fail; | |
385 | ||
386 | /* Store operation */ | |
387 | if (!strcmp(parg->type->name, "string")) { | |
388 | if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_IMM && | |
389 | code->op != FETCH_OP_COMM) { | |
390 | pr_info("string only accepts memory or address.\n"); | |
391 | ret = -EINVAL; | |
392 | goto fail; | |
393 | } | |
394 | /* Since IMM or COMM must be the 1st insn, this is safe */ | |
395 | if (code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM) | |
396 | code++; | |
397 | code->op = FETCH_OP_ST_STRING; /* In DEREF case, replace it */ | |
398 | parg->dynamic = true; | |
399 | } else if (code->op == FETCH_OP_DEREF) { | |
400 | code->op = FETCH_OP_ST_MEM; | |
401 | code->size = parg->type->size; | |
402 | } else { | |
403 | code++; | |
404 | if (code->op != FETCH_OP_NOP) { | |
405 | ret = -E2BIG; | |
406 | goto fail; | |
407 | } | |
408 | code->op = FETCH_OP_ST_RAW; | |
409 | code->size = parg->type->size; | |
410 | } | |
411 | /* Modify operation */ | |
412 | if (t != NULL) { | |
413 | ret = __parse_bitfield_probe_arg(t, parg->type, &code); | |
414 | if (ret) | |
415 | goto fail; | |
8ab83f56 | 416 | } |
53305928 MH |
417 | code++; |
418 | code->op = FETCH_OP_END; | |
419 | ||
420 | /* Shrink down the code buffer */ | |
421 | parg->code = kzalloc(sizeof(*code) * (code - tmp + 1), GFP_KERNEL); | |
422 | if (!parg->code) | |
423 | ret = -ENOMEM; | |
424 | else | |
425 | memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); | |
426 | ||
427 | fail: | |
428 | kfree(tmp); | |
8ab83f56 SD |
429 | |
430 | return ret; | |
431 | } | |
432 | ||
433 | /* Return 1 if name is reserved or already used by another argument */ | |
434 | int traceprobe_conflict_field_name(const char *name, | |
435 | struct probe_arg *args, int narg) | |
436 | { | |
437 | int i; | |
438 | ||
439 | for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) | |
440 | if (strcmp(reserved_field_names[i], name) == 0) | |
441 | return 1; | |
442 | ||
443 | for (i = 0; i < narg; i++) | |
444 | if (strcmp(args[i].name, name) == 0) | |
445 | return 1; | |
446 | ||
447 | return 0; | |
448 | } | |
449 | ||
8ab83f56 SD |
450 | void traceprobe_free_probe_arg(struct probe_arg *arg) |
451 | { | |
53305928 | 452 | kfree(arg->code); |
8ab83f56 SD |
453 | kfree(arg->name); |
454 | kfree(arg->comm); | |
455 | } | |
456 | ||
5bf652aa NK |
457 | static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, |
458 | bool is_return) | |
459 | { | |
460 | int i; | |
461 | int pos = 0; | |
462 | ||
463 | const char *fmt, *arg; | |
464 | ||
465 | if (!is_return) { | |
466 | fmt = "(%lx)"; | |
467 | arg = "REC->" FIELD_STRING_IP; | |
468 | } else { | |
469 | fmt = "(%lx <- %lx)"; | |
470 | arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; | |
471 | } | |
472 | ||
473 | /* When len=0, we just calculate the needed length */ | |
474 | #define LEN_OR_ZERO (len ? len - pos : 0) | |
475 | ||
476 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); | |
477 | ||
478 | for (i = 0; i < tp->nr_args; i++) { | |
479 | pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=%s", | |
480 | tp->args[i].name, tp->args[i].type->fmt); | |
481 | } | |
482 | ||
483 | pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); | |
484 | ||
485 | for (i = 0; i < tp->nr_args; i++) { | |
486 | if (strcmp(tp->args[i].type->name, "string") == 0) | |
487 | pos += snprintf(buf + pos, LEN_OR_ZERO, | |
488 | ", __get_str(%s)", | |
489 | tp->args[i].name); | |
490 | else | |
491 | pos += snprintf(buf + pos, LEN_OR_ZERO, ", REC->%s", | |
492 | tp->args[i].name); | |
493 | } | |
494 | ||
495 | #undef LEN_OR_ZERO | |
496 | ||
497 | /* return the length of print_fmt */ | |
498 | return pos; | |
499 | } | |
500 | ||
0a46c854 | 501 | int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
5bf652aa NK |
502 | { |
503 | int len; | |
504 | char *print_fmt; | |
505 | ||
506 | /* First: called with 0 length to calculate the needed length */ | |
507 | len = __set_print_fmt(tp, NULL, 0, is_return); | |
508 | print_fmt = kmalloc(len + 1, GFP_KERNEL); | |
509 | if (!print_fmt) | |
510 | return -ENOMEM; | |
511 | ||
512 | /* Second: actually write the @print_fmt */ | |
513 | __set_print_fmt(tp, print_fmt, len + 1, is_return); | |
514 | tp->call.print_fmt = print_fmt; | |
515 | ||
516 | return 0; | |
517 | } | |
eeb07b06 MH |
518 | |
519 | int traceprobe_define_arg_fields(struct trace_event_call *event_call, | |
520 | size_t offset, struct trace_probe *tp) | |
521 | { | |
522 | int ret, i; | |
523 | ||
524 | /* Set argument names as fields */ | |
525 | for (i = 0; i < tp->nr_args; i++) { | |
526 | struct probe_arg *parg = &tp->args[i]; | |
527 | ||
528 | ret = trace_define_field(event_call, parg->type->fmttype, | |
529 | parg->name, | |
530 | offset + parg->offset, | |
531 | parg->type->size, | |
532 | parg->type->is_signed, | |
533 | FILTER_OTHER); | |
534 | if (ret) | |
535 | return ret; | |
536 | } | |
537 | return 0; | |
538 | } |