diff options
author | Masami Hiramatsu <mhiramat@redhat.com> | 2010-03-16 18:06:12 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2010-03-17 06:32:31 -0400 |
commit | 4235b0454ebeefc2295ad8417e18a8761425b19e (patch) | |
tree | e6b0a3c66618dede18117a71fd16d2e65f93cba1 /tools/perf | |
parent | f4d7da499e4fc1fdff8f26fdeb1a058d475a7a6c (diff) |
perf probe: Introduce kprobe_trace_event and perf_probe_event
Introduce kprobe_trace_event and perf_probe_event and replace
old probe_point structure with it. probe_point structure is
not enough flexible nor extensible. New data structures
will help implementing further features.
Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com>
Cc: systemtap <systemtap@sources.redhat.com>
Cc: DLE <dle-develop@lists.sourceforge.net>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Arnaldo Carvalho de Melo <acme@redhat.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
LKML-Reference: <20100316220612.32050.33806.stgit@localhost6.localdomain6>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/builtin-probe.c | 30 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 626 | ||||
-rw-r--r-- | tools/perf/util/probe-event.h | 111 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 140 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 58 |
5 files changed, 589 insertions, 376 deletions
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c index a1a2891ca66f..e0dafd9dfeb5 100644 --- a/tools/perf/builtin-probe.c +++ b/tools/perf/builtin-probe.c | |||
@@ -48,12 +48,11 @@ | |||
48 | 48 | ||
49 | /* Session management structure */ | 49 | /* Session management structure */ |
50 | static struct { | 50 | static struct { |
51 | bool need_dwarf; | ||
52 | bool list_events; | 51 | bool list_events; |
53 | bool force_add; | 52 | bool force_add; |
54 | bool show_lines; | 53 | bool show_lines; |
55 | int nr_probe; | 54 | int nevents; |
56 | struct probe_point probes[MAX_PROBES]; | 55 | struct perf_probe_event events[MAX_PROBES]; |
57 | struct strlist *dellist; | 56 | struct strlist *dellist; |
58 | struct line_range line_range; | 57 | struct line_range line_range; |
59 | } params; | 58 | } params; |
@@ -62,16 +61,16 @@ static struct { | |||
62 | /* Parse an event definition. Note that any error must die. */ | 61 | /* Parse an event definition. Note that any error must die. */ |
63 | static void parse_probe_event(const char *str) | 62 | static void parse_probe_event(const char *str) |
64 | { | 63 | { |
65 | struct probe_point *pp = ¶ms.probes[params.nr_probe]; | 64 | struct perf_probe_event *pev = ¶ms.events[params.nevents]; |
66 | 65 | ||
67 | pr_debug("probe-definition(%d): %s\n", params.nr_probe, str); | 66 | pr_debug("probe-definition(%d): %s\n", params.nevents, str); |
68 | if (++params.nr_probe == MAX_PROBES) | 67 | if (++params.nevents == MAX_PROBES) |
69 | die("Too many probes (> %d) are specified.", MAX_PROBES); | 68 | die("Too many probes (> %d) are specified.", MAX_PROBES); |
70 | 69 | ||
71 | /* Parse perf-probe event into probe_point */ | 70 | /* Parse a perf-probe command into event */ |
72 | parse_perf_probe_event(str, pp, ¶ms.need_dwarf); | 71 | parse_perf_probe_command(str, pev); |
73 | 72 | ||
74 | pr_debug("%d arguments\n", pp->nr_args); | 73 | pr_debug("%d arguments\n", pev->nargs); |
75 | } | 74 | } |
76 | 75 | ||
77 | static void parse_probe_event_argv(int argc, const char **argv) | 76 | static void parse_probe_event_argv(int argc, const char **argv) |
@@ -191,7 +190,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
191 | parse_probe_event_argv(argc, argv); | 190 | parse_probe_event_argv(argc, argv); |
192 | } | 191 | } |
193 | 192 | ||
194 | if ((!params.nr_probe && !params.dellist && !params.list_events && | 193 | if ((!params.nevents && !params.dellist && !params.list_events && |
195 | !params.show_lines)) | 194 | !params.show_lines)) |
196 | usage_with_options(probe_usage, options); | 195 | usage_with_options(probe_usage, options); |
197 | 196 | ||
@@ -199,7 +198,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
199 | die("Failed to find debugfs path."); | 198 | die("Failed to find debugfs path."); |
200 | 199 | ||
201 | if (params.list_events) { | 200 | if (params.list_events) { |
202 | if (params.nr_probe != 0 || params.dellist) { | 201 | if (params.nevents != 0 || params.dellist) { |
203 | pr_warning(" Error: Don't use --list with" | 202 | pr_warning(" Error: Don't use --list with" |
204 | " --add/--del.\n"); | 203 | " --add/--del.\n"); |
205 | usage_with_options(probe_usage, options); | 204 | usage_with_options(probe_usage, options); |
@@ -214,7 +213,7 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
214 | 213 | ||
215 | #ifndef NO_DWARF_SUPPORT | 214 | #ifndef NO_DWARF_SUPPORT |
216 | if (params.show_lines) { | 215 | if (params.show_lines) { |
217 | if (params.nr_probe != 0 || params.dellist) { | 216 | if (params.nevents != 0 || params.dellist) { |
218 | pr_warning(" Error: Don't use --line with" | 217 | pr_warning(" Error: Don't use --line with" |
219 | " --add/--del.\n"); | 218 | " --add/--del.\n"); |
220 | usage_with_options(probe_usage, options); | 219 | usage_with_options(probe_usage, options); |
@@ -226,14 +225,13 @@ int cmd_probe(int argc, const char **argv, const char *prefix __used) | |||
226 | #endif | 225 | #endif |
227 | 226 | ||
228 | if (params.dellist) { | 227 | if (params.dellist) { |
229 | del_trace_kprobe_events(params.dellist); | 228 | del_perf_probe_events(params.dellist); |
230 | strlist__delete(params.dellist); | 229 | strlist__delete(params.dellist); |
231 | if (params.nr_probe == 0) | 230 | if (params.nevents == 0) |
232 | return 0; | 231 | return 0; |
233 | } | 232 | } |
234 | 233 | ||
235 | add_trace_kprobe_events(params.probes, params.nr_probe, | 234 | add_perf_probe_events(params.events, params.nevents, params.force_add); |
236 | params.force_add, params.need_dwarf); | ||
237 | return 0; | 235 | return 0; |
238 | } | 236 | } |
239 | 237 | ||
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index ac41578a3552..b44ddfb030d7 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -44,6 +44,7 @@ | |||
44 | #include "thread.h" | 44 | #include "thread.h" |
45 | #include "parse-events.h" /* For debugfs_path */ | 45 | #include "parse-events.h" /* For debugfs_path */ |
46 | #include "probe-event.h" | 46 | #include "probe-event.h" |
47 | #include "probe-finder.h" | ||
47 | 48 | ||
48 | #define MAX_CMDLEN 256 | 49 | #define MAX_CMDLEN 256 |
49 | #define MAX_PROBE_ARGS 128 | 50 | #define MAX_PROBE_ARGS 128 |
@@ -150,8 +151,9 @@ static bool check_event_name(const char *name) | |||
150 | } | 151 | } |
151 | 152 | ||
152 | /* Parse probepoint definition. */ | 153 | /* Parse probepoint definition. */ |
153 | static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | 154 | static void parse_perf_probe_point(char *arg, struct perf_probe_event *pev) |
154 | { | 155 | { |
156 | struct perf_probe_point *pp = &pev->point; | ||
155 | char *ptr, *tmp; | 157 | char *ptr, *tmp; |
156 | char c, nc = 0; | 158 | char c, nc = 0; |
157 | /* | 159 | /* |
@@ -172,7 +174,8 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | |||
172 | if (!check_event_name(arg)) | 174 | if (!check_event_name(arg)) |
173 | semantic_error("%s is bad for event name -it must " | 175 | semantic_error("%s is bad for event name -it must " |
174 | "follow C symbol-naming rule.", arg); | 176 | "follow C symbol-naming rule.", arg); |
175 | pp->event = xstrdup(arg); | 177 | pev->event = xstrdup(arg); |
178 | pev->group = NULL; | ||
176 | arg = tmp; | 179 | arg = tmp; |
177 | } | 180 | } |
178 | 181 | ||
@@ -255,57 +258,65 @@ static void parse_perf_probe_probepoint(char *arg, struct probe_point *pp) | |||
255 | semantic_error("Offset/Line/Lazy pattern can't be used with " | 258 | semantic_error("Offset/Line/Lazy pattern can't be used with " |
256 | "return probe."); | 259 | "return probe."); |
257 | 260 | ||
258 | pr_debug("symbol:%s file:%s line:%d offset:%d return:%d lazy:%s\n", | 261 | pr_debug("symbol:%s file:%s line:%d offset:%lu return:%d lazy:%s\n", |
259 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, | 262 | pp->function, pp->file, pp->line, pp->offset, pp->retprobe, |
260 | pp->lazy_line); | 263 | pp->lazy_line); |
261 | } | 264 | } |
262 | 265 | ||
263 | /* Parse perf-probe event definition */ | 266 | /* Parse perf-probe event command */ |
264 | void parse_perf_probe_event(const char *str, struct probe_point *pp, | 267 | void parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev) |
265 | bool *need_dwarf) | ||
266 | { | 268 | { |
267 | char **argv; | 269 | char **argv; |
268 | int argc, i; | 270 | int argc, i; |
269 | 271 | ||
270 | *need_dwarf = false; | 272 | argv = argv_split(cmd, &argc); |
271 | |||
272 | argv = argv_split(str, &argc); | ||
273 | if (!argv) | 273 | if (!argv) |
274 | die("argv_split failed."); | 274 | die("argv_split failed."); |
275 | if (argc > MAX_PROBE_ARGS + 1) | 275 | if (argc > MAX_PROBE_ARGS + 1) |
276 | semantic_error("Too many arguments"); | 276 | semantic_error("Too many arguments"); |
277 | 277 | ||
278 | /* Parse probe point */ | 278 | /* Parse probe point */ |
279 | parse_perf_probe_probepoint(argv[0], pp); | 279 | parse_perf_probe_point(argv[0], pev); |
280 | if (pp->file || pp->line || pp->lazy_line) | ||
281 | *need_dwarf = true; | ||
282 | 280 | ||
283 | /* Copy arguments and ensure return probe has no C argument */ | 281 | /* Copy arguments and ensure return probe has no C argument */ |
284 | pp->nr_args = argc - 1; | 282 | pev->nargs = argc - 1; |
285 | pp->args = xzalloc(sizeof(char *) * pp->nr_args); | 283 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); |
286 | for (i = 0; i < pp->nr_args; i++) { | 284 | for (i = 0; i < pev->nargs; i++) { |
287 | pp->args[i] = xstrdup(argv[i + 1]); | 285 | pev->args[i].name = xstrdup(argv[i + 1]); |
288 | if (is_c_varname(pp->args[i])) { | 286 | if (is_c_varname(pev->args[i].name) && pev->point.retprobe) |
289 | if (pp->retprobe) | 287 | semantic_error("You can't specify local variable for" |
290 | semantic_error("You can't specify local" | 288 | " kretprobe"); |
291 | " variable for kretprobe"); | ||
292 | *need_dwarf = true; | ||
293 | } | ||
294 | } | 289 | } |
295 | 290 | ||
296 | argv_free(argv); | 291 | argv_free(argv); |
297 | } | 292 | } |
298 | 293 | ||
294 | /* Return true if this perf_probe_event requires debuginfo */ | ||
295 | bool perf_probe_event_need_dwarf(struct perf_probe_event *pev) | ||
296 | { | ||
297 | int i; | ||
298 | |||
299 | if (pev->point.file || pev->point.line || pev->point.lazy_line) | ||
300 | return true; | ||
301 | |||
302 | for (i = 0; i < pev->nargs; i++) | ||
303 | if (is_c_varname(pev->args[i].name)) | ||
304 | return true; | ||
305 | |||
306 | return false; | ||
307 | } | ||
308 | |||
299 | /* Parse kprobe_events event into struct probe_point */ | 309 | /* Parse kprobe_events event into struct probe_point */ |
300 | void parse_trace_kprobe_event(const char *str, struct probe_point *pp) | 310 | void parse_kprobe_trace_command(const char *cmd, struct kprobe_trace_event *tev) |
301 | { | 311 | { |
312 | struct kprobe_trace_point *tp = &tev->point; | ||
302 | char pr; | 313 | char pr; |
303 | char *p; | 314 | char *p; |
304 | int ret, i, argc; | 315 | int ret, i, argc; |
305 | char **argv; | 316 | char **argv; |
306 | 317 | ||
307 | pr_debug("Parsing kprobe_events: %s\n", str); | 318 | pr_debug("Parsing kprobe_events: %s\n", cmd); |
308 | argv = argv_split(str, &argc); | 319 | argv = argv_split(cmd, &argc); |
309 | if (!argv) | 320 | if (!argv) |
310 | die("argv_split failed."); | 321 | die("argv_split failed."); |
311 | if (argc < 2) | 322 | if (argc < 2) |
@@ -313,47 +324,46 @@ void parse_trace_kprobe_event(const char *str, struct probe_point *pp) | |||
313 | 324 | ||
314 | /* Scan event and group name. */ | 325 | /* Scan event and group name. */ |
315 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", | 326 | ret = sscanf(argv[0], "%c:%a[^/ \t]/%a[^ \t]", |
316 | &pr, (float *)(void *)&pp->group, | 327 | &pr, (float *)(void *)&tev->group, |
317 | (float *)(void *)&pp->event); | 328 | (float *)(void *)&tev->event); |
318 | if (ret != 3) | 329 | if (ret != 3) |
319 | semantic_error("Failed to parse event name: %s", argv[0]); | 330 | semantic_error("Failed to parse event name: %s", argv[0]); |
320 | pr_debug("Group:%s Event:%s probe:%c\n", pp->group, pp->event, pr); | 331 | pr_debug("Group:%s Event:%s probe:%c\n", tev->group, tev->event, pr); |
321 | 332 | ||
322 | pp->retprobe = (pr == 'r'); | 333 | tp->retprobe = (pr == 'r'); |
323 | 334 | ||
324 | /* Scan function name and offset */ | 335 | /* Scan function name and offset */ |
325 | ret = sscanf(argv[1], "%a[^+]+%d", (float *)(void *)&pp->function, | 336 | ret = sscanf(argv[1], "%a[^+]+%lu", (float *)(void *)&tp->symbol, |
326 | &pp->offset); | 337 | &tp->offset); |
327 | if (ret == 1) | 338 | if (ret == 1) |
328 | pp->offset = 0; | 339 | tp->offset = 0; |
329 | |||
330 | /* kprobe_events doesn't have this information */ | ||
331 | pp->line = 0; | ||
332 | pp->file = NULL; | ||
333 | 340 | ||
334 | pp->nr_args = argc - 2; | 341 | tev->nargs = argc - 2; |
335 | pp->args = xzalloc(sizeof(char *) * pp->nr_args); | 342 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); |
336 | for (i = 0; i < pp->nr_args; i++) { | 343 | for (i = 0; i < tev->nargs; i++) { |
337 | p = strchr(argv[i + 2], '='); | 344 | p = strchr(argv[i + 2], '='); |
338 | if (p) /* We don't need which register is assigned. */ | 345 | if (p) /* We don't need which register is assigned. */ |
339 | *p = '\0'; | 346 | *p++ = '\0'; |
340 | pp->args[i] = xstrdup(argv[i + 2]); | 347 | else |
348 | p = argv[i + 2]; | ||
349 | tev->args[i].name = xstrdup(argv[i + 2]); | ||
350 | /* TODO: parse regs and offset */ | ||
351 | tev->args[i].value = xstrdup(p); | ||
341 | } | 352 | } |
342 | 353 | ||
343 | argv_free(argv); | 354 | argv_free(argv); |
344 | } | 355 | } |
345 | 356 | ||
346 | /* Synthesize only probe point (not argument) */ | 357 | /* Compose only probe point (not argument) */ |
347 | int synthesize_perf_probe_point(struct probe_point *pp) | 358 | static char *synthesize_perf_probe_point(struct perf_probe_point *pp) |
348 | { | 359 | { |
349 | char *buf; | 360 | char *buf; |
350 | char offs[64] = "", line[64] = ""; | 361 | char offs[64] = "", line[64] = ""; |
351 | int ret; | 362 | int ret; |
352 | 363 | ||
353 | pp->probes[0] = buf = xzalloc(MAX_CMDLEN); | 364 | buf = xzalloc(MAX_CMDLEN); |
354 | pp->found = 1; | ||
355 | if (pp->offset) { | 365 | if (pp->offset) { |
356 | ret = e_snprintf(offs, 64, "+%d", pp->offset); | 366 | ret = e_snprintf(offs, 64, "+%lu", pp->offset); |
357 | if (ret <= 0) | 367 | if (ret <= 0) |
358 | goto error; | 368 | goto error; |
359 | } | 369 | } |
@@ -368,68 +378,209 @@ int synthesize_perf_probe_point(struct probe_point *pp) | |||
368 | offs, pp->retprobe ? "%return" : "", line); | 378 | offs, pp->retprobe ? "%return" : "", line); |
369 | else | 379 | else |
370 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); | 380 | ret = e_snprintf(buf, MAX_CMDLEN, "%s%s", pp->file, line); |
371 | if (ret <= 0) { | 381 | if (ret <= 0) |
382 | goto error; | ||
383 | |||
384 | return buf; | ||
372 | error: | 385 | error: |
373 | free(pp->probes[0]); | 386 | die("Failed to synthesize perf probe point: %s", strerror(-ret)); |
374 | pp->probes[0] = NULL; | ||
375 | pp->found = 0; | ||
376 | } | ||
377 | return ret; | ||
378 | } | 387 | } |
379 | 388 | ||
380 | int synthesize_perf_probe_event(struct probe_point *pp) | 389 | #if 0 |
390 | char *synthesize_perf_probe_command(struct perf_probe_event *pev) | ||
381 | { | 391 | { |
382 | char *buf; | 392 | char *buf; |
383 | int i, len, ret; | 393 | int i, len, ret; |
384 | 394 | ||
385 | len = synthesize_perf_probe_point(pp); | 395 | buf = synthesize_perf_probe_point(&pev->point); |
386 | if (len < 0) | 396 | if (!buf) |
387 | return 0; | 397 | return NULL; |
388 | 398 | ||
389 | buf = pp->probes[0]; | 399 | len = strlen(buf); |
390 | for (i = 0; i < pp->nr_args; i++) { | 400 | for (i = 0; i < pev->nargs; i++) { |
391 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | 401 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", |
392 | pp->args[i]); | 402 | pev->args[i].name); |
393 | if (ret <= 0) | 403 | if (ret <= 0) { |
394 | goto error; | 404 | free(buf); |
405 | return NULL; | ||
406 | } | ||
395 | len += ret; | 407 | len += ret; |
396 | } | 408 | } |
397 | pp->found = 1; | ||
398 | 409 | ||
399 | return pp->found; | 410 | return buf; |
400 | error: | 411 | } |
401 | free(pp->probes[0]); | 412 | #endif |
402 | pp->probes[0] = NULL; | 413 | |
414 | static int __synthesize_kprobe_trace_arg_ref(struct kprobe_trace_arg_ref *ref, | ||
415 | char **buf, size_t *buflen, | ||
416 | int depth) | ||
417 | { | ||
418 | int ret; | ||
419 | if (ref->next) { | ||
420 | depth = __synthesize_kprobe_trace_arg_ref(ref->next, buf, | ||
421 | buflen, depth + 1); | ||
422 | if (depth < 0) | ||
423 | goto out; | ||
424 | } | ||
425 | |||
426 | ret = e_snprintf(*buf, *buflen, "%+ld(", ref->offset); | ||
427 | if (ret < 0) | ||
428 | depth = ret; | ||
429 | else { | ||
430 | *buf += ret; | ||
431 | *buflen -= ret; | ||
432 | } | ||
433 | out: | ||
434 | return depth; | ||
403 | 435 | ||
404 | return ret; | ||
405 | } | 436 | } |
406 | 437 | ||
407 | int synthesize_trace_kprobe_event(struct probe_point *pp) | 438 | static int synthesize_kprobe_trace_arg(struct kprobe_trace_arg *arg, |
439 | char *buf, size_t buflen) | ||
408 | { | 440 | { |
441 | int ret, depth = 0; | ||
442 | char *tmp = buf; | ||
443 | |||
444 | /* Argument name or separator */ | ||
445 | if (arg->name) | ||
446 | ret = e_snprintf(buf, buflen, " %s=", arg->name); | ||
447 | else | ||
448 | ret = e_snprintf(buf, buflen, " "); | ||
449 | if (ret < 0) | ||
450 | return ret; | ||
451 | buf += ret; | ||
452 | buflen -= ret; | ||
453 | |||
454 | /* Dereferencing arguments */ | ||
455 | if (arg->ref) { | ||
456 | depth = __synthesize_kprobe_trace_arg_ref(arg->ref, &buf, | ||
457 | &buflen, 1); | ||
458 | if (depth < 0) | ||
459 | return depth; | ||
460 | } | ||
461 | |||
462 | /* Print argument value */ | ||
463 | ret = e_snprintf(buf, buflen, "%s", arg->value); | ||
464 | if (ret < 0) | ||
465 | return ret; | ||
466 | buf += ret; | ||
467 | buflen -= ret; | ||
468 | |||
469 | /* Closing */ | ||
470 | while (depth--) { | ||
471 | ret = e_snprintf(buf, buflen, ")"); | ||
472 | if (ret < 0) | ||
473 | return ret; | ||
474 | buf += ret; | ||
475 | buflen -= ret; | ||
476 | } | ||
477 | |||
478 | return buf - tmp; | ||
479 | } | ||
480 | |||
481 | char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev) | ||
482 | { | ||
483 | struct kprobe_trace_point *tp = &tev->point; | ||
409 | char *buf; | 484 | char *buf; |
410 | int i, len, ret; | 485 | int i, len, ret; |
411 | 486 | ||
412 | pp->probes[0] = buf = xzalloc(MAX_CMDLEN); | 487 | buf = xzalloc(MAX_CMDLEN); |
413 | ret = e_snprintf(buf, MAX_CMDLEN, "%s+%d", pp->function, pp->offset); | 488 | len = e_snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s+%lu", |
414 | if (ret <= 0) | 489 | tp->retprobe ? 'r' : 'p', |
490 | tev->group, tev->event, | ||
491 | tp->symbol, tp->offset); | ||
492 | if (len <= 0) | ||
415 | goto error; | 493 | goto error; |
416 | len = ret; | ||
417 | 494 | ||
418 | for (i = 0; i < pp->nr_args; i++) { | 495 | for (i = 0; i < tev->nargs; i++) { |
419 | ret = e_snprintf(&buf[len], MAX_CMDLEN - len, " %s", | 496 | ret = synthesize_kprobe_trace_arg(&tev->args[i], buf + len, |
420 | pp->args[i]); | 497 | MAX_CMDLEN - len); |
421 | if (ret <= 0) | 498 | if (ret <= 0) |
422 | goto error; | 499 | goto error; |
423 | len += ret; | 500 | len += ret; |
424 | } | 501 | } |
425 | pp->found = 1; | ||
426 | 502 | ||
427 | return pp->found; | 503 | return buf; |
428 | error: | 504 | error: |
429 | free(pp->probes[0]); | 505 | free(buf); |
430 | pp->probes[0] = NULL; | 506 | return NULL; |
507 | } | ||
431 | 508 | ||
432 | return ret; | 509 | void convert_to_perf_probe_event(struct kprobe_trace_event *tev, |
510 | struct perf_probe_event *pev) | ||
511 | { | ||
512 | char buf[64]; | ||
513 | int i; | ||
514 | |||
515 | pev->event = xstrdup(tev->event); | ||
516 | pev->group = xstrdup(tev->group); | ||
517 | |||
518 | /* Convert trace_point to probe_point */ | ||
519 | pev->point.function = xstrdup(tev->point.symbol); | ||
520 | pev->point.offset = tev->point.offset; | ||
521 | pev->point.retprobe = tev->point.retprobe; | ||
522 | |||
523 | /* Convert trace_arg to probe_arg */ | ||
524 | pev->nargs = tev->nargs; | ||
525 | pev->args = xzalloc(sizeof(struct perf_probe_arg) * pev->nargs); | ||
526 | for (i = 0; i < tev->nargs; i++) | ||
527 | if (tev->args[i].name) | ||
528 | pev->args[i].name = xstrdup(tev->args[i].name); | ||
529 | else { | ||
530 | synthesize_kprobe_trace_arg(&tev->args[i], buf, 64); | ||
531 | pev->args[i].name = xstrdup(buf); | ||
532 | } | ||
533 | } | ||
534 | |||
535 | void clear_perf_probe_event(struct perf_probe_event *pev) | ||
536 | { | ||
537 | struct perf_probe_point *pp = &pev->point; | ||
538 | int i; | ||
539 | |||
540 | if (pev->event) | ||
541 | free(pev->event); | ||
542 | if (pev->group) | ||
543 | free(pev->group); | ||
544 | if (pp->file) | ||
545 | free(pp->file); | ||
546 | if (pp->function) | ||
547 | free(pp->function); | ||
548 | if (pp->lazy_line) | ||
549 | free(pp->lazy_line); | ||
550 | for (i = 0; i < pev->nargs; i++) | ||
551 | if (pev->args[i].name) | ||
552 | free(pev->args[i].name); | ||
553 | if (pev->args) | ||
554 | free(pev->args); | ||
555 | memset(pev, 0, sizeof(*pev)); | ||
556 | } | ||
557 | |||
558 | void clear_kprobe_trace_event(struct kprobe_trace_event *tev) | ||
559 | { | ||
560 | struct kprobe_trace_arg_ref *ref, *next; | ||
561 | int i; | ||
562 | |||
563 | if (tev->event) | ||
564 | free(tev->event); | ||
565 | if (tev->group) | ||
566 | free(tev->group); | ||
567 | if (tev->point.symbol) | ||
568 | free(tev->point.symbol); | ||
569 | for (i = 0; i < tev->nargs; i++) { | ||
570 | if (tev->args[i].name) | ||
571 | free(tev->args[i].name); | ||
572 | if (tev->args[i].value) | ||
573 | free(tev->args[i].value); | ||
574 | ref = tev->args[i].ref; | ||
575 | while (ref) { | ||
576 | next = ref->next; | ||
577 | free(ref); | ||
578 | ref = next; | ||
579 | } | ||
580 | } | ||
581 | if (tev->args) | ||
582 | free(tev->args); | ||
583 | memset(tev, 0, sizeof(*tev)); | ||
433 | } | 584 | } |
434 | 585 | ||
435 | static int open_kprobe_events(bool readwrite) | 586 | static int open_kprobe_events(bool readwrite) |
@@ -458,7 +609,7 @@ static int open_kprobe_events(bool readwrite) | |||
458 | } | 609 | } |
459 | 610 | ||
460 | /* Get raw string list of current kprobe_events */ | 611 | /* Get raw string list of current kprobe_events */ |
461 | static struct strlist *get_trace_kprobe_event_rawlist(int fd) | 612 | static struct strlist *get_kprobe_trace_command_rawlist(int fd) |
462 | { | 613 | { |
463 | int ret, idx; | 614 | int ret, idx; |
464 | FILE *fp; | 615 | FILE *fp; |
@@ -486,99 +637,82 @@ static struct strlist *get_trace_kprobe_event_rawlist(int fd) | |||
486 | return sl; | 637 | return sl; |
487 | } | 638 | } |
488 | 639 | ||
489 | /* Free and zero clear probe_point */ | ||
490 | static void clear_probe_point(struct probe_point *pp) | ||
491 | { | ||
492 | int i; | ||
493 | |||
494 | if (pp->event) | ||
495 | free(pp->event); | ||
496 | if (pp->group) | ||
497 | free(pp->group); | ||
498 | if (pp->function) | ||
499 | free(pp->function); | ||
500 | if (pp->file) | ||
501 | free(pp->file); | ||
502 | if (pp->lazy_line) | ||
503 | free(pp->lazy_line); | ||
504 | for (i = 0; i < pp->nr_args; i++) | ||
505 | free(pp->args[i]); | ||
506 | if (pp->args) | ||
507 | free(pp->args); | ||
508 | for (i = 0; i < pp->found; i++) | ||
509 | free(pp->probes[i]); | ||
510 | memset(pp, 0, sizeof(*pp)); | ||
511 | } | ||
512 | |||
513 | /* Show an event */ | 640 | /* Show an event */ |
514 | static void show_perf_probe_event(const char *event, const char *place, | 641 | static void show_perf_probe_event(struct perf_probe_event *pev) |
515 | struct probe_point *pp) | ||
516 | { | 642 | { |
517 | int i, ret; | 643 | int i, ret; |
518 | char buf[128]; | 644 | char buf[128]; |
645 | char *place; | ||
519 | 646 | ||
520 | ret = e_snprintf(buf, 128, "%s:%s", pp->group, event); | 647 | /* Synthesize only event probe point */ |
648 | place = synthesize_perf_probe_point(&pev->point); | ||
649 | |||
650 | ret = e_snprintf(buf, 128, "%s:%s", pev->group, pev->event); | ||
521 | if (ret < 0) | 651 | if (ret < 0) |
522 | die("Failed to copy event: %s", strerror(-ret)); | 652 | die("Failed to copy event: %s", strerror(-ret)); |
523 | printf(" %-40s (on %s", buf, place); | 653 | printf(" %-40s (on %s", buf, place); |
524 | 654 | ||
525 | if (pp->nr_args > 0) { | 655 | if (pev->nargs > 0) { |
526 | printf(" with"); | 656 | printf(" with"); |
527 | for (i = 0; i < pp->nr_args; i++) | 657 | for (i = 0; i < pev->nargs; i++) |
528 | printf(" %s", pp->args[i]); | 658 | printf(" %s", pev->args[i].name); |
529 | } | 659 | } |
530 | printf(")\n"); | 660 | printf(")\n"); |
661 | free(place); | ||
531 | } | 662 | } |
532 | 663 | ||
533 | /* List up current perf-probe events */ | 664 | /* List up current perf-probe events */ |
534 | void show_perf_probe_events(void) | 665 | void show_perf_probe_events(void) |
535 | { | 666 | { |
536 | int fd; | 667 | int fd; |
537 | struct probe_point pp; | 668 | struct kprobe_trace_event tev; |
669 | struct perf_probe_event pev; | ||
538 | struct strlist *rawlist; | 670 | struct strlist *rawlist; |
539 | struct str_node *ent; | 671 | struct str_node *ent; |
540 | 672 | ||
541 | setup_pager(); | 673 | setup_pager(); |
542 | memset(&pp, 0, sizeof(pp)); | 674 | |
675 | memset(&tev, 0, sizeof(tev)); | ||
676 | memset(&pev, 0, sizeof(pev)); | ||
543 | 677 | ||
544 | fd = open_kprobe_events(false); | 678 | fd = open_kprobe_events(false); |
545 | rawlist = get_trace_kprobe_event_rawlist(fd); | 679 | rawlist = get_kprobe_trace_command_rawlist(fd); |
546 | close(fd); | 680 | close(fd); |
547 | 681 | ||
548 | strlist__for_each(ent, rawlist) { | 682 | strlist__for_each(ent, rawlist) { |
549 | parse_trace_kprobe_event(ent->s, &pp); | 683 | parse_kprobe_trace_command(ent->s, &tev); |
550 | /* Synthesize only event probe point */ | 684 | convert_to_perf_probe_event(&tev, &pev); |
551 | synthesize_perf_probe_point(&pp); | ||
552 | /* Show an event */ | 685 | /* Show an event */ |
553 | show_perf_probe_event(pp.event, pp.probes[0], &pp); | 686 | show_perf_probe_event(&pev); |
554 | clear_probe_point(&pp); | 687 | clear_perf_probe_event(&pev); |
688 | clear_kprobe_trace_event(&tev); | ||
555 | } | 689 | } |
556 | 690 | ||
557 | strlist__delete(rawlist); | 691 | strlist__delete(rawlist); |
558 | } | 692 | } |
559 | 693 | ||
560 | /* Get current perf-probe event names */ | 694 | /* Get current perf-probe event names */ |
561 | static struct strlist *get_perf_event_names(int fd, bool include_group) | 695 | static struct strlist *get_kprobe_trace_event_names(int fd, bool include_group) |
562 | { | 696 | { |
563 | char buf[128]; | 697 | char buf[128]; |
564 | struct strlist *sl, *rawlist; | 698 | struct strlist *sl, *rawlist; |
565 | struct str_node *ent; | 699 | struct str_node *ent; |
566 | struct probe_point pp; | 700 | struct kprobe_trace_event tev; |
567 | 701 | ||
568 | memset(&pp, 0, sizeof(pp)); | 702 | memset(&tev, 0, sizeof(tev)); |
569 | rawlist = get_trace_kprobe_event_rawlist(fd); | ||
570 | 703 | ||
704 | rawlist = get_kprobe_trace_command_rawlist(fd); | ||
571 | sl = strlist__new(true, NULL); | 705 | sl = strlist__new(true, NULL); |
572 | strlist__for_each(ent, rawlist) { | 706 | strlist__for_each(ent, rawlist) { |
573 | parse_trace_kprobe_event(ent->s, &pp); | 707 | parse_kprobe_trace_command(ent->s, &tev); |
574 | if (include_group) { | 708 | if (include_group) { |
575 | if (e_snprintf(buf, 128, "%s:%s", pp.group, | 709 | if (e_snprintf(buf, 128, "%s:%s", tev.group, |
576 | pp.event) < 0) | 710 | tev.event) < 0) |
577 | die("Failed to copy group:event name."); | 711 | die("Failed to copy group:event name."); |
578 | strlist__add(sl, buf); | 712 | strlist__add(sl, buf); |
579 | } else | 713 | } else |
580 | strlist__add(sl, pp.event); | 714 | strlist__add(sl, tev.event); |
581 | clear_probe_point(&pp); | 715 | clear_kprobe_trace_event(&tev); |
582 | } | 716 | } |
583 | 717 | ||
584 | strlist__delete(rawlist); | 718 | strlist__delete(rawlist); |
@@ -586,9 +720,10 @@ static struct strlist *get_perf_event_names(int fd, bool include_group) | |||
586 | return sl; | 720 | return sl; |
587 | } | 721 | } |
588 | 722 | ||
589 | static void write_trace_kprobe_event(int fd, const char *buf) | 723 | static void write_kprobe_trace_event(int fd, struct kprobe_trace_event *tev) |
590 | { | 724 | { |
591 | int ret; | 725 | int ret; |
726 | char *buf = synthesize_kprobe_trace_command(tev); | ||
592 | 727 | ||
593 | pr_debug("Writing event: %s\n", buf); | 728 | pr_debug("Writing event: %s\n", buf); |
594 | if (!probe_event_dry_run) { | 729 | if (!probe_event_dry_run) { |
@@ -596,6 +731,7 @@ static void write_trace_kprobe_event(int fd, const char *buf) | |||
596 | if (ret <= 0) | 731 | if (ret <= 0) |
597 | die("Failed to write event: %s", strerror(errno)); | 732 | die("Failed to write event: %s", strerror(errno)); |
598 | } | 733 | } |
734 | free(buf); | ||
599 | } | 735 | } |
600 | 736 | ||
601 | static void get_new_event_name(char *buf, size_t len, const char *base, | 737 | static void get_new_event_name(char *buf, size_t len, const char *base, |
@@ -628,81 +764,83 @@ static void get_new_event_name(char *buf, size_t len, const char *base, | |||
628 | die("Too many events are on the same function."); | 764 | die("Too many events are on the same function."); |
629 | } | 765 | } |
630 | 766 | ||
631 | static void __add_trace_kprobe_events(struct probe_point *probes, | 767 | static void __add_kprobe_trace_events(struct perf_probe_event *pev, |
632 | int nr_probes, bool force_add) | 768 | struct kprobe_trace_event *tevs, |
769 | int ntevs, bool allow_suffix) | ||
633 | { | 770 | { |
634 | int i, j, fd; | 771 | int i, fd; |
635 | struct probe_point *pp; | 772 | struct kprobe_trace_event *tev; |
636 | char buf[MAX_CMDLEN]; | 773 | char buf[64]; |
637 | char event[64]; | 774 | const char *event, *group; |
638 | struct strlist *namelist; | 775 | struct strlist *namelist; |
639 | bool allow_suffix; | ||
640 | 776 | ||
641 | fd = open_kprobe_events(true); | 777 | fd = open_kprobe_events(true); |
642 | /* Get current event names */ | 778 | /* Get current event names */ |
643 | namelist = get_perf_event_names(fd, false); | 779 | namelist = get_kprobe_trace_event_names(fd, false); |
644 | 780 | ||
645 | for (j = 0; j < nr_probes; j++) { | 781 | printf("Add new event%s\n", (ntevs > 1) ? "s:" : ":"); |
646 | pp = probes + j; | 782 | for (i = 0; i < ntevs; i++) { |
647 | if (!pp->event) | 783 | tev = &tevs[i]; |
648 | pp->event = xstrdup(pp->function); | 784 | if (pev->event) |
649 | if (!pp->group) | 785 | event = pev->event; |
650 | pp->group = xstrdup(PERFPROBE_GROUP); | 786 | else |
651 | /* If force_add is true, suffix search is allowed */ | 787 | if (pev->point.function) |
652 | allow_suffix = force_add; | 788 | event = pev->point.function; |
653 | for (i = 0; i < pp->found; i++) { | 789 | else |
654 | /* Get an unused new event name */ | 790 | event = tev->point.symbol; |
655 | get_new_event_name(event, 64, pp->event, namelist, | 791 | if (pev->group) |
656 | allow_suffix); | 792 | group = pev->group; |
657 | snprintf(buf, MAX_CMDLEN, "%c:%s/%s %s\n", | 793 | else |
658 | pp->retprobe ? 'r' : 'p', | 794 | group = PERFPROBE_GROUP; |
659 | pp->group, event, | 795 | |
660 | pp->probes[i]); | 796 | /* Get an unused new event name */ |
661 | write_trace_kprobe_event(fd, buf); | 797 | get_new_event_name(buf, 64, event, namelist, allow_suffix); |
662 | printf("Added new event:\n"); | 798 | event = buf; |
663 | /* Get the first parameter (probe-point) */ | 799 | |
664 | sscanf(pp->probes[i], "%s", buf); | 800 | tev->event = xstrdup(event); |
665 | show_perf_probe_event(event, buf, pp); | 801 | tev->group = xstrdup(group); |
666 | /* Add added event name to namelist */ | 802 | write_kprobe_trace_event(fd, tev); |
667 | strlist__add(namelist, event); | 803 | /* Add added event name to namelist */ |
668 | /* | 804 | strlist__add(namelist, event); |
669 | * Probes after the first probe which comes from same | 805 | |
670 | * user input are always allowed to add suffix, because | 806 | /* Trick here - save current event/group */ |
671 | * there might be several addresses corresponding to | 807 | event = pev->event; |
672 | * one code line. | 808 | group = pev->group; |
673 | */ | 809 | pev->event = tev->event; |
674 | allow_suffix = true; | 810 | pev->group = tev->group; |
675 | } | 811 | show_perf_probe_event(pev); |
812 | /* Trick here - restore current event/group */ | ||
813 | pev->event = (char *)event; | ||
814 | pev->group = (char *)group; | ||
815 | |||
816 | /* | ||
817 | * Probes after the first probe which comes from same | ||
818 | * user input are always allowed to add suffix, because | ||
819 | * there might be several addresses corresponding to | ||
820 | * one code line. | ||
821 | */ | ||
822 | allow_suffix = true; | ||
676 | } | 823 | } |
677 | /* Show how to use the event. */ | 824 | /* Show how to use the event. */ |
678 | printf("\nYou can now use it on all perf tools, such as:\n\n"); | 825 | printf("\nYou can now use it on all perf tools, such as:\n\n"); |
679 | printf("\tperf record -e %s:%s -a sleep 1\n\n", PERFPROBE_GROUP, event); | 826 | printf("\tperf record -e %s:%s -a sleep 1\n\n", tev->group, tev->event); |
680 | 827 | ||
681 | strlist__delete(namelist); | 828 | strlist__delete(namelist); |
682 | close(fd); | 829 | close(fd); |
683 | } | 830 | } |
684 | 831 | ||
685 | /* Currently just checking function name from symbol map */ | 832 | static int convert_to_kprobe_trace_events(struct perf_probe_event *pev, |
686 | static void evaluate_probe_point(struct probe_point *pp) | 833 | struct kprobe_trace_event **tevs) |
687 | { | 834 | { |
688 | struct symbol *sym; | 835 | struct symbol *sym; |
689 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], | 836 | bool need_dwarf; |
690 | pp->function, NULL); | ||
691 | if (!sym) | ||
692 | die("Kernel symbol \'%s\' not found - probe not added.", | ||
693 | pp->function); | ||
694 | } | ||
695 | |||
696 | void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, | ||
697 | bool force_add, bool need_dwarf) | ||
698 | { | ||
699 | int i, ret; | ||
700 | struct probe_point *pp; | ||
701 | #ifndef NO_DWARF_SUPPORT | 837 | #ifndef NO_DWARF_SUPPORT |
702 | int fd; | 838 | int fd; |
703 | #endif | 839 | #endif |
704 | /* Add probes */ | 840 | int ntevs = 0, i; |
705 | init_vmlinux(); | 841 | struct kprobe_trace_event *tev; |
842 | |||
843 | need_dwarf = perf_probe_event_need_dwarf(pev); | ||
706 | 844 | ||
707 | if (need_dwarf) | 845 | if (need_dwarf) |
708 | #ifdef NO_DWARF_SUPPORT | 846 | #ifdef NO_DWARF_SUPPORT |
@@ -721,57 +859,90 @@ void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, | |||
721 | } | 859 | } |
722 | 860 | ||
723 | /* Searching probe points */ | 861 | /* Searching probe points */ |
724 | for (i = 0; i < nr_probes; i++) { | 862 | ntevs = find_kprobe_trace_events(fd, pev, tevs); |
725 | pp = &probes[i]; | 863 | |
726 | if (pp->found) | 864 | if (ntevs > 0) /* Found */ |
727 | continue; | 865 | goto found; |
728 | 866 | ||
729 | lseek(fd, SEEK_SET, 0); | 867 | if (ntevs == 0) /* No error but failed to find probe point. */ |
730 | ret = find_probe_point(fd, pp); | 868 | die("Probe point '%s' not found. - probe not added.", |
731 | if (ret > 0) | 869 | synthesize_perf_probe_point(&pev->point)); |
732 | continue; | 870 | |
733 | if (ret == 0) { /* No error but failed to find probe point. */ | 871 | /* Error path */ |
734 | synthesize_perf_probe_point(pp); | 872 | if (need_dwarf) { |
735 | die("Probe point '%s' not found. - probe not added.", | 873 | if (ntevs == -ENOENT) |
736 | pp->probes[0]); | 874 | pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n"); |
737 | } | 875 | die("Could not analyze debuginfo."); |
738 | /* Error path */ | ||
739 | if (need_dwarf) { | ||
740 | if (ret == -ENOENT) | ||
741 | pr_warning("No dwarf info found in the vmlinux - please rebuild with CONFIG_DEBUG_INFO=y.\n"); | ||
742 | die("Could not analyze debuginfo."); | ||
743 | } | ||
744 | pr_debug("An error occurred in debuginfo analysis." | ||
745 | " Try to use symbols.\n"); | ||
746 | break; | ||
747 | } | 876 | } |
748 | close(fd); | 877 | pr_debug("An error occurred in debuginfo analysis." |
878 | " Try to use symbols.\n"); | ||
749 | 879 | ||
750 | end_dwarf: | 880 | end_dwarf: |
751 | #endif /* !NO_DWARF_SUPPORT */ | 881 | #endif /* !NO_DWARF_SUPPORT */ |
752 | 882 | ||
753 | /* Synthesize probes without dwarf */ | 883 | /* Allocate trace event buffer */ |
754 | for (i = 0; i < nr_probes; i++) { | 884 | ntevs = 1; |
755 | pp = &probes[i]; | 885 | tev = *tevs = xzalloc(sizeof(struct kprobe_trace_event)); |
756 | if (pp->found) /* This probe is already found. */ | 886 | |
757 | continue; | 887 | /* Copy parameters */ |
888 | tev->point.symbol = xstrdup(pev->point.function); | ||
889 | tev->point.offset = pev->point.offset; | ||
890 | tev->nargs = pev->nargs; | ||
891 | if (tev->nargs) { | ||
892 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) | ||
893 | * tev->nargs); | ||
894 | for (i = 0; i < tev->nargs; i++) | ||
895 | tev->args[i].value = xstrdup(pev->args[i].name); | ||
896 | } | ||
897 | |||
898 | /* Currently just checking function name from symbol map */ | ||
899 | sym = map__find_symbol_by_name(kmaps[MAP__FUNCTION], | ||
900 | tev->point.symbol, NULL); | ||
901 | if (!sym) | ||
902 | die("Kernel symbol \'%s\' not found - probe not added.", | ||
903 | tev->point.symbol); | ||
904 | found: | ||
905 | close(fd); | ||
906 | return ntevs; | ||
907 | } | ||
908 | |||
909 | struct __event_package { | ||
910 | struct perf_probe_event *pev; | ||
911 | struct kprobe_trace_event *tevs; | ||
912 | int ntevs; | ||
913 | }; | ||
758 | 914 | ||
759 | evaluate_probe_point(pp); | 915 | void add_perf_probe_events(struct perf_probe_event *pevs, int npevs, |
760 | ret = synthesize_trace_kprobe_event(pp); | 916 | bool force_add) |
761 | if (ret == -E2BIG) | 917 | { |
762 | die("probe point definition becomes too long."); | 918 | int i; |
763 | else if (ret < 0) | 919 | struct __event_package *pkgs; |
764 | die("Failed to synthesize a probe point."); | 920 | |
921 | pkgs = xzalloc(sizeof(struct __event_package) * npevs); | ||
922 | |||
923 | /* Init vmlinux path */ | ||
924 | init_vmlinux(); | ||
925 | |||
926 | /* Loop 1: convert all events */ | ||
927 | for (i = 0; i < npevs; i++) { | ||
928 | pkgs[i].pev = &pevs[i]; | ||
929 | /* Convert with or without debuginfo */ | ||
930 | pkgs[i].ntevs = convert_to_kprobe_trace_events(pkgs[i].pev, | ||
931 | &pkgs[i].tevs); | ||
765 | } | 932 | } |
766 | 933 | ||
767 | /* Settng up probe points */ | 934 | /* Loop 2: add all events */ |
768 | __add_trace_kprobe_events(probes, nr_probes, force_add); | 935 | for (i = 0; i < npevs; i++) |
936 | __add_kprobe_trace_events(pkgs[i].pev, pkgs[i].tevs, | ||
937 | pkgs[i].ntevs, force_add); | ||
938 | /* TODO: cleanup all trace events? */ | ||
769 | } | 939 | } |
770 | 940 | ||
771 | static void __del_trace_kprobe_event(int fd, struct str_node *ent) | 941 | static void __del_trace_kprobe_event(int fd, struct str_node *ent) |
772 | { | 942 | { |
773 | char *p; | 943 | char *p; |
774 | char buf[128]; | 944 | char buf[128]; |
945 | int ret; | ||
775 | 946 | ||
776 | /* Convert from perf-probe event to trace-kprobe event */ | 947 | /* Convert from perf-probe event to trace-kprobe event */ |
777 | if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) | 948 | if (e_snprintf(buf, 128, "-:%s", ent->s) < 0) |
@@ -781,7 +952,10 @@ static void __del_trace_kprobe_event(int fd, struct str_node *ent) | |||
781 | die("Internal error: %s should have ':' but not.", ent->s); | 952 | die("Internal error: %s should have ':' but not.", ent->s); |
782 | *p = '/'; | 953 | *p = '/'; |
783 | 954 | ||
784 | write_trace_kprobe_event(fd, buf); | 955 | pr_debug("Writing event: %s\n", buf); |
956 | ret = write(fd, buf, strlen(buf)); | ||
957 | if (ret <= 0) | ||
958 | die("Failed to write event: %s", strerror(errno)); | ||
785 | printf("Remove event: %s\n", ent->s); | 959 | printf("Remove event: %s\n", ent->s); |
786 | } | 960 | } |
787 | 961 | ||
@@ -814,7 +988,7 @@ static void del_trace_kprobe_event(int fd, const char *group, | |||
814 | pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); | 988 | pr_info("Info: event \"%s\" does not exist, could not remove it.\n", buf); |
815 | } | 989 | } |
816 | 990 | ||
817 | void del_trace_kprobe_events(struct strlist *dellist) | 991 | void del_perf_probe_events(struct strlist *dellist) |
818 | { | 992 | { |
819 | int fd; | 993 | int fd; |
820 | const char *group, *event; | 994 | const char *group, *event; |
@@ -824,7 +998,7 @@ void del_trace_kprobe_events(struct strlist *dellist) | |||
824 | 998 | ||
825 | fd = open_kprobe_events(true); | 999 | fd = open_kprobe_events(true); |
826 | /* Get current event names */ | 1000 | /* Get current event names */ |
827 | namelist = get_perf_event_names(fd, true); | 1001 | namelist = get_kprobe_trace_event_names(fd, true); |
828 | 1002 | ||
829 | strlist__for_each(ent, dellist) { | 1003 | strlist__for_each(ent, dellist) { |
830 | str = xstrdup(ent->s); | 1004 | str = xstrdup(ent->s); |
diff --git a/tools/perf/util/probe-event.h b/tools/perf/util/probe-event.h index 703b8876dfb1..2a2f0a26dc67 100644 --- a/tools/perf/util/probe-event.h +++ b/tools/perf/util/probe-event.h | |||
@@ -2,24 +2,113 @@ | |||
2 | #define _PROBE_EVENT_H | 2 | #define _PROBE_EVENT_H |
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "probe-finder.h" | ||
6 | #include "strlist.h" | 5 | #include "strlist.h" |
7 | 6 | ||
8 | extern bool probe_event_dry_run; | 7 | extern bool probe_event_dry_run; |
9 | 8 | ||
10 | extern void parse_line_range_desc(const char *arg, struct line_range *lr); | 9 | /* kprobe-tracer tracing point */ |
11 | extern void parse_perf_probe_event(const char *str, struct probe_point *pp, | 10 | struct kprobe_trace_point { |
12 | bool *need_dwarf); | 11 | char *symbol; /* Base symbol */ |
13 | extern int synthesize_perf_probe_point(struct probe_point *pp); | 12 | unsigned long offset; /* Offset from symbol */ |
14 | extern int synthesize_perf_probe_event(struct probe_point *pp); | 13 | bool retprobe; /* Return probe flag */ |
15 | extern void parse_trace_kprobe_event(const char *str, struct probe_point *pp); | 14 | }; |
16 | extern int synthesize_trace_kprobe_event(struct probe_point *pp); | 15 | |
17 | extern void add_trace_kprobe_events(struct probe_point *probes, int nr_probes, | 16 | /* kprobe-tracer tracing argument referencing offset */ |
18 | bool force_add, bool need_dwarf); | 17 | struct kprobe_trace_arg_ref { |
19 | extern void del_trace_kprobe_events(struct strlist *dellist); | 18 | struct kprobe_trace_arg_ref *next; /* Next reference */ |
19 | long offset; /* Offset value */ | ||
20 | }; | ||
21 | |||
22 | /* kprobe-tracer tracing argument */ | ||
23 | struct kprobe_trace_arg { | ||
24 | char *name; /* Argument name */ | ||
25 | char *value; /* Base value */ | ||
26 | struct kprobe_trace_arg_ref *ref; /* Referencing offset */ | ||
27 | }; | ||
28 | |||
29 | /* kprobe-tracer tracing event (point + arg) */ | ||
30 | struct kprobe_trace_event { | ||
31 | char *event; /* Event name */ | ||
32 | char *group; /* Group name */ | ||
33 | struct kprobe_trace_point point; /* Trace point */ | ||
34 | int nargs; /* Number of args */ | ||
35 | struct kprobe_trace_arg *args; /* Arguments */ | ||
36 | }; | ||
37 | |||
38 | /* Perf probe probing point */ | ||
39 | struct perf_probe_point { | ||
40 | char *file; /* File path */ | ||
41 | char *function; /* Function name */ | ||
42 | int line; /* Line number */ | ||
43 | char *lazy_line; /* Lazy matching pattern */ | ||
44 | unsigned long offset; /* Offset from function entry */ | ||
45 | bool retprobe; /* Return probe flag */ | ||
46 | }; | ||
47 | |||
48 | /* Perf probe probing argument */ | ||
49 | struct perf_probe_arg { | ||
50 | char *name; /* Argument name */ | ||
51 | }; | ||
52 | |||
53 | /* Perf probe probing event (point + arg) */ | ||
54 | struct perf_probe_event { | ||
55 | char *event; /* Event name */ | ||
56 | char *group; /* Group name */ | ||
57 | struct perf_probe_point point; /* Probe point */ | ||
58 | int nargs; /* Number of arguments */ | ||
59 | struct perf_probe_arg *args; /* Arguments */ | ||
60 | }; | ||
61 | |||
62 | |||
63 | /* Line number container */ | ||
64 | struct line_node { | ||
65 | struct list_head list; | ||
66 | unsigned int line; | ||
67 | }; | ||
68 | |||
69 | /* Line range */ | ||
70 | struct line_range { | ||
71 | char *file; /* File name */ | ||
72 | char *function; /* Function name */ | ||
73 | unsigned int start; /* Start line number */ | ||
74 | unsigned int end; /* End line number */ | ||
75 | int offset; /* Start line offset */ | ||
76 | char *path; /* Real path name */ | ||
77 | struct list_head line_list; /* Visible lines */ | ||
78 | }; | ||
79 | |||
80 | /* Command string to events */ | ||
81 | extern void parse_perf_probe_command(const char *cmd, | ||
82 | struct perf_probe_event *pev); | ||
83 | extern void parse_kprobe_trace_command(const char *cmd, | ||
84 | struct kprobe_trace_event *tev); | ||
85 | |||
86 | /* Events to command string */ | ||
87 | extern char *synthesize_perf_probe_command(struct perf_probe_event *pev); | ||
88 | extern char *synthesize_kprobe_trace_command(struct kprobe_trace_event *tev); | ||
89 | |||
90 | /* Check the perf_probe_event needs debuginfo */ | ||
91 | extern bool perf_probe_event_need_dwarf(struct perf_probe_event *pev); | ||
92 | |||
93 | /* Convert from kprobe_trace_event to perf_probe_event */ | ||
94 | extern void convert_to_perf_probe_event(struct kprobe_trace_event *tev, | ||
95 | struct perf_probe_event *pev); | ||
96 | |||
97 | /* Release event contents */ | ||
98 | extern void clear_perf_probe_event(struct perf_probe_event *pev); | ||
99 | extern void clear_kprobe_trace_event(struct kprobe_trace_event *tev); | ||
100 | |||
101 | /* Command string to line-range */ | ||
102 | extern void parse_line_range_desc(const char *cmd, struct line_range *lr); | ||
103 | |||
104 | |||
105 | extern void add_perf_probe_events(struct perf_probe_event *pevs, int ntevs, | ||
106 | bool force_add); | ||
107 | extern void del_perf_probe_events(struct strlist *dellist); | ||
20 | extern void show_perf_probe_events(void); | 108 | extern void show_perf_probe_events(void); |
21 | extern void show_line_range(struct line_range *lr); | 109 | extern void show_line_range(struct line_range *lr); |
22 | 110 | ||
111 | |||
23 | /* Maximum index number of event-name postfix */ | 112 | /* Maximum index number of event-name postfix */ |
24 | #define MAX_EVENT_INDEX 1024 | 113 | #define MAX_EVENT_INDEX 1024 |
25 | 114 | ||
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 3942e14e95cf..251b4c49653e 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -319,19 +319,20 @@ static Dwarf_Die *die_find_variable(Dwarf_Die *sp_die, const char *name, | |||
319 | */ | 319 | */ |
320 | 320 | ||
321 | /* Show a location */ | 321 | /* Show a location */ |
322 | static void show_location(Dwarf_Op *op, struct probe_finder *pf) | 322 | static void convert_location(Dwarf_Op *op, struct probe_finder *pf) |
323 | { | 323 | { |
324 | unsigned int regn; | 324 | unsigned int regn; |
325 | Dwarf_Word offs = 0; | 325 | Dwarf_Word offs = 0; |
326 | int deref = 0, ret; | 326 | bool ref = false; |
327 | const char *regs; | 327 | const char *regs; |
328 | struct kprobe_trace_arg *tvar = pf->tvar; | ||
328 | 329 | ||
329 | /* TODO: support CFA */ | 330 | /* TODO: support CFA */ |
330 | /* If this is based on frame buffer, set the offset */ | 331 | /* If this is based on frame buffer, set the offset */ |
331 | if (op->atom == DW_OP_fbreg) { | 332 | if (op->atom == DW_OP_fbreg) { |
332 | if (pf->fb_ops == NULL) | 333 | if (pf->fb_ops == NULL) |
333 | die("The attribute of frame base is not supported.\n"); | 334 | die("The attribute of frame base is not supported.\n"); |
334 | deref = 1; | 335 | ref = true; |
335 | offs = op->number; | 336 | offs = op->number; |
336 | op = &pf->fb_ops[0]; | 337 | op = &pf->fb_ops[0]; |
337 | } | 338 | } |
@@ -339,13 +340,13 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) | |||
339 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { | 340 | if (op->atom >= DW_OP_breg0 && op->atom <= DW_OP_breg31) { |
340 | regn = op->atom - DW_OP_breg0; | 341 | regn = op->atom - DW_OP_breg0; |
341 | offs += op->number; | 342 | offs += op->number; |
342 | deref = 1; | 343 | ref = true; |
343 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { | 344 | } else if (op->atom >= DW_OP_reg0 && op->atom <= DW_OP_reg31) { |
344 | regn = op->atom - DW_OP_reg0; | 345 | regn = op->atom - DW_OP_reg0; |
345 | } else if (op->atom == DW_OP_bregx) { | 346 | } else if (op->atom == DW_OP_bregx) { |
346 | regn = op->number; | 347 | regn = op->number; |
347 | offs += op->number2; | 348 | offs += op->number2; |
348 | deref = 1; | 349 | ref = true; |
349 | } else if (op->atom == DW_OP_regx) { | 350 | } else if (op->atom == DW_OP_regx) { |
350 | regn = op->number; | 351 | regn = op->number; |
351 | } else | 352 | } else |
@@ -355,17 +356,15 @@ static void show_location(Dwarf_Op *op, struct probe_finder *pf) | |||
355 | if (!regs) | 356 | if (!regs) |
356 | die("%u exceeds max register number.", regn); | 357 | die("%u exceeds max register number.", regn); |
357 | 358 | ||
358 | if (deref) | 359 | tvar->value = xstrdup(regs); |
359 | ret = snprintf(pf->buf, pf->len, " %s=%+jd(%s)", | 360 | if (ref) { |
360 | pf->var, (intmax_t)offs, regs); | 361 | tvar->ref = xzalloc(sizeof(struct kprobe_trace_arg_ref)); |
361 | else | 362 | tvar->ref->offset = (long)offs; |
362 | ret = snprintf(pf->buf, pf->len, " %s=%s", pf->var, regs); | 363 | } |
363 | DIE_IF(ret < 0); | ||
364 | DIE_IF(ret >= pf->len); | ||
365 | } | 364 | } |
366 | 365 | ||
367 | /* Show a variables in kprobe event format */ | 366 | /* Show a variables in kprobe event format */ |
368 | static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | 367 | static void convert_variable(Dwarf_Die *vr_die, struct probe_finder *pf) |
369 | { | 368 | { |
370 | Dwarf_Attribute attr; | 369 | Dwarf_Attribute attr; |
371 | Dwarf_Op *expr; | 370 | Dwarf_Op *expr; |
@@ -379,50 +378,51 @@ static void show_variable(Dwarf_Die *vr_die, struct probe_finder *pf) | |||
379 | if (ret <= 0 || nexpr == 0) | 378 | if (ret <= 0 || nexpr == 0) |
380 | goto error; | 379 | goto error; |
381 | 380 | ||
382 | show_location(expr, pf); | 381 | convert_location(expr, pf); |
383 | /* *expr will be cached in libdw. Don't free it. */ | 382 | /* *expr will be cached in libdw. Don't free it. */ |
384 | return ; | 383 | return ; |
385 | error: | 384 | error: |
386 | /* TODO: Support const_value */ | 385 | /* TODO: Support const_value */ |
387 | die("Failed to find the location of %s at this address.\n" | 386 | die("Failed to find the location of %s at this address.\n" |
388 | " Perhaps, it has been optimized out.", pf->var); | 387 | " Perhaps, it has been optimized out.", pf->pvar->name); |
389 | } | 388 | } |
390 | 389 | ||
391 | /* Find a variable in a subprogram die */ | 390 | /* Find a variable in a subprogram die */ |
392 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) | 391 | static void find_variable(Dwarf_Die *sp_die, struct probe_finder *pf) |
393 | { | 392 | { |
394 | int ret; | ||
395 | Dwarf_Die vr_die; | 393 | Dwarf_Die vr_die; |
396 | 394 | ||
397 | /* TODO: Support struct members and arrays */ | 395 | /* TODO: Support struct members and arrays */ |
398 | if (!is_c_varname(pf->var)) { | 396 | if (!is_c_varname(pf->pvar->name)) { |
399 | /* Output raw parameters */ | 397 | /* Copy raw parameters */ |
400 | ret = snprintf(pf->buf, pf->len, " %s", pf->var); | 398 | pf->tvar->value = xstrdup(pf->pvar->name); |
401 | DIE_IF(ret < 0); | 399 | } else { |
402 | DIE_IF(ret >= pf->len); | 400 | pf->tvar->name = xstrdup(pf->pvar->name); |
403 | return ; | 401 | pr_debug("Searching '%s' variable in context.\n", |
402 | pf->pvar->name); | ||
403 | /* Search child die for local variables and parameters. */ | ||
404 | if (!die_find_variable(sp_die, pf->pvar->name, &vr_die)) | ||
405 | die("Failed to find '%s' in this function.", | ||
406 | pf->pvar->name); | ||
407 | convert_variable(&vr_die, pf); | ||
404 | } | 408 | } |
405 | |||
406 | pr_debug("Searching '%s' variable in context.\n", pf->var); | ||
407 | /* Search child die for local variables and parameters. */ | ||
408 | if (!die_find_variable(sp_die, pf->var, &vr_die)) | ||
409 | die("Failed to find '%s' in this function.", pf->var); | ||
410 | |||
411 | show_variable(&vr_die, pf); | ||
412 | } | 409 | } |
413 | 410 | ||
414 | /* Show a probe point to output buffer */ | 411 | /* Show a probe point to output buffer */ |
415 | static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | 412 | static void convert_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) |
416 | { | 413 | { |
417 | struct probe_point *pp = pf->pp; | 414 | struct kprobe_trace_event *tev; |
418 | Dwarf_Addr eaddr; | 415 | Dwarf_Addr eaddr; |
419 | Dwarf_Die die_mem; | 416 | Dwarf_Die die_mem; |
420 | const char *name; | 417 | const char *name; |
421 | char tmp[MAX_PROBE_BUFFER]; | 418 | int ret, i; |
422 | int ret, i, len; | ||
423 | Dwarf_Attribute fb_attr; | 419 | Dwarf_Attribute fb_attr; |
424 | size_t nops; | 420 | size_t nops; |
425 | 421 | ||
422 | if (pf->ntevs == MAX_PROBES) | ||
423 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
424 | tev = &pf->tevs[pf->ntevs++]; | ||
425 | |||
426 | /* If no real subprogram, find a real one */ | 426 | /* If no real subprogram, find a real one */ |
427 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { | 427 | if (!sp_die || dwarf_tag(sp_die) != DW_TAG_subprogram) { |
428 | sp_die = die_find_real_subprogram(&pf->cu_die, | 428 | sp_die = die_find_real_subprogram(&pf->cu_die, |
@@ -431,31 +431,18 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
431 | die("Probe point is not found in subprograms."); | 431 | die("Probe point is not found in subprograms."); |
432 | } | 432 | } |
433 | 433 | ||
434 | /* Output name of probe point */ | 434 | /* Copy the name of probe point */ |
435 | name = dwarf_diename(sp_die); | 435 | name = dwarf_diename(sp_die); |
436 | if (name) { | 436 | if (name) { |
437 | dwarf_entrypc(sp_die, &eaddr); | 437 | dwarf_entrypc(sp_die, &eaddr); |
438 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "%s+%lu", name, | 438 | tev->point.symbol = xstrdup(name); |
439 | (unsigned long)(pf->addr - eaddr)); | 439 | tev->point.offset = (unsigned long)(pf->addr - eaddr); |
440 | /* Copy the function name if possible */ | 440 | } else |
441 | if (!pp->function) { | ||
442 | pp->function = xstrdup(name); | ||
443 | pp->offset = (size_t)(pf->addr - eaddr); | ||
444 | } | ||
445 | } else { | ||
446 | /* This function has no name. */ | 441 | /* This function has no name. */ |
447 | ret = snprintf(tmp, MAX_PROBE_BUFFER, "0x%jx", | 442 | tev->point.offset = (unsigned long)pf->addr; |
448 | (uintmax_t)pf->addr); | 443 | |
449 | if (!pp->function) { | 444 | pr_debug("Probe point found: %s+%lu\n", tev->point.symbol, |
450 | /* TODO: Use _stext */ | 445 | tev->point.offset); |
451 | pp->function = xstrdup(""); | ||
452 | pp->offset = (size_t)pf->addr; | ||
453 | } | ||
454 | } | ||
455 | DIE_IF(ret < 0); | ||
456 | DIE_IF(ret >= MAX_PROBE_BUFFER); | ||
457 | len = ret; | ||
458 | pr_debug("Probe point found: %s\n", tmp); | ||
459 | 446 | ||
460 | /* Get the frame base attribute/ops */ | 447 | /* Get the frame base attribute/ops */ |
461 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); | 448 | dwarf_attr(sp_die, DW_AT_frame_base, &fb_attr); |
@@ -465,22 +452,16 @@ static void show_probe_point(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
465 | 452 | ||
466 | /* Find each argument */ | 453 | /* Find each argument */ |
467 | /* TODO: use dwarf_cfi_addrframe */ | 454 | /* TODO: use dwarf_cfi_addrframe */ |
468 | for (i = 0; i < pp->nr_args; i++) { | 455 | tev->nargs = pf->pev->nargs; |
469 | pf->var = pp->args[i]; | 456 | tev->args = xzalloc(sizeof(struct kprobe_trace_arg) * tev->nargs); |
470 | pf->buf = &tmp[len]; | 457 | for (i = 0; i < pf->pev->nargs; i++) { |
471 | pf->len = MAX_PROBE_BUFFER - len; | 458 | pf->pvar = &pf->pev->args[i]; |
459 | pf->tvar = &tev->args[i]; | ||
472 | find_variable(sp_die, pf); | 460 | find_variable(sp_die, pf); |
473 | len += strlen(pf->buf); | ||
474 | } | 461 | } |
475 | 462 | ||
476 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ | 463 | /* *pf->fb_ops will be cached in libdw. Don't free it. */ |
477 | pf->fb_ops = NULL; | 464 | pf->fb_ops = NULL; |
478 | |||
479 | if (pp->found == MAX_PROBES) | ||
480 | die("Too many( > %d) probe point found.\n", MAX_PROBES); | ||
481 | |||
482 | pp->probes[pp->found] = xstrdup(tmp); | ||
483 | pp->found++; | ||
484 | } | 465 | } |
485 | 466 | ||
486 | /* Find probe point from its line number */ | 467 | /* Find probe point from its line number */ |
@@ -512,7 +493,7 @@ static void find_probe_point_by_line(struct probe_finder *pf) | |||
512 | (int)i, lineno, (uintmax_t)addr); | 493 | (int)i, lineno, (uintmax_t)addr); |
513 | pf->addr = addr; | 494 | pf->addr = addr; |
514 | 495 | ||
515 | show_probe_point(NULL, pf); | 496 | convert_probe_point(NULL, pf); |
516 | /* Continuing, because target line might be inlined. */ | 497 | /* Continuing, because target line might be inlined. */ |
517 | } | 498 | } |
518 | } | 499 | } |
@@ -563,7 +544,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
563 | if (list_empty(&pf->lcache)) { | 544 | if (list_empty(&pf->lcache)) { |
564 | /* Matching lazy line pattern */ | 545 | /* Matching lazy line pattern */ |
565 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, | 546 | ret = find_lazy_match_lines(&pf->lcache, pf->fname, |
566 | pf->pp->lazy_line); | 547 | pf->pev->point.lazy_line); |
567 | if (ret <= 0) | 548 | if (ret <= 0) |
568 | die("No matched lines found in %s.", pf->fname); | 549 | die("No matched lines found in %s.", pf->fname); |
569 | } | 550 | } |
@@ -596,7 +577,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
596 | (int)i, lineno, (unsigned long long)addr); | 577 | (int)i, lineno, (unsigned long long)addr); |
597 | pf->addr = addr; | 578 | pf->addr = addr; |
598 | 579 | ||
599 | show_probe_point(sp_die, pf); | 580 | convert_probe_point(sp_die, pf); |
600 | /* Continuing, because target line might be inlined. */ | 581 | /* Continuing, because target line might be inlined. */ |
601 | } | 582 | } |
602 | /* TODO: deallocate lines, but how? */ | 583 | /* TODO: deallocate lines, but how? */ |
@@ -605,7 +586,7 @@ static void find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
605 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 586 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
606 | { | 587 | { |
607 | struct probe_finder *pf = (struct probe_finder *)data; | 588 | struct probe_finder *pf = (struct probe_finder *)data; |
608 | struct probe_point *pp = pf->pp; | 589 | struct perf_probe_point *pp = &pf->pev->point; |
609 | 590 | ||
610 | if (pp->lazy_line) | 591 | if (pp->lazy_line) |
611 | find_probe_point_lazy(in_die, pf); | 592 | find_probe_point_lazy(in_die, pf); |
@@ -616,7 +597,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | |||
616 | pr_debug("found inline addr: 0x%jx\n", | 597 | pr_debug("found inline addr: 0x%jx\n", |
617 | (uintmax_t)pf->addr); | 598 | (uintmax_t)pf->addr); |
618 | 599 | ||
619 | show_probe_point(in_die, pf); | 600 | convert_probe_point(in_die, pf); |
620 | } | 601 | } |
621 | 602 | ||
622 | return DWARF_CB_OK; | 603 | return DWARF_CB_OK; |
@@ -626,7 +607,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | |||
626 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 607 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
627 | { | 608 | { |
628 | struct probe_finder *pf = (struct probe_finder *)data; | 609 | struct probe_finder *pf = (struct probe_finder *)data; |
629 | struct probe_point *pp = pf->pp; | 610 | struct perf_probe_point *pp = &pf->pev->point; |
630 | 611 | ||
631 | /* Check tag and diename */ | 612 | /* Check tag and diename */ |
632 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || | 613 | if (dwarf_tag(sp_die) != DW_TAG_subprogram || |
@@ -646,7 +627,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
646 | pf->addr = die_get_entrypc(sp_die); | 627 | pf->addr = die_get_entrypc(sp_die); |
647 | pf->addr += pp->offset; | 628 | pf->addr += pp->offset; |
648 | /* TODO: Check the address in this function */ | 629 | /* TODO: Check the address in this function */ |
649 | show_probe_point(sp_die, pf); | 630 | convert_probe_point(sp_die, pf); |
650 | } | 631 | } |
651 | } else | 632 | } else |
652 | /* Inlined function: search instances */ | 633 | /* Inlined function: search instances */ |
@@ -660,20 +641,25 @@ static void find_probe_point_by_func(struct probe_finder *pf) | |||
660 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); | 641 | dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, pf, 0); |
661 | } | 642 | } |
662 | 643 | ||
663 | /* Find a probe point */ | 644 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ |
664 | int find_probe_point(int fd, struct probe_point *pp) | 645 | int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, |
646 | struct kprobe_trace_event **tevs) | ||
665 | { | 647 | { |
666 | struct probe_finder pf = {.pp = pp}; | 648 | struct probe_finder pf = {.pev = pev}; |
649 | struct perf_probe_point *pp = &pev->point; | ||
667 | Dwarf_Off off, noff; | 650 | Dwarf_Off off, noff; |
668 | size_t cuhl; | 651 | size_t cuhl; |
669 | Dwarf_Die *diep; | 652 | Dwarf_Die *diep; |
670 | Dwarf *dbg; | 653 | Dwarf *dbg; |
671 | 654 | ||
655 | pf.tevs = xzalloc(sizeof(struct kprobe_trace_event) * MAX_PROBES); | ||
656 | *tevs = pf.tevs; | ||
657 | pf.ntevs = 0; | ||
658 | |||
672 | dbg = dwarf_begin(fd, DWARF_C_READ); | 659 | dbg = dwarf_begin(fd, DWARF_C_READ); |
673 | if (!dbg) | 660 | if (!dbg) |
674 | return -ENOENT; | 661 | return -ENOENT; |
675 | 662 | ||
676 | pp->found = 0; | ||
677 | off = 0; | 663 | off = 0; |
678 | line_list__init(&pf.lcache); | 664 | line_list__init(&pf.lcache); |
679 | /* Loop on CUs (Compilation Unit) */ | 665 | /* Loop on CUs (Compilation Unit) */ |
@@ -704,7 +690,7 @@ int find_probe_point(int fd, struct probe_point *pp) | |||
704 | line_list__free(&pf.lcache); | 690 | line_list__free(&pf.lcache); |
705 | dwarf_end(dbg); | 691 | dwarf_end(dbg); |
706 | 692 | ||
707 | return pp->found; | 693 | return pf.ntevs; |
708 | } | 694 | } |
709 | 695 | ||
710 | /* Find line range from its line number */ | 696 | /* Find line range from its line number */ |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index 21f7354397b4..494952619b9c 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -3,6 +3,7 @@ | |||
3 | 3 | ||
4 | #include <stdbool.h> | 4 | #include <stdbool.h> |
5 | #include "util.h" | 5 | #include "util.h" |
6 | #include "probe-event.h" | ||
6 | 7 | ||
7 | #define MAX_PATH_LEN 256 | 8 | #define MAX_PATH_LEN 256 |
8 | #define MAX_PROBE_BUFFER 1024 | 9 | #define MAX_PROBE_BUFFER 1024 |
@@ -14,67 +15,32 @@ static inline int is_c_varname(const char *name) | |||
14 | return isalpha(name[0]) || name[0] == '_'; | 15 | return isalpha(name[0]) || name[0] == '_'; |
15 | } | 16 | } |
16 | 17 | ||
17 | struct probe_point { | ||
18 | char *event; /* Event name */ | ||
19 | char *group; /* Event group */ | ||
20 | |||
21 | /* Inputs */ | ||
22 | char *file; /* File name */ | ||
23 | int line; /* Line number */ | ||
24 | char *lazy_line; /* Lazy line pattern */ | ||
25 | |||
26 | char *function; /* Function name */ | ||
27 | int offset; /* Offset bytes */ | ||
28 | |||
29 | int nr_args; /* Number of arguments */ | ||
30 | char **args; /* Arguments */ | ||
31 | |||
32 | int retprobe; /* Return probe */ | ||
33 | |||
34 | /* Output */ | ||
35 | int found; /* Number of found probe points */ | ||
36 | char *probes[MAX_PROBES]; /* Output buffers (will be allocated)*/ | ||
37 | }; | ||
38 | |||
39 | /* Line number container */ | ||
40 | struct line_node { | ||
41 | struct list_head list; | ||
42 | unsigned int line; | ||
43 | }; | ||
44 | |||
45 | /* Line range */ | ||
46 | struct line_range { | ||
47 | char *file; /* File name */ | ||
48 | char *function; /* Function name */ | ||
49 | unsigned int start; /* Start line number */ | ||
50 | unsigned int end; /* End line number */ | ||
51 | int offset; /* Start line offset */ | ||
52 | char *path; /* Real path name */ | ||
53 | struct list_head line_list; /* Visible lines */ | ||
54 | }; | ||
55 | |||
56 | #ifndef NO_DWARF_SUPPORT | 18 | #ifndef NO_DWARF_SUPPORT |
57 | extern int find_probe_point(int fd, struct probe_point *pp); | 19 | /* Find kprobe_trace_events specified by perf_probe_event from debuginfo */ |
20 | extern int find_kprobe_trace_events(int fd, struct perf_probe_event *pev, | ||
21 | struct kprobe_trace_event **tevs); | ||
22 | |||
58 | extern int find_line_range(int fd, struct line_range *lr); | 23 | extern int find_line_range(int fd, struct line_range *lr); |
59 | 24 | ||
60 | #include <dwarf.h> | 25 | #include <dwarf.h> |
61 | #include <libdw.h> | 26 | #include <libdw.h> |
62 | 27 | ||
63 | struct probe_finder { | 28 | struct probe_finder { |
64 | struct probe_point *pp; /* Target probe point */ | 29 | struct perf_probe_event *pev; /* Target probe event */ |
30 | int ntevs; /* number of trace events */ | ||
31 | struct kprobe_trace_event *tevs; /* Result trace events */ | ||
65 | 32 | ||
66 | /* For function searching */ | 33 | /* For function searching */ |
67 | Dwarf_Addr addr; /* Address */ | 34 | Dwarf_Addr addr; /* Address */ |
68 | const char *fname; /* File name */ | 35 | const char *fname; /* Real file name */ |
69 | int lno; /* Line number */ | 36 | int lno; /* Line number */ |
70 | Dwarf_Die cu_die; /* Current CU */ | 37 | Dwarf_Die cu_die; /* Current CU */ |
38 | struct list_head lcache; /* Line cache for lazy match */ | ||
71 | 39 | ||
72 | /* For variable searching */ | 40 | /* For variable searching */ |
73 | Dwarf_Op *fb_ops; /* Frame base attribute */ | 41 | Dwarf_Op *fb_ops; /* Frame base attribute */ |
74 | const char *var; /* Current variable name */ | 42 | struct perf_probe_arg *pvar; /* Current target variable */ |
75 | char *buf; /* Current output buffer */ | 43 | struct kprobe_trace_arg *tvar; /* Current result variable */ |
76 | int len; /* Length of output buffer */ | ||
77 | struct list_head lcache; /* Line cache for lazy match */ | ||
78 | }; | 44 | }; |
79 | 45 | ||
80 | struct line_finder { | 46 | struct line_finder { |