diff options
Diffstat (limited to 'tools/perf/util/probe-event.c')
-rw-r--r-- | tools/perf/util/probe-event.c | 626 |
1 files changed, 400 insertions, 226 deletions
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); |