[RFC 5/6] perf probe: Make listing of variables work for C++ functions

From: Holger Freyther
Date: Mon May 14 2018 - 00:28:16 EST


From: Holger Hans Peter Freyther <holgar+kernel@xxxxxxxxxx>

Update call sites with die_match_name to call matches_demangled as well.
This requires to pass the struct debuginfo/struct dso to the callbacks
and modifies the closure/void *data parameter. For most functions this
will change the parameter from struct probe_finder to the generic struct
dwarf_callback_param.

$ ./perf probe -x ./foo -V "std::vector<int, std::allocator<int> >::at"
Available variables at std::vector<int, std::allocator<int> >::at
@<at+0>
size_type __n
vector<int, std::allocator<int> >* this

Signed-off-by: Holger Hans Peter Freyther <holgar+kernel@xxxxxxxxxx>
---
tools/perf/util/probe-finder.c | 88 +++++++++++++++++++++++++++---------------
1 file changed, 56 insertions(+), 32 deletions(-)

diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c73dccc..4ba4b18 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -760,6 +760,7 @@ struct find_scope_param {
int line;
int diff;
Dwarf_Die *die_mem;
+ struct debuginfo *dbg;
bool found;
};

@@ -777,7 +778,8 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
}
/* If the function name is given, that's what user expects */
if (fsp->function) {
- if (die_match_name(fn_die, fsp->function)) {
+ if (die_match_name(fn_die, fsp->function) ||
+ matches_demangled(fsp->dbg, fn_die, fsp->function)) {
memcpy(fsp->die_mem, fn_die, sizeof(Dwarf_Die));
fsp->found = true;
return 1;
@@ -795,8 +797,16 @@ static int find_best_scope_cb(Dwarf_Die *fn_die, void *data)
return 0;
}

+/* Callback parameter with return value for libdw */
+struct dwarf_callback_param {
+ void *data;
+ int retval;
+ struct debuginfo *dbg;
+};
+
/* Find an appropriate scope fits to given conditions */
-static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
+static Dwarf_Die *find_best_scope(struct debuginfo *dbg,
+ struct probe_finder *pf, Dwarf_Die *die_mem)
{
struct find_scope_param fsp = {
.function = pf->pev->point.function,
@@ -804,6 +814,7 @@ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
.line = pf->lno,
.diff = INT_MAX,
.die_mem = die_mem,
+ .dbg = dbg,
.found = false,
};

@@ -815,7 +826,8 @@ static Dwarf_Die *find_best_scope(struct probe_finder *pf, Dwarf_Die *die_mem)
static int probe_point_line_walker(const char *fname, int lineno,
Dwarf_Addr addr, void *data)
{
- struct probe_finder *pf = data;
+ struct dwarf_callback_param *param = data;
+ struct probe_finder *pf = param->data;
Dwarf_Die *sc_die, die_mem;
int ret;

@@ -823,7 +835,7 @@ static int probe_point_line_walker(const char *fname, int lineno,
return 0;

pf->addr = addr;
- sc_die = find_best_scope(pf, &die_mem);
+ sc_die = find_best_scope(param->dbg, pf, &die_mem);
if (!sc_die) {
pr_warning("Failed to find scope of probe point.\n");
return -ENOENT;
@@ -836,9 +848,12 @@ static int probe_point_line_walker(const char *fname, int lineno,
}

/* Find probe point from its line number */
-static int find_probe_point_by_line(struct probe_finder *pf)
+static int find_probe_point_by_line(struct debuginfo *dbg,
+ struct probe_finder *pf)
{
- return die_walk_lines(&pf->cu_die, probe_point_line_walker, pf);
+ struct dwarf_callback_param param = {
+ .data = (void *)pf, .dbg = dbg, .retval = 0};
+ return die_walk_lines(&pf->cu_die, probe_point_line_walker, &param);
}

/* Find lines which match lazy pattern */
@@ -884,7 +899,8 @@ static int find_lazy_match_lines(struct intlist *list,
static int probe_point_lazy_walker(const char *fname, int lineno,
Dwarf_Addr addr, void *data)
{
- struct probe_finder *pf = data;
+ struct dwarf_callback_param *param = data;
+ struct probe_finder *pf = param->data;
Dwarf_Die *sc_die, die_mem;
int ret;

@@ -896,7 +912,7 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
lineno, (unsigned long long)addr);
pf->addr = addr;
pf->lno = lineno;
- sc_die = find_best_scope(pf, &die_mem);
+ sc_die = find_best_scope(param->dbg, pf, &die_mem);
if (!sc_die) {
pr_warning("Failed to find scope of probe point.\n");
return -ENOENT;
@@ -912,8 +928,10 @@ static int probe_point_lazy_walker(const char *fname, int lineno,
}

/* Find probe points from lazy pattern */
-static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
+static int find_probe_point_lazy(Dwarf_Die *sp_die,
+ struct dwarf_callback_param *param)
{
+ struct probe_finder *pf = param->data;
int ret = 0;
char *fpath;

@@ -935,7 +953,7 @@ static int find_probe_point_lazy(Dwarf_Die *sp_die, struct probe_finder *pf)
return ret;
}

- return die_walk_lines(sp_die, probe_point_lazy_walker, pf);
+ return die_walk_lines(sp_die, probe_point_lazy_walker, param);
}

static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)
@@ -972,13 +990,14 @@ static void skip_prologue(Dwarf_Die *sp_die, struct probe_finder *pf)

static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
{
- struct probe_finder *pf = data;
+ struct dwarf_callback_param *param = data;
+ struct probe_finder *pf = param->data;
struct perf_probe_point *pp = &pf->pev->point;
Dwarf_Addr addr;
int ret;

if (pp->lazy_line)
- ret = find_probe_point_lazy(in_die, pf);
+ ret = find_probe_point_lazy(in_die, param);
else {
/* Get probe address */
if (dwarf_entrypc(in_die, &addr) != 0) {
@@ -1002,13 +1021,6 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
return ret;
}

-/* Callback parameter with return value for libdw */
-struct dwarf_callback_param {
- void *data;
- int retval;
- struct debuginfo *dbg;
-};
-
/* Search function from function name */
static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
{
@@ -1018,7 +1030,8 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)

/* Check tag and diename */
if (!die_is_func_def(sp_die) ||
- !die_match_name(sp_die, pp->function))
+ (!die_match_name(sp_die, pp->function) &&
+ !matches_demangled(param->dbg, sp_die, pp->function)))
return DWARF_CB_OK;

/* Check declared file */
@@ -1031,7 +1044,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
if (pp->line) { /* Function relative line */
dwarf_decl_line(sp_die, &pf->lno);
pf->lno += pp->line;
- param->retval = find_probe_point_by_line(pf);
+ param->retval = find_probe_point_by_line(param->dbg, pf);
} else if (die_is_func_instance(sp_die)) {
/* Instances always have the entry address */
dwarf_entrypc(sp_die, &pf->addr);
@@ -1042,7 +1055,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
param->retval = 0;
/* Real function */
} else if (pp->lazy_line)
- param->retval = find_probe_point_lazy(sp_die, pf);
+ param->retval = find_probe_point_lazy(sp_die, param);
else {
skip_prologue(sp_die, pf);
pf->addr += pp->offset;
@@ -1052,7 +1065,7 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
} else if (!probe_conf.no_inlines) {
/* Inlined function: search instances */
param->retval = die_walk_instances(sp_die,
- probe_point_inline_cb, (void *)pf);
+ probe_point_inline_cb, data);
/* This could be a non-existed inline definition */
if (param->retval == -ENOENT)
param->retval = 0;
@@ -1067,9 +1080,10 @@ static int probe_point_search_cb(Dwarf_Die *sp_die, void *data)
return DWARF_CB_ABORT; /* Exit; no same symbol in this CU. */
}

-static int find_probe_point_by_func(struct probe_finder *pf)
+static int find_probe_point_by_func(struct debuginfo *dbg,
+ struct probe_finder *pf)
{
- struct dwarf_callback_param _param = {.data = (void *)pf,
+ struct dwarf_callback_param _param = {.data = (void *)pf, .dbg = dbg,
.retval = 0};
dwarf_getfuncs(&pf->cu_die, probe_point_search_cb, &_param, 0);
return _param.retval;
@@ -1080,6 +1094,7 @@ struct pubname_callback_param {
char *file;
Dwarf_Die *cu_die;
Dwarf_Die *sp_die;
+ struct debuginfo *dbg;
int found;
};

@@ -1091,7 +1106,9 @@ static int pubname_search_cb(Dwarf *dbg, Dwarf_Global *gl, void *data)
if (dwarf_tag(param->sp_die) != DW_TAG_subprogram)
return DWARF_CB_OK;

- if (die_match_name(param->sp_die, param->function)) {
+ if (die_match_name(param->sp_die, param->function) ||
+ matches_demangled(param->dbg, param->sp_die,
+ param->function)) {
if (!dwarf_offdie(dbg, gl->cu_offset, param->cu_die))
return DWARF_CB_OK;

@@ -1128,10 +1145,12 @@ static int debuginfo__find_probe_location(struct debuginfo *dbg,
.file = pp->file,
.cu_die = &pf->cu_die,
.sp_die = &pf->sp_die,
+ .dbg = dbg,
.found = 0,
};
struct dwarf_callback_param probe_param = {
.data = pf,
+ .dbg = dbg,
};

dwarf_getpubnames(dbg->dbg, pubname_search_cb,
@@ -1158,12 +1177,17 @@ static int debuginfo__find_probe_location(struct debuginfo *dbg,

if (!pp->file || pf->fname) {
if (pp->function)
- ret = find_probe_point_by_func(pf);
- else if (pp->lazy_line)
- ret = find_probe_point_lazy(&pf->cu_die, pf);
- else {
+ ret = find_probe_point_by_func(dbg, pf);
+ else if (pp->lazy_line) {
+ struct dwarf_callback_param probe_param = {
+ .data = pf,
+ .dbg = dbg,
+ };
+ ret = find_probe_point_lazy(&pf->cu_die,
+ &probe_param);
+ } else {
pf->lno = pp->line;
- ret = find_probe_point_by_line(pf);
+ ret = find_probe_point_by_line(dbg, pf);
}
if (ret < 0)
break;
@@ -1798,7 +1822,7 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
/* Fastpath: lookup by function name from .debug_pubnames section */
if (lr->function) {
struct pubname_callback_param pubname_param = {
- .function = lr->function, .file = lr->file,
+ .function = lr->function, .file = lr->file, .dbg = dbg,
.cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
struct dwarf_callback_param line_range_param = {
.data = (void *)&lf, .retval = 0, .dbg = dbg};
--
2.7.4