Commit db0d2c6420eeb8fd669bac84d72f1ab828bbaa64
Committed by
Arnaldo Carvalho de Melo
1 parent
f182e3e13c
Exists in
master
and in
6 other branches
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>
Showing 3 changed files with 83 additions and 35 deletions Side-by-side Diff
tools/perf/util/dwarf-aux.c
... | ... | @@ -453,6 +453,64 @@ |
453 | 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 | 514 | /* Line walker internal parameters */ |
457 | 515 | struct __line_walk_param { |
458 | 516 | bool recursive; |
tools/perf/util/dwarf-aux.h
... | ... | @@ -80,6 +80,10 @@ |
80 | 80 | extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, |
81 | 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 | 87 | /* Walker on lines (Note: line number will not be sorted) */ |
84 | 88 | typedef int (* line_walk_callback_t) (const char *fname, int lineno, |
85 | 89 | Dwarf_Addr addr, void *data); |
tools/perf/util/probe-finder.c
... | ... | @@ -924,42 +924,39 @@ |
924 | 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 | 927 | static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) |
934 | 928 | { |
935 | - struct dwarf_callback_param *param = data; | |
936 | - struct probe_finder *pf = param->data; | |
929 | + struct probe_finder *pf = data; | |
937 | 930 | struct perf_probe_point *pp = &pf->pev->point; |
938 | 931 | Dwarf_Addr addr; |
932 | + int ret; | |
939 | 933 | |
940 | 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 | 936 | else { |
943 | 937 | /* Get probe address */ |
944 | 938 | if (dwarf_entrypc(in_die, &addr) != 0) { |
945 | 939 | pr_warning("Failed to get entry address of %s.\n", |
946 | 940 | dwarf_diename(in_die)); |
947 | - param->retval = -ENOENT; | |
948 | - return DWARF_CB_ABORT; | |
941 | + return -ENOENT; | |
949 | 942 | } |
950 | 943 | pf->addr = addr; |
951 | 944 | pf->addr += pp->offset; |
952 | 945 | pr_debug("found inline addr: 0x%jx\n", |
953 | 946 | (uintmax_t)pf->addr); |
954 | 947 | |
955 | - param->retval = call_probe_finder(in_die, pf); | |
956 | - if (param->retval < 0) | |
957 | - return DWARF_CB_ABORT; | |
948 | + ret = call_probe_finder(in_die, pf); | |
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 | 960 | /* Search function from function name */ |
964 | 961 | static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) |
965 | 962 | { |
966 | 963 | |
... | ... | @@ -996,14 +993,10 @@ |
996 | 993 | /* TODO: Check the address in this function */ |
997 | 994 | param->retval = call_probe_finder(sp_die, pf); |
998 | 995 | } |
999 | - } else { | |
1000 | - struct dwarf_callback_param _param = {.data = (void *)pf, | |
1001 | - .retval = 0}; | |
996 | + } else | |
1002 | 997 | /* Inlined function: search instances */ |
1003 | - dwarf_func_inline_instances(sp_die, probe_point_inline_cb, | |
1004 | - &_param); | |
1005 | - param->retval = _param.retval; | |
1006 | - } | |
998 | + param->retval = die_walk_instances(sp_die, | |
999 | + probe_point_inline_cb, (void *)pf); | |
1007 | 1000 | |
1008 | 1001 | return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */ |
1009 | 1002 | } |
1010 | 1003 | |
1011 | 1004 | |
... | ... | @@ -1452,16 +1445,14 @@ |
1452 | 1445 | |
1453 | 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 | 1449 | |
1457 | - param->retval = find_line_range_by_line(in_die, param->data); | |
1458 | - | |
1459 | 1450 | /* |
1460 | 1451 | * We have to check all instances of inlined function, because |
1461 | 1452 | * some execution paths can be optimized out depends on the |
1462 | 1453 | * function argument of instances |
1463 | 1454 | */ |
1464 | - return DWARF_CB_OK; | |
1455 | + return 0; | |
1465 | 1456 | } |
1466 | 1457 | |
1467 | 1458 | /* Search function from function name */ |
... | ... | @@ -1489,15 +1480,10 @@ |
1489 | 1480 | pr_debug("New line range: %d to %d\n", lf->lno_s, lf->lno_e); |
1490 | 1481 | lr->start = lf->lno_s; |
1491 | 1482 | lr->end = lf->lno_e; |
1492 | - if (dwarf_func_inline(sp_die)) { | |
1493 | - struct dwarf_callback_param _param; | |
1494 | - _param.data = (void *)lf; | |
1495 | - _param.retval = 0; | |
1496 | - dwarf_func_inline_instances(sp_die, | |
1497 | - line_range_inline_cb, | |
1498 | - &_param); | |
1499 | - param->retval = _param.retval; | |
1500 | - } else | |
1483 | + if (dwarf_func_inline(sp_die)) | |
1484 | + param->retval = die_walk_instances(sp_die, | |
1485 | + line_range_inline_cb, lf); | |
1486 | + else | |
1501 | 1487 | param->retval = find_line_range_by_line(sp_die, lf); |
1502 | 1488 | return DWARF_CB_ABORT; |
1503 | 1489 | } |