aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2011-08-11 07:03:11 -0400
committerArnaldo Carvalho de Melo <acme@redhat.com>2011-08-12 08:32:10 -0400
commitdb0d2c6420eeb8fd669bac84d72f1ab828bbaa64 (patch)
treeda076fa408f501005fc851a28bbade134ad4ca62 /tools
parentf182e3e13ca71b64b40fab1aef31fa6a78271648 (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.c58
-rw-r--r--tools/perf/util/dwarf-aux.h4
-rw-r--r--tools/perf/util/probe-finder.c56
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
456struct __instance_walk_param {
457 void *addr;
458 int (*callback)(Dwarf_Die *, void *);
459 void *data;
460 int retval;
461};
462
463static 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 */
494int 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 */
457struct __line_walk_param { 515struct __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,
80extern Dwarf_Die *die_find_inlinefunc(Dwarf_Die *sp_die, Dwarf_Addr addr, 80extern 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 */
84extern 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) */
84typedef int (* line_walk_callback_t) (const char *fname, int lineno, 88typedef 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 */
928struct dwarf_callback_param {
929 void *data;
930 int retval;
931};
932
933static int probe_point_inline_cb(Dwarf_Die *in_die, void *data) 927static 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 */
955struct dwarf_callback_param {
956 void *data;
957 int retval;
958};
959
963/* Search function from function name */ 960/* Search function from function name */
964static int probe_point_search_cb(Dwarf_Die *sp_die, void *data) 961static 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
1453static int line_range_inline_cb(Dwarf_Die *in_die, void *data) 1446static 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 }