diff options
| author | Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> | 2011-08-11 07:03:11 -0400 |
|---|---|---|
| committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2011-08-12 08:32:10 -0400 |
| commit | db0d2c6420eeb8fd669bac84d72f1ab828bbaa64 (patch) | |
| tree | da076fa408f501005fc851a28bbade134ad4ca62 | |
| parent | f182e3e13ca71b64b40fab1aef31fa6a78271648 (diff) | |
perf probe: Search concrete out-of-line instances
gcc 4.6 generates a concrete out-of-line instance when there is a
function which is implicitly inlined somewhere but also has its own
instance. The concrete out-of-line instance means that it has an
abstract origin of the function which is referred by not only
inlined-subroutines but also a concrete subprogram.
Since current dwarf_func_inline_instances() can find only instances of
inlined-subroutines, this introduces new die_walk_instances() to find
both of subprogram and inlined-subroutines.
e.g. without this,
Available variables at sched_group_rt_period
@<cpu_rt_period_read_uint+9>
struct task_group* tg
perf probe failed to find actual subprogram instance of
sched_group_rt_period().
With this,
Available variables at sched_group_rt_period
@<cpu_rt_period_read_uint+9>
struct task_group* tg
@<sched_group_rt_period+0>
struct task_group* tg
Now it found the sched_group_rt_period() itself.
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Pekka Enberg <penberg@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: yrl.pp-manager.tt@hitachi.com
Link: http://lkml.kernel.org/r/20110811110311.19900.63997.stgit@fedora15
Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com>
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
| -rw-r--r-- | tools/perf/util/dwarf-aux.c | 58 | ||||
| -rw-r--r-- | tools/perf/util/dwarf-aux.h | 4 | ||||
| -rw-r--r-- | tools/perf/util/probe-finder.c | 56 |
3 files changed, 83 insertions, 35 deletions
diff --git a/tools/perf/util/dwarf-aux.c b/tools/perf/util/dwarf-aux.c index 425703a58638..d0f4048b634f 100644 --- a/tools/perf/util/dwarf-aux.c +++ b/tools/perf/util/dwarf-aux.c | |||
| @@ -453,6 +453,64 @@ Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | |||
| 453 | return die_mem; | 453 | return die_mem; |
| 454 | } | 454 | } |
| 455 | 455 | ||
| 456 | struct __instance_walk_param { | ||
| 457 | void *addr; | ||
| 458 | int (*callback)(Dwarf_Die *, void *); | ||
| 459 | void *data; | ||
| 460 | int retval; | ||
| 461 | }; | ||
| 462 | |||
| 463 | static int __die_walk_instances_cb(Dwarf_Die *inst, void *data) | ||
| 464 | { | ||
| 465 | struct __instance_walk_param *iwp = data; | ||
| 466 | Dwarf_Attribute attr_mem; | ||
| 467 | Dwarf_Die origin_mem; | ||
| 468 | Dwarf_Attribute *attr; | ||
| 469 | Dwarf_Die *origin; | ||
| 470 | |||
| 471 | attr = dwarf_attr(inst, DW_AT_abstract_origin, &attr_mem); | ||
| 472 | if (attr == NULL) | ||
| 473 | return DIE_FIND_CB_CONTINUE; | ||
| 474 | |||
| 475 | origin = dwarf_formref_die(attr, &origin_mem); | ||
| 476 | if (origin == NULL || origin->addr != iwp->addr) | ||
| 477 | return DIE_FIND_CB_CONTINUE; | ||
| 478 | |||
| 479 | iwp->retval = iwp->callback(inst, iwp->data); | ||
| 480 | |||
| 481 | return (iwp->retval) ? DIE_FIND_CB_END : DIE_FIND_CB_CONTINUE; | ||
| 482 | } | ||
| 483 | |||
| 484 | /** | ||
| 485 | * die_walk_instances - Walk on instances of given DIE | ||
| 486 | * @or_die: an abstract original DIE | ||
| 487 | * @callback: a callback function which is called with instance DIE | ||
| 488 | * @data: user data | ||
| 489 | * | ||
| 490 | * Walk on the instances of give @in_die. @in_die must be an inlined function | ||
| 491 | * declartion. This returns the return value of @callback if it returns | ||
| 492 | * non-zero value, or -ENOENT if there is no instance. | ||
| 493 | */ | ||
| 494 | int die_walk_instances(Dwarf_Die *or_die, int (*callback)(Dwarf_Die *, void *), | ||
| 495 | void *data) | ||
| 496 | { | ||
| 497 | Dwarf_Die cu_die; | ||
| 498 | Dwarf_Die die_mem; | ||
| 499 | struct __instance_walk_param iwp = { | ||
| 500 | .addr = or_die->addr, | ||
| 501 | .callback = callback, | ||
| 502 | .data = data, | ||
| 503 | .retval = -ENOENT, | ||
| 504 | }; | ||
| 505 | |||
| 506 | if (dwarf_diecu(or_die, &cu_die, NULL, NULL) == NULL) | ||
| 507 | return -ENOENT; | ||
| 508 | |||
| 509 | die_find_child(&cu_die, __die_walk_instances_cb, &iwp, &die_mem); | ||
| 510 | |||
| 511 | return iwp.retval; | ||
| 512 | } | ||
| 513 | |||
| 456 | /* Line walker internal parameters */ | 514 | /* Line walker internal parameters */ |
| 457 | struct __line_walk_param { | 515 | struct __line_walk_param { |
| 458 | bool recursive; | 516 | bool recursive; |
diff --git a/tools/perf/util/dwarf-aux.h b/tools/perf/util/dwarf-aux.h index 6f46106fd1d5..6ce1717784b7 100644 --- a/tools/perf/util/dwarf-aux.h +++ b/tools/perf/util/dwarf-aux.h | |||
| @@ -80,6 +80,10 @@ extern Dwarf_Die *die_find_realfunc(Dwarf_Die *cu_die, Dwarf_Addr addr, | |||
| 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
| 81 | Dwarf_Die *die_mem); | 81 | Dwarf_Die *die_mem); |
| 82 | 82 | ||
| 83 | /* Walk on the instances of given DIE */ | ||
| 84 | extern int die_walk_instances(Dwarf_Die *in_die, | ||
| 85 | int (*callback)(Dwarf_Die *, void *), void *data); | ||
| 86 | |||
| 83 | /* Walker on lines (Note: line number will not be sorted) */ | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
| 84 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
| 85 | Dwarf_Addr addr, void *data); | 89 | Dwarf_Addr addr, void *data); |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 114542a5a99c..555fc3864b90 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
| @@ -924,42 +924,39 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf) | |||
| 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); | 924 | return die_walk_lines(sp_die, probe_point_lazy_walker, pf); |
| 925 | } | 925 | } |
| 926 | 926 | ||
| 927 | /* Callback parameter with return value */ | ||
| 928 | struct dwarf_callback_param { | ||
| 929 | void *data; | ||
| 930 | int retval; | ||
| 931 | }; | ||
| 932 | |||
| 933 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
| 934 | { | 928 | { |
| 935 | struct dwarf_callback_param *param = data; | 929 | struct probe_finder *pf = data; |
| 936 | struct probe_finder *pf = param->data; | ||
| 937 | struct perf_probe_point *pp = &pf->pev->point; | 930 | struct perf_probe_point *pp = &pf->pev->point; |
| 938 | Dwarf_Addr addr; | 931 | Dwarf_Addr addr; |
| 932 | int ret; | ||
| 939 | 933 | ||
| 940 | if (pp->lazy_line) | 934 | if (pp->lazy_line) |
| 941 | param->retval = find_probe_point_lazy(in_die, pf); | 935 | ret = find_probe_point_lazy(in_die, pf); |
| 942 | else { | 936 | else { |
| 943 | /* Get probe address */ | 937 | /* Get probe address */ |
| 944 | if (dwarf_entrypc(in_die, &addr) != 0) { | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
| 945 | pr_warning("Failed to get entry address of %s.\n", | 939 | pr_warning("Failed to get entry address of %s.\n", |
| 946 | dwarf_diename(in_die)); | 940 | dwarf_diename(in_die)); |
| 947 | param->retval = -ENOENT; | 941 | return -ENOENT; |
| 948 | return DWARF_CB_ABORT; | ||
| 949 | } | 942 | } |
| 950 | pf->addr = addr; | 943 | pf->addr = addr; |
| 951 | pf->addr += pp->offset; | 944 | pf->addr += pp->offset; |
| 952 | pr_debug("found inline addr: 0x%jx\n", | 945 | pr_debug("found inline addr: 0x%jx\n", |
| 953 | (uintmax_t)pf->addr); | 946 | (uintmax_t)pf->addr); |
| 954 | 947 | ||
| 955 | param->retval = call_probe_finder(in_die, pf); | 948 | ret = call_probe_finder(in_die, pf); |
| 956 | if (param->retval < 0) | ||
| 957 | return DWARF_CB_ABORT; | ||
| 958 | } | 949 | } |
| 959 | 950 | ||
| 960 | return DWARF_CB_OK; | 951 | return ret; |
| 961 | } | 952 | } |
| 962 | 953 | ||
| 954 | /* Callback parameter with return value for libdw */ | ||
| 955 | struct dwarf_callback_param { | ||
| 956 | void *data; | ||
| 957 | int retval; | ||
| 958 | }; | ||
| 959 | |||
| 963 | /* Search function from function name */ | 960 | /* Search function from function name */ |
| 964 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
| 965 | { | 962 | { |
| @@ -996,14 +993,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 996 | /* TODO: Check the address in this function */ | 993 | /* TODO: Check the address in this function */ |
| 997 | param->retval = call_probe_finder(sp_die, pf); | 994 | param->retval = call_probe_finder(sp_die, pf); |
| 998 | } | 995 | } |
| 999 | } else { | 996 | } else |
| 1000 | struct dwarf_callback_param _param = {.data = (void *)pf, | ||
| 1001 | .retval = 0}; | ||
| 1002 | /* Inlined function: search instances */ | 997 | /* Inlined function: search instances */ |
| 1003 | dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | 998 | param->retval = die_walk_instances(sp_die, |
| 1004 | &_param); | 999 | probe_point_inline_cb, (void *)pf); |
| 1005 | param->retval = _param.retval; | ||
| 1006 | } | ||
| 1007 | 1000 | ||
| 1008 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
| 1009 | } | 1002 | } |
| @@ -1452,16 +1445,14 @@ static int find_line_range_by_line(Dwarf_Die *sp_die, struct line_finder *lf) | |||
| 1452 | 1445 | ||
| 1453 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) | 1446 | static int line_range_inline_cb(Dwarf_Die *in_die, void *data) |
| 1454 | { | 1447 | { |
| 1455 | struct dwarf_callback_param *param = data; | 1448 | find_line_range_by_line(in_die, data); |
| 1456 | |||
| 1457 | param->retval = find_line_range_by_line(in_die, param->data); | ||
| 1458 | 1449 | ||
| 1459 | /* | 1450 | /* |
| 1460 | * We have to check all instances of inlined function, because | 1451 | * We have to check all instances of inlined function, because |
| 1461 | * some execution paths can be optimized out depends on the | 1452 | * some execution paths can be optimized out depends on the |
| 1462 | * function argument of instances | 1453 | * function argument of instances |
| 1463 | */ | 1454 | */ |
| 1464 | return DWARF_CB_OK; | 1455 | return 0; |
| 1465 | } | 1456 | } |
| 1466 | 1457 | ||
| 1467 | /* Search function from function name */ | 1458 | /* Search function from function name */ |
| @@ -1489,15 +1480,10 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data) | |||
| 1489 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
| 1490 | lr->start = lf->lno_s; | 1481 | lr->start = lf->lno_s; |
| 1491 | lr->end = lf->lno_e; | 1482 | lr->end = lf->lno_e; |
| 1492 | if (dwarf_func_inline(sp_die)) { | 1483 | if (dwarf_func_inline(sp_die)) |
| 1493 | struct dwarf_callback_param _param; | 1484 | param->retval = die_walk_instances(sp_die, |
| 1494 | _param.data = (void *)lf; | 1485 | line_range_inline_cb, lf); |
| 1495 | _param.retval = 0; | 1486 | else |
| 1496 | dwarf_func_inline_instances(sp_die, | ||
| 1497 | line_range_inline_cb, | ||
| 1498 | &_param); | ||
| 1499 | param->retval = _param.retval; | ||
| 1500 | } else | ||
| 1501 | param->retval = find_line_range_by_line(sp_die, lf); | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
| 1502 | return DWARF_CB_ABORT; | 1488 | return DWARF_CB_ABORT; |
| 1503 | } | 1489 | } |
