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/util/probe-finder.c | |
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/util/probe-finder.c')
-rw-r--r-- | tools/perf/util/probe-finder.c | 140 |
1 files changed, 63 insertions, 77 deletions
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 */ |