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 /tools | |
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>
Diffstat (limited to 'tools')
-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 | } |