Blame view
kernel/trace/trace_probe.c
26.4 KB
bcea3f96e tracing: Add SPDX... |
1 |
// SPDX-License-Identifier: GPL-2.0 |
8ab83f564 tracing: Extract ... |
2 3 4 |
/* * Common code for probe-based Dynamic events. * |
8ab83f564 tracing: Extract ... |
5 6 7 8 9 10 11 |
* This code was copied from kernel/trace/trace_kprobe.c written by * Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> * * Updates to make this generic: * Copyright (C) IBM Corporation, 2010-2011 * Author: Srikar Dronamraju */ |
725763413 tracing/probe: Sh... |
12 |
#define pr_fmt(fmt) "trace_probe: " fmt |
8ab83f564 tracing: Extract ... |
13 14 |
#include "trace_probe.h" |
ab105a4fb tracing: Use trac... |
15 16 17 18 |
#undef C #define C(a, b) b static const char *trace_probe_err_text[] = { ERRORS }; |
084162520 tracing/probes: M... |
19 |
static const char *reserved_field_names[] = { |
8ab83f564 tracing: Extract ... |
20 21 22 23 24 25 26 27 28 |
"common_type", "common_flags", "common_preempt_count", "common_pid", "common_tgid", FIELD_STRING_IP, FIELD_STRING_RETIP, FIELD_STRING_FUNC, }; |
8ab83f564 tracing: Extract ... |
29 |
/* Printing in basic type function template */ |
17ce3dc7e ftrace: kprobe: u... |
30 |
#define DEFINE_BASIC_PRINT_TYPE_FUNC(tname, type, fmt) \ |
56de76305 tracing: probeeve... |
31 |
int PRINT_TYPE_FUNC_NAME(tname)(struct trace_seq *s, void *data, void *ent)\ |
8ab83f564 tracing: Extract ... |
32 |
{ \ |
56de76305 tracing: probeeve... |
33 |
trace_seq_printf(s, fmt, *(type *)data); \ |
d2b0191a3 tracing/probes: D... |
34 |
return !trace_seq_has_overflowed(s); \ |
8ab83f564 tracing: Extract ... |
35 |
} \ |
7bfbc63ed tracing: probeeve... |
36 |
const char PRINT_TYPE_FMT_NAME(tname)[] = fmt; |
8ab83f564 tracing: Extract ... |
37 |
|
bdca79c2b ftrace: kprobe: u... |
38 39 40 41 |
DEFINE_BASIC_PRINT_TYPE_FUNC(u8, u8, "%u") DEFINE_BASIC_PRINT_TYPE_FUNC(u16, u16, "%u") DEFINE_BASIC_PRINT_TYPE_FUNC(u32, u32, "%u") DEFINE_BASIC_PRINT_TYPE_FUNC(u64, u64, "%Lu") |
17ce3dc7e ftrace: kprobe: u... |
42 43 44 45 46 47 48 49 |
DEFINE_BASIC_PRINT_TYPE_FUNC(s8, s8, "%d") DEFINE_BASIC_PRINT_TYPE_FUNC(s16, s16, "%d") DEFINE_BASIC_PRINT_TYPE_FUNC(s32, s32, "%d") DEFINE_BASIC_PRINT_TYPE_FUNC(s64, s64, "%Ld") DEFINE_BASIC_PRINT_TYPE_FUNC(x8, u8, "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(x16, u16, "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(x32, u32, "0x%x") DEFINE_BASIC_PRINT_TYPE_FUNC(x64, u64, "0x%Lx") |
8ab83f564 tracing: Extract ... |
50 |
|
60c2e0ceb tracing: probeeve... |
51 52 53 54 55 56 |
int PRINT_TYPE_FUNC_NAME(symbol)(struct trace_seq *s, void *data, void *ent) { trace_seq_printf(s, "%pS", (void *)*(unsigned long *)data); return !trace_seq_has_overflowed(s); } const char PRINT_TYPE_FMT_NAME(symbol)[] = "%pS"; |
8ab83f564 tracing: Extract ... |
57 |
/* Print type function for string type */ |
56de76305 tracing: probeeve... |
58 |
int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, void *data, void *ent) |
8ab83f564 tracing: Extract ... |
59 60 61 62 |
{ int len = *(u32 *)data >> 16; if (!len) |
56de76305 tracing: probeeve... |
63 |
trace_seq_puts(s, "(fault)"); |
8ab83f564 tracing: Extract ... |
64 |
else |
56de76305 tracing: probeeve... |
65 |
trace_seq_printf(s, "\"%s\"", |
d2b0191a3 tracing/probes: D... |
66 67 |
(const char *)get_loc_data(data, ent)); return !trace_seq_has_overflowed(s); |
8ab83f564 tracing: Extract ... |
68 |
} |
b26c74e11 tracing/probes: M... |
69 |
const char PRINT_TYPE_FMT_NAME(string)[] = "\\\"%s\\\""; |
8ab83f564 tracing: Extract ... |
70 |
|
f451bc89d tracing: probeeve... |
71 72 73 74 75 |
/* Fetch type information table */ static const struct fetch_type probe_fetch_types[] = { /* Special types */ __ASSIGN_FETCH_TYPE("string", string, string, sizeof(u32), 1, "__data_loc char[]"), |
88903c464 tracing/probe: Ad... |
76 77 |
__ASSIGN_FETCH_TYPE("ustring", string, string, sizeof(u32), 1, "__data_loc char[]"), |
f451bc89d tracing: probeeve... |
78 79 80 81 82 83 84 85 86 87 88 89 90 |
/* Basic types */ ASSIGN_FETCH_TYPE(u8, u8, 0), ASSIGN_FETCH_TYPE(u16, u16, 0), ASSIGN_FETCH_TYPE(u32, u32, 0), ASSIGN_FETCH_TYPE(u64, u64, 0), ASSIGN_FETCH_TYPE(s8, u8, 1), ASSIGN_FETCH_TYPE(s16, u16, 1), ASSIGN_FETCH_TYPE(s32, u32, 1), ASSIGN_FETCH_TYPE(s64, u64, 1), ASSIGN_FETCH_TYPE_ALIAS(x8, u8, u8, 0), ASSIGN_FETCH_TYPE_ALIAS(x16, u16, u16, 0), ASSIGN_FETCH_TYPE_ALIAS(x32, u32, u32, 0), ASSIGN_FETCH_TYPE_ALIAS(x64, u64, u64, 0), |
60c2e0ceb tracing: probeeve... |
91 |
ASSIGN_FETCH_TYPE_ALIAS(symbol, ADDR_FETCH_TYPE, ADDR_FETCH_TYPE, 0), |
f451bc89d tracing: probeeve... |
92 93 94 95 96 |
ASSIGN_FETCH_TYPE_END }; static const struct fetch_type *find_fetch_type(const char *type) |
8ab83f564 tracing: Extract ... |
97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
{ int i; if (!type) type = DEFAULT_FETCH_TYPE_STR; /* Special case: bitfield */ if (*type == 'b') { unsigned long bs; type = strchr(type, '/'); if (!type) goto fail; type++; |
bcd83ea6c tracing: Replace ... |
112 |
if (kstrtoul(type, 0, &bs)) |
8ab83f564 tracing: Extract ... |
113 114 115 116 |
goto fail; switch (bs) { case 8: |
f451bc89d tracing: probeeve... |
117 |
return find_fetch_type("u8"); |
8ab83f564 tracing: Extract ... |
118 |
case 16: |
f451bc89d tracing: probeeve... |
119 |
return find_fetch_type("u16"); |
8ab83f564 tracing: Extract ... |
120 |
case 32: |
f451bc89d tracing: probeeve... |
121 |
return find_fetch_type("u32"); |
8ab83f564 tracing: Extract ... |
122 |
case 64: |
f451bc89d tracing: probeeve... |
123 |
return find_fetch_type("u64"); |
8ab83f564 tracing: Extract ... |
124 125 126 127 |
default: goto fail; } } |
f451bc89d tracing: probeeve... |
128 129 130 |
for (i = 0; probe_fetch_types[i].name; i++) { if (strcmp(type, probe_fetch_types[i].name) == 0) return &probe_fetch_types[i]; |
34fee3a10 tracing/probes: S... |
131 |
} |
8ab83f564 tracing: Extract ... |
132 133 134 135 |
fail: return NULL; } |
ab105a4fb tracing: Use trac... |
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 |
static struct trace_probe_log trace_probe_log; void trace_probe_log_init(const char *subsystem, int argc, const char **argv) { trace_probe_log.subsystem = subsystem; trace_probe_log.argc = argc; trace_probe_log.argv = argv; trace_probe_log.index = 0; } void trace_probe_log_clear(void) { memset(&trace_probe_log, 0, sizeof(trace_probe_log)); } void trace_probe_log_set_index(int index) { trace_probe_log.index = index; } void __trace_probe_log_err(int offset, int err_type) { char *command, *p; int i, len = 0, pos = 0; if (!trace_probe_log.argv) return; /* Recalcurate the length and allocate buffer */ for (i = 0; i < trace_probe_log.argc; i++) { if (i == trace_probe_log.index) pos = len; len += strlen(trace_probe_log.argv[i]) + 1; } command = kzalloc(len, GFP_KERNEL); if (!command) return; |
d2aea95a1 tracing/probe: Fi... |
173 174 175 176 177 178 179 180 181 |
if (trace_probe_log.index >= trace_probe_log.argc) { /** * Set the error position is next to the last arg + space. * Note that len includes the terminal null and the cursor * appaers at pos + 1. */ pos = len; offset = 0; } |
ab105a4fb tracing: Use trac... |
182 183 184 185 186 187 188 189 190 |
/* And make a command string from argv array */ p = command; for (i = 0; i < trace_probe_log.argc; i++) { len = strlen(trace_probe_log.argv[i]); strcpy(p, trace_probe_log.argv[i]); p[len] = ' '; p += len + 1; } *(p - 1) = '\0'; |
2f754e771 tracing: Have the... |
191 |
tracing_log_err(NULL, trace_probe_log.subsystem, command, |
ab105a4fb tracing: Use trac... |
192 193 194 195 |
trace_probe_err_text, err_type, pos + offset); kfree(command); } |
8ab83f564 tracing: Extract ... |
196 |
/* Split symbol and offset. */ |
c5d343b6b tracing: probeeve... |
197 |
int traceprobe_split_symbol_offset(char *symbol, long *offset) |
8ab83f564 tracing: Extract ... |
198 199 200 201 202 203 |
{ char *tmp; int ret; if (!offset) return -EINVAL; |
c5d343b6b tracing: probeeve... |
204 |
tmp = strpbrk(symbol, "+-"); |
8ab83f564 tracing: Extract ... |
205 |
if (tmp) { |
c5d343b6b tracing: probeeve... |
206 |
ret = kstrtol(tmp, 0, offset); |
8ab83f564 tracing: Extract ... |
207 208 |
if (ret) return ret; |
8ab83f564 tracing: Extract ... |
209 210 211 212 213 214 |
*tmp = '\0'; } else *offset = 0; return 0; } |
6212dd296 tracing/kprobes: ... |
215 216 |
/* @buf must has MAX_EVENT_NAME_LEN size */ int traceprobe_parse_event_name(const char **pevent, const char **pgroup, |
ab105a4fb tracing: Use trac... |
217 |
char *buf, int offset) |
6212dd296 tracing/kprobes: ... |
218 219 |
{ const char *slash, *event = *pevent; |
dec65d79f tracing/probe: Ch... |
220 |
int len; |
6212dd296 tracing/kprobes: ... |
221 222 223 224 |
slash = strchr(event, '/'); if (slash) { if (slash == event) { |
ab105a4fb tracing: Use trac... |
225 |
trace_probe_log_err(offset, NO_GROUP_NAME); |
6212dd296 tracing/kprobes: ... |
226 227 228 |
return -EINVAL; } if (slash - event + 1 > MAX_EVENT_NAME_LEN) { |
ab105a4fb tracing: Use trac... |
229 230 |
trace_probe_log_err(offset, GROUP_TOO_LONG); return -EINVAL; |
6212dd296 tracing/kprobes: ... |
231 232 |
} strlcpy(buf, event, slash - event + 1); |
5b7a96220 tracing/probe: Ch... |
233 |
if (!is_good_name(buf)) { |
ab105a4fb tracing: Use trac... |
234 |
trace_probe_log_err(offset, BAD_GROUP_NAME); |
5b7a96220 tracing/probe: Ch... |
235 236 |
return -EINVAL; } |
6212dd296 tracing/kprobes: ... |
237 238 |
*pgroup = buf; *pevent = slash + 1; |
ab105a4fb tracing: Use trac... |
239 |
offset += slash - event + 1; |
dec65d79f tracing/probe: Ch... |
240 |
event = *pevent; |
6212dd296 tracing/kprobes: ... |
241 |
} |
dec65d79f tracing/probe: Ch... |
242 243 |
len = strlen(event); if (len == 0) { |
ab105a4fb tracing: Use trac... |
244 |
trace_probe_log_err(offset, NO_EVENT_NAME); |
6212dd296 tracing/kprobes: ... |
245 |
return -EINVAL; |
dec65d79f tracing/probe: Ch... |
246 |
} else if (len > MAX_EVENT_NAME_LEN) { |
ab105a4fb tracing: Use trac... |
247 248 |
trace_probe_log_err(offset, EVENT_TOO_LONG); return -EINVAL; |
6212dd296 tracing/kprobes: ... |
249 |
} |
5b7a96220 tracing/probe: Ch... |
250 |
if (!is_good_name(event)) { |
ab105a4fb tracing: Use trac... |
251 |
trace_probe_log_err(offset, BAD_EVENT_NAME); |
5b7a96220 tracing/probe: Ch... |
252 253 |
return -EINVAL; } |
6212dd296 tracing/kprobes: ... |
254 255 |
return 0; } |
8ab83f564 tracing: Extract ... |
256 257 258 |
#define PARAM_MAX_STACK (THREAD_SIZE / sizeof(unsigned long)) static int parse_probe_vars(char *arg, const struct fetch_type *t, |
ab105a4fb tracing: Use trac... |
259 |
struct fetch_insn *code, unsigned int flags, int offs) |
8ab83f564 tracing: Extract ... |
260 |
{ |
8ab83f564 tracing: Extract ... |
261 |
unsigned long param; |
3d739c1f6 tracing: Use the ... |
262 263 |
int ret = 0; int len; |
8ab83f564 tracing: Extract ... |
264 265 |
if (strcmp(arg, "retval") == 0) { |
ab105a4fb tracing: Use trac... |
266 |
if (flags & TPARG_FL_RETURN) { |
533059281 tracing: probeeve... |
267 |
code->op = FETCH_OP_RETVAL; |
ab105a4fb tracing: Use trac... |
268 269 |
} else { trace_probe_log_err(offs, RETVAL_ON_PROBE); |
8ab83f564 tracing: Extract ... |
270 |
ret = -EINVAL; |
ab105a4fb tracing: Use trac... |
271 |
} |
3d739c1f6 tracing: Use the ... |
272 273 |
} else if ((len = str_has_prefix(arg, "stack"))) { if (arg[len] == '\0') { |
533059281 tracing: probeeve... |
274 |
code->op = FETCH_OP_STACKP; |
3d739c1f6 tracing: Use the ... |
275 276 |
} else if (isdigit(arg[len])) { ret = kstrtoul(arg + len, 10, ¶m); |
ab105a4fb tracing: Use trac... |
277 278 279 280 281 |
if (ret) { goto inval_var; } else if ((flags & TPARG_FL_KERNEL) && param > PARAM_MAX_STACK) { trace_probe_log_err(offs, BAD_STACK_NUM); |
8ab83f564 tracing: Extract ... |
282 |
ret = -EINVAL; |
ab105a4fb tracing: Use trac... |
283 |
} else { |
533059281 tracing: probeeve... |
284 285 |
code->op = FETCH_OP_STACK; code->param = (unsigned int)param; |
8ab83f564 tracing: Extract ... |
286 287 |
} } else |
ab105a4fb tracing: Use trac... |
288 |
goto inval_var; |
35abb67de tracing: expose c... |
289 |
} else if (strcmp(arg, "comm") == 0) { |
533059281 tracing: probeeve... |
290 |
code->op = FETCH_OP_COMM; |
a1303af5d tracing: probeeve... |
291 292 293 |
#ifdef CONFIG_HAVE_FUNCTION_ARG_ACCESS_API } else if (((flags & TPARG_FL_MASK) == (TPARG_FL_KERNEL | TPARG_FL_FENTRY)) && |
3d739c1f6 tracing: Use the ... |
294 |
(len = str_has_prefix(arg, "arg"))) { |
3d739c1f6 tracing: Use the ... |
295 |
ret = kstrtoul(arg + len, 10, ¶m); |
ab105a4fb tracing: Use trac... |
296 297 298 299 |
if (ret) { goto inval_var; } else if (!param || param > PARAM_MAX_STACK) { trace_probe_log_err(offs, BAD_ARG_NUM); |
a1303af5d tracing: probeeve... |
300 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
301 |
} |
a1303af5d tracing: probeeve... |
302 303 304 |
code->op = FETCH_OP_ARG; code->param = (unsigned int)param - 1; #endif |
8ab83f564 tracing: Extract ... |
305 |
} else |
ab105a4fb tracing: Use trac... |
306 |
goto inval_var; |
8ab83f564 tracing: Extract ... |
307 308 |
return ret; |
ab105a4fb tracing: Use trac... |
309 310 311 312 |
inval_var: trace_probe_log_err(offs, BAD_VAR); return -EINVAL; |
8ab83f564 tracing: Extract ... |
313 |
} |
6218bf9f4 tracing/probe: Ad... |
314 315 316 317 318 319 320 321 322 323 |
static int str_to_immediate(char *str, unsigned long *imm) { if (isdigit(str[0])) return kstrtoul(str, 0, imm); else if (str[0] == '-') return kstrtol(str, 0, (long *)imm); else if (str[0] == '+') return kstrtol(str + 1, 0, (long *)imm); return -EINVAL; } |
a42e3c4de tracing/probe: Ad... |
324 325 326 327 328 329 330 331 332 333 334 |
static int __parse_imm_string(char *str, char **pbuf, int offs) { size_t len = strlen(str); if (str[len - 1] != '"') { trace_probe_log_err(offs + len, IMMSTR_NO_CLOSE); return -EINVAL; } *pbuf = kstrndup(str, len - 1, GFP_KERNEL); return 0; } |
8ab83f564 tracing: Extract ... |
335 |
/* Recursive argument parser */ |
533059281 tracing: probeeve... |
336 337 338 |
static int parse_probe_arg(char *arg, const struct fetch_type *type, struct fetch_insn **pcode, struct fetch_insn *end, |
ab105a4fb tracing: Use trac... |
339 |
unsigned int flags, int offs) |
8ab83f564 tracing: Extract ... |
340 |
{ |
533059281 tracing: probeeve... |
341 |
struct fetch_insn *code = *pcode; |
8ab83f564 tracing: Extract ... |
342 |
unsigned long param; |
e65f7ae7f tracing/probe: Su... |
343 |
int deref = FETCH_OP_DEREF; |
bf173ca92 tracing: probeeve... |
344 |
long offset = 0; |
8ab83f564 tracing: Extract ... |
345 |
char *tmp; |
34fee3a10 tracing/probes: S... |
346 |
int ret = 0; |
8ab83f564 tracing: Extract ... |
347 |
|
8ab83f564 tracing: Extract ... |
348 349 |
switch (arg[0]) { case '$': |
ab105a4fb tracing: Use trac... |
350 |
ret = parse_probe_vars(arg + 1, type, code, flags, offs); |
8ab83f564 tracing: Extract ... |
351 352 353 354 355 |
break; case '%': /* named register */ ret = regs_query_register_offset(arg + 1); if (ret >= 0) { |
533059281 tracing: probeeve... |
356 357 |
code->op = FETCH_OP_REG; code->param = (unsigned int)ret; |
8ab83f564 tracing: Extract ... |
358 |
ret = 0; |
ab105a4fb tracing: Use trac... |
359 360 |
} else trace_probe_log_err(offs, BAD_REG_NAME); |
8ab83f564 tracing: Extract ... |
361 |
break; |
b7e0bf341 tracing/uprobes: ... |
362 |
case '@': /* memory, file-offset or symbol */ |
8ab83f564 tracing: Extract ... |
363 |
if (isdigit(arg[1])) { |
bcd83ea6c tracing: Replace ... |
364 |
ret = kstrtoul(arg + 1, 0, ¶m); |
ab105a4fb tracing: Use trac... |
365 366 |
if (ret) { trace_probe_log_err(offs, BAD_MEM_ADDR); |
8ab83f564 tracing: Extract ... |
367 |
break; |
ab105a4fb tracing: Use trac... |
368 |
} |
533059281 tracing: probeeve... |
369 370 371 |
/* load address */ code->op = FETCH_OP_IMM; code->immediate = param; |
b7e0bf341 tracing/uprobes: ... |
372 373 |
} else if (arg[1] == '+') { /* kprobes don't support file offsets */ |
ab105a4fb tracing: Use trac... |
374 375 |
if (flags & TPARG_FL_KERNEL) { trace_probe_log_err(offs, FILE_ON_KPROBE); |
b7e0bf341 tracing/uprobes: ... |
376 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
377 |
} |
b7e0bf341 tracing/uprobes: ... |
378 |
ret = kstrtol(arg + 2, 0, &offset); |
ab105a4fb tracing: Use trac... |
379 380 |
if (ret) { trace_probe_log_err(offs, BAD_FILE_OFFS); |
b7e0bf341 tracing/uprobes: ... |
381 |
break; |
ab105a4fb tracing: Use trac... |
382 |
} |
b7e0bf341 tracing/uprobes: ... |
383 |
|
533059281 tracing: probeeve... |
384 385 |
code->op = FETCH_OP_FOFFS; code->immediate = (unsigned long)offset; // imm64? |
8ab83f564 tracing: Extract ... |
386 |
} else { |
b079d374f tracing/uprobes: ... |
387 |
/* uprobes don't support symbols */ |
ab105a4fb tracing: Use trac... |
388 389 |
if (!(flags & TPARG_FL_KERNEL)) { trace_probe_log_err(offs, SYM_ON_UPROBE); |
b079d374f tracing/uprobes: ... |
390 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
391 |
} |
a6682814f tracing/kprobes: ... |
392 393 394 395 396 |
/* Preserve symbol for updating */ code->op = FETCH_NOP_SYMBOL; code->data = kstrdup(arg + 1, GFP_KERNEL); if (!code->data) return -ENOMEM; |
ab105a4fb tracing: Use trac... |
397 398 399 400 |
if (++code == end) { trace_probe_log_err(offs, TOO_MANY_OPS); return -EINVAL; } |
533059281 tracing: probeeve... |
401 |
code->op = FETCH_OP_IMM; |
a6682814f tracing/kprobes: ... |
402 |
code->immediate = 0; |
8ab83f564 tracing: Extract ... |
403 |
} |
533059281 tracing: probeeve... |
404 |
/* These are fetching from memory */ |
ab105a4fb tracing: Use trac... |
405 406 407 408 |
if (++code == end) { trace_probe_log_err(offs, TOO_MANY_OPS); return -EINVAL; } |
533059281 tracing: probeeve... |
409 410 411 |
*pcode = code; code->op = FETCH_OP_DEREF; code->offset = offset; |
8ab83f564 tracing: Extract ... |
412 413 414 |
break; case '+': /* deref memory */ |
8ab83f564 tracing: Extract ... |
415 |
case '-': |
e65f7ae7f tracing/probe: Su... |
416 417 418 419 420 421 422 |
if (arg[1] == 'u') { deref = FETCH_OP_UDEREF; arg[1] = arg[0]; arg++; } if (arg[0] == '+') arg++; /* Skip '+', because kstrtol() rejects it. */ |
8ab83f564 tracing: Extract ... |
423 |
tmp = strchr(arg, '('); |
ab105a4fb tracing: Use trac... |
424 425 |
if (!tmp) { trace_probe_log_err(offs, DEREF_NEED_BRACE); |
533059281 tracing: probeeve... |
426 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
427 |
} |
8ab83f564 tracing: Extract ... |
428 |
*tmp = '\0'; |
bcd83ea6c tracing: Replace ... |
429 |
ret = kstrtol(arg, 0, &offset); |
ab105a4fb tracing: Use trac... |
430 431 |
if (ret) { trace_probe_log_err(offs, BAD_DEREF_OFFS); |
8ab83f564 tracing: Extract ... |
432 |
break; |
ab105a4fb tracing: Use trac... |
433 434 |
} offs += (tmp + 1 - arg) + (arg[0] != '-' ? 1 : 0); |
8ab83f564 tracing: Extract ... |
435 436 |
arg = tmp + 1; tmp = strrchr(arg, ')'); |
ab105a4fb tracing: Use trac... |
437 438 439 440 441 |
if (!tmp) { trace_probe_log_err(offs + strlen(arg), DEREF_OPEN_BRACE); return -EINVAL; } else { |
f451bc89d tracing: probeeve... |
442 |
const struct fetch_type *t2 = find_fetch_type(NULL); |
8ab83f564 tracing: Extract ... |
443 |
|
8ab83f564 tracing: Extract ... |
444 |
*tmp = '\0'; |
ab105a4fb tracing: Use trac... |
445 |
ret = parse_probe_arg(arg, t2, &code, end, flags, offs); |
8ab83f564 tracing: Extract ... |
446 |
if (ret) |
533059281 tracing: probeeve... |
447 |
break; |
a42e3c4de tracing/probe: Ad... |
448 449 |
if (code->op == FETCH_OP_COMM || code->op == FETCH_OP_DATA) { |
ab105a4fb tracing: Use trac... |
450 451 452 453 454 |
trace_probe_log_err(offs, COMM_CANT_DEREF); return -EINVAL; } if (++code == end) { trace_probe_log_err(offs, TOO_MANY_OPS); |
533059281 tracing: probeeve... |
455 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
456 |
} |
533059281 tracing: probeeve... |
457 |
*pcode = code; |
e65f7ae7f tracing/probe: Su... |
458 |
code->op = deref; |
533059281 tracing: probeeve... |
459 |
code->offset = offset; |
8ab83f564 tracing: Extract ... |
460 461 |
} break; |
6218bf9f4 tracing/probe: Ad... |
462 |
case '\\': /* Immediate value */ |
a42e3c4de tracing/probe: Ad... |
463 464 465 466 467 468 469 470 471 472 473 474 475 |
if (arg[1] == '"') { /* Immediate string */ ret = __parse_imm_string(arg + 2, &tmp, offs + 2); if (ret) break; code->op = FETCH_OP_DATA; code->data = tmp; } else { ret = str_to_immediate(arg + 1, &code->immediate); if (ret) trace_probe_log_err(offs + 1, BAD_IMM); else code->op = FETCH_OP_IMM; } |
6218bf9f4 tracing/probe: Ad... |
476 |
break; |
8ab83f564 tracing: Extract ... |
477 |
} |
533059281 tracing: probeeve... |
478 479 |
if (!ret && code->op == FETCH_OP_NOP) { /* Parsed, but do not find fetch method */ |
ab105a4fb tracing: Use trac... |
480 |
trace_probe_log_err(offs, BAD_FETCH_ARG); |
8ab83f564 tracing: Extract ... |
481 482 |
ret = -EINVAL; } |
8ab83f564 tracing: Extract ... |
483 484 485 486 487 488 489 490 |
return ret; } #define BYTES_TO_BITS(nb) ((BITS_PER_LONG * (nb)) / sizeof(long)) /* Bitfield type needs to be parsed into a fetch function */ static int __parse_bitfield_probe_arg(const char *bf, const struct fetch_type *t, |
533059281 tracing: probeeve... |
491 |
struct fetch_insn **pcode) |
8ab83f564 tracing: Extract ... |
492 |
{ |
533059281 tracing: probeeve... |
493 |
struct fetch_insn *code = *pcode; |
8ab83f564 tracing: Extract ... |
494 495 496 497 498 |
unsigned long bw, bo; char *tail; if (*bf != 'b') return 0; |
8ab83f564 tracing: Extract ... |
499 500 501 502 503 504 505 506 507 508 |
bw = simple_strtoul(bf + 1, &tail, 0); /* Use simple one */ if (bw == 0 || *tail != '@') return -EINVAL; bf = tail + 1; bo = simple_strtoul(bf, &tail, 0); if (tail == bf || *tail != '/') return -EINVAL; |
533059281 tracing: probeeve... |
509 510 |
code++; if (code->op != FETCH_OP_NOP) |
ab105a4fb tracing: Use trac... |
511 |
return -EINVAL; |
533059281 tracing: probeeve... |
512 |
*pcode = code; |
8ab83f564 tracing: Extract ... |
513 |
|
533059281 tracing: probeeve... |
514 515 516 517 |
code->op = FETCH_OP_MOD_BF; code->lshift = BYTES_TO_BITS(t->size) - (bw + bo); code->rshift = BYTES_TO_BITS(t->size) - bw; code->basesize = t->size; |
8ab83f564 tracing: Extract ... |
518 519 520 521 522 |
return (BYTES_TO_BITS(t->size) < (bw + bo)) ? -EINVAL : 0; } /* String length checking wrapper */ |
d00bbea94 tracing: Integrat... |
523 |
static int traceprobe_parse_probe_arg_body(char *arg, ssize_t *size, |
ab105a4fb tracing: Use trac... |
524 |
struct probe_arg *parg, unsigned int flags, int offset) |
8ab83f564 tracing: Extract ... |
525 |
{ |
40b53b771 tracing: probeeve... |
526 |
struct fetch_insn *code, *scode, *tmp = NULL; |
ab105a4fb tracing: Use trac... |
527 |
char *t, *t2, *t3; |
40b53b771 tracing: probeeve... |
528 |
int ret, len; |
8ab83f564 tracing: Extract ... |
529 |
|
ab105a4fb tracing: Use trac... |
530 531 532 533 534 535 536 |
len = strlen(arg); if (len > MAX_ARGSTR_LEN) { trace_probe_log_err(offset, ARG_TOO_LONG); return -EINVAL; } else if (len == 0) { trace_probe_log_err(offset, NO_ARG_BODY); return -EINVAL; |
8ab83f564 tracing: Extract ... |
537 |
} |
ab105a4fb tracing: Use trac... |
538 |
|
8ab83f564 tracing: Extract ... |
539 |
parg->comm = kstrdup(arg, GFP_KERNEL); |
ab105a4fb tracing: Use trac... |
540 |
if (!parg->comm) |
8ab83f564 tracing: Extract ... |
541 |
return -ENOMEM; |
ab105a4fb tracing: Use trac... |
542 |
|
40b53b771 tracing: probeeve... |
543 |
t = strchr(arg, ':'); |
8ab83f564 tracing: Extract ... |
544 |
if (t) { |
40b53b771 tracing: probeeve... |
545 546 547 |
*t = '\0'; t2 = strchr(++t, '['); if (t2) { |
ab105a4fb tracing: Use trac... |
548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
*t2++ = '\0'; t3 = strchr(t2, ']'); if (!t3) { offset += t2 + strlen(t2) - arg; trace_probe_log_err(offset, ARRAY_NO_CLOSE); return -EINVAL; } else if (t3[1] != '\0') { trace_probe_log_err(offset + t3 + 1 - arg, BAD_ARRAY_SUFFIX); return -EINVAL; } *t3 = '\0'; if (kstrtouint(t2, 0, &parg->count) || !parg->count) { trace_probe_log_err(offset + t2 - arg, BAD_ARRAY_NUM); |
40b53b771 tracing: probeeve... |
564 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
565 566 567 568 569 570 |
} if (parg->count > MAX_ARRAY_LEN) { trace_probe_log_err(offset + t2 - arg, ARRAY_TOO_BIG); return -EINVAL; } |
40b53b771 tracing: probeeve... |
571 |
} |
8ab83f564 tracing: Extract ... |
572 |
} |
3dd1f7f24 tracing: probeeve... |
573 |
|
a42e3c4de tracing/probe: Ad... |
574 575 576 577 578 |
/* * Since $comm and immediate string can not be dereferred, * we can find those by strcmp. */ if (strcmp(arg, "$comm") == 0 || strncmp(arg, "\\\"", 2) == 0) { |
3dd1f7f24 tracing: probeeve... |
579 580 581 |
/* The type of $comm must be "string", and not an array. */ if (parg->count || (t && strcmp(t, "string"))) return -EINVAL; |
40b53b771 tracing: probeeve... |
582 |
parg->type = find_fetch_type("string"); |
3dd1f7f24 tracing: probeeve... |
583 |
} else |
40b53b771 tracing: probeeve... |
584 |
parg->type = find_fetch_type(t); |
8ab83f564 tracing: Extract ... |
585 |
if (!parg->type) { |
ab105a4fb tracing: Use trac... |
586 |
trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_TYPE); |
8ab83f564 tracing: Extract ... |
587 588 589 |
return -EINVAL; } parg->offset = *size; |
40b53b771 tracing: probeeve... |
590 591 592 593 594 595 596 597 598 599 |
*size += parg->type->size * (parg->count ?: 1); if (parg->count) { len = strlen(parg->type->fmttype) + 6; parg->fmt = kmalloc(len, GFP_KERNEL); if (!parg->fmt) return -ENOMEM; snprintf(parg->fmt, len, "%s[%d]", parg->type->fmttype, parg->count); } |
8ab83f564 tracing: Extract ... |
600 |
|
8623b0067 tracing: Replace ... |
601 |
code = tmp = kcalloc(FETCH_INSN_MAX, sizeof(*code), GFP_KERNEL); |
533059281 tracing: probeeve... |
602 603 604 605 606 |
if (!code) return -ENOMEM; code[FETCH_INSN_MAX - 1].op = FETCH_OP_END; ret = parse_probe_arg(arg, parg->type, &code, &code[FETCH_INSN_MAX - 1], |
ab105a4fb tracing: Use trac... |
607 |
flags, offset); |
533059281 tracing: probeeve... |
608 609 610 611 |
if (ret) goto fail; /* Store operation */ |
88903c464 tracing/probe: Ad... |
612 613 |
if (!strcmp(parg->type->name, "string") || !strcmp(parg->type->name, "ustring")) { |
e65f7ae7f tracing/probe: Su... |
614 |
if (code->op != FETCH_OP_DEREF && code->op != FETCH_OP_UDEREF && |
a42e3c4de tracing/probe: Ad... |
615 616 |
code->op != FETCH_OP_IMM && code->op != FETCH_OP_COMM && code->op != FETCH_OP_DATA) { |
ab105a4fb tracing: Use trac... |
617 618 |
trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_STRING); |
533059281 tracing: probeeve... |
619 620 621 |
ret = -EINVAL; goto fail; } |
3aa8fdc37 tracing/probe: Fi... |
622 623 |
if ((code->op == FETCH_OP_IMM || code->op == FETCH_OP_COMM || code->op == FETCH_OP_DATA) || parg->count) { |
40b53b771 tracing: probeeve... |
624 |
/* |
a42e3c4de tracing/probe: Ad... |
625 626 627 628 |
* IMM, DATA and COMM is pointing actual address, those * must be kept, and if parg->count != 0, this is an * array of string pointers instead of string address * itself. |
40b53b771 tracing: probeeve... |
629 |
*/ |
533059281 tracing: probeeve... |
630 |
code++; |
40b53b771 tracing: probeeve... |
631 |
if (code->op != FETCH_OP_NOP) { |
ab105a4fb tracing: Use trac... |
632 633 |
trace_probe_log_err(offset, TOO_MANY_OPS); ret = -EINVAL; |
40b53b771 tracing: probeeve... |
634 635 636 |
goto fail; } } |
88903c464 tracing/probe: Ad... |
637 |
/* If op == DEREF, replace it with STRING */ |
e65f7ae7f tracing/probe: Su... |
638 639 |
if (!strcmp(parg->type->name, "ustring") || code->op == FETCH_OP_UDEREF) |
88903c464 tracing/probe: Ad... |
640 641 642 |
code->op = FETCH_OP_ST_USTRING; else code->op = FETCH_OP_ST_STRING; |
40b53b771 tracing: probeeve... |
643 |
code->size = parg->type->size; |
533059281 tracing: probeeve... |
644 645 646 647 |
parg->dynamic = true; } else if (code->op == FETCH_OP_DEREF) { code->op = FETCH_OP_ST_MEM; code->size = parg->type->size; |
e65f7ae7f tracing/probe: Su... |
648 649 650 |
} else if (code->op == FETCH_OP_UDEREF) { code->op = FETCH_OP_ST_UMEM; code->size = parg->type->size; |
533059281 tracing: probeeve... |
651 652 653 |
} else { code++; if (code->op != FETCH_OP_NOP) { |
ab105a4fb tracing: Use trac... |
654 655 |
trace_probe_log_err(offset, TOO_MANY_OPS); ret = -EINVAL; |
533059281 tracing: probeeve... |
656 657 658 659 660 |
goto fail; } code->op = FETCH_OP_ST_RAW; code->size = parg->type->size; } |
40b53b771 tracing: probeeve... |
661 |
scode = code; |
533059281 tracing: probeeve... |
662 663 664 |
/* Modify operation */ if (t != NULL) { ret = __parse_bitfield_probe_arg(t, parg->type, &code); |
ab105a4fb tracing: Use trac... |
665 666 |
if (ret) { trace_probe_log_err(offset + t - arg, BAD_BITFIELD); |
533059281 tracing: probeeve... |
667 |
goto fail; |
ab105a4fb tracing: Use trac... |
668 |
} |
8ab83f564 tracing: Extract ... |
669 |
} |
40b53b771 tracing: probeeve... |
670 671 672 |
/* Loop(Array) operation */ if (parg->count) { if (scode->op != FETCH_OP_ST_MEM && |
88903c464 tracing/probe: Ad... |
673 674 |
scode->op != FETCH_OP_ST_STRING && scode->op != FETCH_OP_ST_USTRING) { |
ab105a4fb tracing: Use trac... |
675 676 |
trace_probe_log_err(offset + (t ? (t - arg) : 0), BAD_STRING); |
40b53b771 tracing: probeeve... |
677 678 679 680 681 |
ret = -EINVAL; goto fail; } code++; if (code->op != FETCH_OP_NOP) { |
ab105a4fb tracing: Use trac... |
682 683 |
trace_probe_log_err(offset, TOO_MANY_OPS); ret = -EINVAL; |
40b53b771 tracing: probeeve... |
684 685 686 687 688 |
goto fail; } code->op = FETCH_OP_LP_ARRAY; code->param = parg->count; } |
533059281 tracing: probeeve... |
689 690 691 692 |
code++; code->op = FETCH_OP_END; /* Shrink down the code buffer */ |
8623b0067 tracing: Replace ... |
693 |
parg->code = kcalloc(code - tmp + 1, sizeof(*code), GFP_KERNEL); |
533059281 tracing: probeeve... |
694 695 696 697 698 699 |
if (!parg->code) ret = -ENOMEM; else memcpy(parg->code, tmp, sizeof(*code) * (code - tmp + 1)); fail: |
a6682814f tracing/kprobes: ... |
700 701 |
if (ret) { for (code = tmp; code < tmp + FETCH_INSN_MAX; code++) |
a42e3c4de tracing/probe: Ad... |
702 703 |
if (code->op == FETCH_NOP_SYMBOL || code->op == FETCH_OP_DATA) |
a6682814f tracing/kprobes: ... |
704 705 |
kfree(code->data); } |
533059281 tracing: probeeve... |
706 |
kfree(tmp); |
8ab83f564 tracing: Extract ... |
707 708 709 710 711 |
return ret; } /* Return 1 if name is reserved or already used by another argument */ |
d00bbea94 tracing: Integrat... |
712 713 |
static int traceprobe_conflict_field_name(const char *name, struct probe_arg *args, int narg) |
8ab83f564 tracing: Extract ... |
714 715 716 717 718 719 720 721 722 723 724 725 726 |
{ int i; for (i = 0; i < ARRAY_SIZE(reserved_field_names); i++) if (strcmp(reserved_field_names[i], name) == 0) return 1; for (i = 0; i < narg; i++) if (strcmp(args[i].name, name) == 0) return 1; return 0; } |
d00bbea94 tracing: Integrat... |
727 728 729 730 731 |
int traceprobe_parse_probe_arg(struct trace_probe *tp, int i, char *arg, unsigned int flags) { struct probe_arg *parg = &tp->args[i]; char *body; |
d00bbea94 tracing: Integrat... |
732 733 734 735 736 737 |
/* Increment count for freeing args in error case */ tp->nr_args++; body = strchr(arg, '='); if (body) { |
ab105a4fb tracing: Use trac... |
738 739 740 741 742 |
if (body - arg > MAX_ARG_NAME_LEN) { trace_probe_log_err(0, ARG_NAME_TOO_LONG); return -EINVAL; } else if (body == arg) { trace_probe_log_err(0, NO_ARG_NAME); |
b4443c17a tracing/probe: Ch... |
743 |
return -EINVAL; |
ab105a4fb tracing: Use trac... |
744 |
} |
d00bbea94 tracing: Integrat... |
745 746 747 748 749 750 751 752 753 754 755 |
parg->name = kmemdup_nul(arg, body - arg, GFP_KERNEL); body++; } else { /* If argument name is omitted, set "argN" */ parg->name = kasprintf(GFP_KERNEL, "arg%d", i + 1); body = arg; } if (!parg->name) return -ENOMEM; if (!is_good_name(parg->name)) { |
ab105a4fb tracing: Use trac... |
756 |
trace_probe_log_err(0, BAD_ARG_NAME); |
d00bbea94 tracing: Integrat... |
757 758 |
return -EINVAL; } |
d00bbea94 tracing: Integrat... |
759 |
if (traceprobe_conflict_field_name(parg->name, tp->args, i)) { |
ab105a4fb tracing: Use trac... |
760 |
trace_probe_log_err(0, USED_ARG_NAME); |
d00bbea94 tracing: Integrat... |
761 762 |
return -EINVAL; } |
d00bbea94 tracing: Integrat... |
763 |
/* Parse fetch argument */ |
ab105a4fb tracing: Use trac... |
764 765 |
return traceprobe_parse_probe_arg_body(body, &tp->size, parg, flags, body - arg); |
d00bbea94 tracing: Integrat... |
766 |
} |
8ab83f564 tracing: Extract ... |
767 768 |
void traceprobe_free_probe_arg(struct probe_arg *arg) { |
a6682814f tracing/kprobes: ... |
769 770 771 |
struct fetch_insn *code = arg->code; while (code && code->op != FETCH_OP_END) { |
a42e3c4de tracing/probe: Ad... |
772 773 |
if (code->op == FETCH_NOP_SYMBOL || code->op == FETCH_OP_DATA) |
a6682814f tracing/kprobes: ... |
774 775 776 |
kfree(code->data); code++; } |
533059281 tracing: probeeve... |
777 |
kfree(arg->code); |
8ab83f564 tracing: Extract ... |
778 779 |
kfree(arg->name); kfree(arg->comm); |
40b53b771 tracing: probeeve... |
780 |
kfree(arg->fmt); |
8ab83f564 tracing: Extract ... |
781 |
} |
a6682814f tracing/kprobes: ... |
782 783 784 785 786 787 788 789 790 791 792 793 |
int traceprobe_update_arg(struct probe_arg *arg) { struct fetch_insn *code = arg->code; long offset; char *tmp; char c; int ret = 0; while (code && code->op != FETCH_OP_END) { if (code->op == FETCH_NOP_SYMBOL) { if (code[1].op != FETCH_OP_IMM) return -EINVAL; |
ee474b81f tracing/kprobes: ... |
794 |
tmp = strpbrk(code->data, "+-"); |
a6682814f tracing/kprobes: ... |
795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 |
if (tmp) c = *tmp; ret = traceprobe_split_symbol_offset(code->data, &offset); if (ret) return ret; code[1].immediate = (unsigned long)kallsyms_lookup_name(code->data); if (tmp) *tmp = c; if (!code[1].immediate) return -ENOENT; code[1].immediate += offset; } code++; } return 0; } |
40b53b771 tracing: probeeve... |
814 815 |
/* When len=0, we just calculate the needed length */ #define LEN_OR_ZERO (len ? len - pos : 0) |
5bf652aaf tracing/probes: I... |
816 817 818 |
static int __set_print_fmt(struct trace_probe *tp, char *buf, int len, bool is_return) { |
40b53b771 tracing: probeeve... |
819 820 |
struct probe_arg *parg; int i, j; |
5bf652aaf tracing/probes: I... |
821 |
int pos = 0; |
5bf652aaf tracing/probes: I... |
822 823 824 825 826 827 828 829 830 |
const char *fmt, *arg; if (!is_return) { fmt = "(%lx)"; arg = "REC->" FIELD_STRING_IP; } else { fmt = "(%lx <- %lx)"; arg = "REC->" FIELD_STRING_FUNC ", REC->" FIELD_STRING_RETIP; } |
5bf652aaf tracing/probes: I... |
831 832 833 |
pos += snprintf(buf + pos, LEN_OR_ZERO, "\"%s", fmt); for (i = 0; i < tp->nr_args; i++) { |
40b53b771 tracing: probeeve... |
834 835 836 837 838 839 840 841 842 843 844 845 |
parg = tp->args + i; pos += snprintf(buf + pos, LEN_OR_ZERO, " %s=", parg->name); if (parg->count) { pos += snprintf(buf + pos, LEN_OR_ZERO, "{%s", parg->type->fmt); for (j = 1; j < parg->count; j++) pos += snprintf(buf + pos, LEN_OR_ZERO, ",%s", parg->type->fmt); pos += snprintf(buf + pos, LEN_OR_ZERO, "}"); } else pos += snprintf(buf + pos, LEN_OR_ZERO, "%s", parg->type->fmt); |
5bf652aaf tracing/probes: I... |
846 847 848 849 850 |
} pos += snprintf(buf + pos, LEN_OR_ZERO, "\", %s", arg); for (i = 0; i < tp->nr_args; i++) { |
40b53b771 tracing: probeeve... |
851 852 |
parg = tp->args + i; if (parg->count) { |
20279420a tracing/kprobes: ... |
853 854 |
if ((strcmp(parg->type->name, "string") == 0) || (strcmp(parg->type->name, "ustring") == 0)) |
40b53b771 tracing: probeeve... |
855 856 857 858 859 860 861 |
fmt = ", __get_str(%s[%d])"; else fmt = ", REC->%s[%d]"; for (j = 0; j < parg->count; j++) pos += snprintf(buf + pos, LEN_OR_ZERO, fmt, parg->name, j); } else { |
20279420a tracing/kprobes: ... |
862 863 |
if ((strcmp(parg->type->name, "string") == 0) || (strcmp(parg->type->name, "ustring") == 0)) |
40b53b771 tracing: probeeve... |
864 865 866 |
fmt = ", __get_str(%s)"; else fmt = ", REC->%s"; |
5bf652aaf tracing/probes: I... |
867 |
pos += snprintf(buf + pos, LEN_OR_ZERO, |
40b53b771 tracing: probeeve... |
868 869 |
fmt, parg->name); } |
5bf652aaf tracing/probes: I... |
870 |
} |
5bf652aaf tracing/probes: I... |
871 872 873 |
/* return the length of print_fmt */ return pos; } |
40b53b771 tracing: probeeve... |
874 |
#undef LEN_OR_ZERO |
5bf652aaf tracing/probes: I... |
875 |
|
0a46c8549 tracing: probeeve... |
876 |
int traceprobe_set_print_fmt(struct trace_probe *tp, bool is_return) |
5bf652aaf tracing/probes: I... |
877 |
{ |
e3dc9f898 tracing/probe: Ad... |
878 |
struct trace_event_call *call = trace_probe_event_call(tp); |
5bf652aaf tracing/probes: I... |
879 880 881 882 883 884 885 886 887 888 889 |
int len; char *print_fmt; /* First: called with 0 length to calculate the needed length */ len = __set_print_fmt(tp, NULL, 0, is_return); print_fmt = kmalloc(len + 1, GFP_KERNEL); if (!print_fmt) return -ENOMEM; /* Second: actually write the @print_fmt */ __set_print_fmt(tp, print_fmt, len + 1, is_return); |
e3dc9f898 tracing/probe: Ad... |
890 |
call->print_fmt = print_fmt; |
5bf652aaf tracing/probes: I... |
891 892 893 |
return 0; } |
eeb07b061 tracing: probeeve... |
894 895 896 897 898 899 900 901 902 |
int traceprobe_define_arg_fields(struct trace_event_call *event_call, size_t offset, struct trace_probe *tp) { int ret, i; /* Set argument names as fields */ for (i = 0; i < tp->nr_args; i++) { struct probe_arg *parg = &tp->args[i]; |
40b53b771 tracing: probeeve... |
903 904 905 906 907 908 909 910 911 |
const char *fmt = parg->type->fmttype; int size = parg->type->size; if (parg->fmt) fmt = parg->fmt; if (parg->count) size *= parg->count; ret = trace_define_field(event_call, fmt, parg->name, offset + parg->offset, size, |
eeb07b061 tracing: probeeve... |
912 913 914 915 916 917 918 |
parg->type->is_signed, FILTER_OTHER); if (ret) return ret; } return 0; } |
455b28997 tracing/probe: Ad... |
919 |
|
ca89bc071 tracing/kprobe: A... |
920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 |
static void trace_probe_event_free(struct trace_probe_event *tpe) { kfree(tpe->class.system); kfree(tpe->call.name); kfree(tpe->call.print_fmt); kfree(tpe); } int trace_probe_append(struct trace_probe *tp, struct trace_probe *to) { if (trace_probe_has_sibling(tp)) return -EBUSY; list_del_init(&tp->list); trace_probe_event_free(tp->event); tp->event = to->event; list_add_tail(&tp->list, trace_probe_probe_list(to)); return 0; } void trace_probe_unlink(struct trace_probe *tp) { list_del_init(&tp->list); if (list_empty(trace_probe_probe_list(tp))) trace_probe_event_free(tp->event); tp->event = NULL; } |
455b28997 tracing/probe: Ad... |
949 950 951 952 953 954 955 |
void trace_probe_cleanup(struct trace_probe *tp) { int i; for (i = 0; i < tp->nr_args; i++) traceprobe_free_probe_arg(&tp->args[i]); |
ca89bc071 tracing/kprobe: A... |
956 957 |
if (tp->event) trace_probe_unlink(tp); |
455b28997 tracing/probe: Ad... |
958 959 960 |
} int trace_probe_init(struct trace_probe *tp, const char *event, |
b61387cb7 tracing/uprobe: F... |
961 |
const char *group, bool alloc_filter) |
455b28997 tracing/probe: Ad... |
962 |
{ |
60d53e2c3 tracing/probe: Sp... |
963 |
struct trace_event_call *call; |
b61387cb7 tracing/uprobe: F... |
964 |
size_t size = sizeof(struct trace_probe_event); |
60d53e2c3 tracing/probe: Sp... |
965 |
int ret = 0; |
e3dc9f898 tracing/probe: Ad... |
966 |
|
455b28997 tracing/probe: Ad... |
967 968 |
if (!event || !group) return -EINVAL; |
b61387cb7 tracing/uprobe: F... |
969 970 971 972 |
if (alloc_filter) size += sizeof(struct trace_uprobe_filter); tp->event = kzalloc(size, GFP_KERNEL); |
60d53e2c3 tracing/probe: Sp... |
973 |
if (!tp->event) |
455b28997 tracing/probe: Ad... |
974 |
return -ENOMEM; |
d59fae6fe tracing/kprobe: F... |
975 976 977 978 |
INIT_LIST_HEAD(&tp->event->files); INIT_LIST_HEAD(&tp->event->class.fields); INIT_LIST_HEAD(&tp->event->probes); INIT_LIST_HEAD(&tp->list); |
fc9d276f2 tracing/probe: re... |
979 |
list_add(&tp->list, &tp->event->probes); |
d59fae6fe tracing/kprobe: F... |
980 |
|
60d53e2c3 tracing/probe: Sp... |
981 982 983 984 985 986 987 988 989 990 991 992 |
call = trace_probe_event_call(tp); call->class = &tp->event->class; call->name = kstrdup(event, GFP_KERNEL); if (!call->name) { ret = -ENOMEM; goto error; } tp->event->class.system = kstrdup(group, GFP_KERNEL); if (!tp->event->class.system) { ret = -ENOMEM; goto error; |
455b28997 tracing/probe: Ad... |
993 |
} |
455b28997 tracing/probe: Ad... |
994 995 |
return 0; |
60d53e2c3 tracing/probe: Sp... |
996 997 998 999 |
error: trace_probe_cleanup(tp); return ret; |
455b28997 tracing/probe: Ad... |
1000 |
} |
46e5376d4 tracing/probe: Ad... |
1001 1002 1003 |
int trace_probe_register_event_call(struct trace_probe *tp) { |
e3dc9f898 tracing/probe: Ad... |
1004 |
struct trace_event_call *call = trace_probe_event_call(tp); |
46e5376d4 tracing/probe: Ad... |
1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 |
int ret; ret = register_trace_event(&call->event); if (!ret) return -ENODEV; ret = trace_add_event_call(call); if (ret) unregister_trace_event(&call->event); return ret; } |
b5f935ee1 tracing/probe: Ad... |
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 |
int trace_probe_add_file(struct trace_probe *tp, struct trace_event_file *file) { struct event_file_link *link; link = kmalloc(sizeof(*link), GFP_KERNEL); if (!link) return -ENOMEM; link->file = file; INIT_LIST_HEAD(&link->list); |
60d53e2c3 tracing/probe: Sp... |
1028 |
list_add_tail_rcu(&link->list, &tp->event->files); |
747774d6b tracing/probe: Ad... |
1029 |
trace_probe_set_flag(tp, TP_FLAG_TRACE); |
b5f935ee1 tracing/probe: Ad... |
1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 |
return 0; } struct event_file_link *trace_probe_get_file_link(struct trace_probe *tp, struct trace_event_file *file) { struct event_file_link *link; trace_probe_for_each_link(link, tp) { if (link->file == file) return link; } return NULL; } int trace_probe_remove_file(struct trace_probe *tp, struct trace_event_file *file) { struct event_file_link *link; link = trace_probe_get_file_link(tp, file); if (!link) return -ENOENT; list_del_rcu(&link->list); synchronize_rcu(); kfree(link); |
60d53e2c3 tracing/probe: Sp... |
1058 |
if (list_empty(&tp->event->files)) |
747774d6b tracing/probe: Ad... |
1059 |
trace_probe_clear_flag(tp, TP_FLAG_TRACE); |
b5f935ee1 tracing/probe: Ad... |
1060 1061 1062 |
return 0; } |
ca89bc071 tracing/kprobe: A... |
1063 1064 1065 1066 1067 1068 1069 1070 |
/* * Return the smallest index of different type argument (start from 1). * If all argument types and name are same, return 0. */ int trace_probe_compare_arg_type(struct trace_probe *a, struct trace_probe *b) { int i; |
d2aea95a1 tracing/probe: Fi... |
1071 1072 1073 1074 1075 |
/* In case of more arguments */ if (a->nr_args < b->nr_args) return a->nr_args + 1; if (a->nr_args > b->nr_args) return b->nr_args + 1; |
ca89bc071 tracing/kprobe: A... |
1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 |
for (i = 0; i < a->nr_args; i++) { if ((b->nr_args <= i) || ((a->args[i].type != b->args[i].type) || (a->args[i].count != b->args[i].count) || strcmp(a->args[i].name, b->args[i].name))) return i + 1; } return 0; } |
eb5bf8133 tracing/kprobe: A... |
1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 |
bool trace_probe_match_command_args(struct trace_probe *tp, int argc, const char **argv) { char buf[MAX_ARGSTR_LEN + 1]; int i; if (tp->nr_args < argc) return false; for (i = 0; i < argc; i++) { snprintf(buf, sizeof(buf), "%s=%s", tp->args[i].name, tp->args[i].comm); if (strcmp(buf, argv[i])) return false; } return true; } |