* [RFC 1/6] perf probe: Do not exclude mangled C++ funcs
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 4:19 ` [RFC 2/6] perf probe: Parse linerange for C++ functions Holger Freyther
` (6 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
Using --funcs --no-demangle on a C++ binary does not list any of the C++
functions. Change the default filter to not exclude the Common C++ ABI
symbols.
$ ./perf probe -x ./cxx-example --funcs --no-demangle
...
_ZN9__gnu_cxx13new_allocatorIiEC1Ev
...
Signed-off-by: Holger Hans Peter Freyther <holgar+kernel@google.com>
---
tools/perf/builtin-probe.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index c006592..d69f679 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -43,7 +43,7 @@
#include "util/probe-file.h"
#define DEFAULT_VAR_FILTER "!__k???tab_* & !__crc_*"
-#define DEFAULT_FUNC_FILTER "!_*"
+#define DEFAULT_FUNC_FILTER "!_* | _Z*"
#define DEFAULT_LIST_FILTER "*"
/* Session management structure */
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 2/6] perf probe: Parse linerange for C++ functions
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
2018-05-14 4:19 ` [RFC 1/6] perf probe: Do not exclude mangled C++ funcs Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 4:19 ` [RFC 3/6] perf probe: Make listing of C++ functions work Holger Freyther
` (5 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
perf probe --funcs will demangle C++ symbols by default but these
functions can not be used for listing sourcecode. Modify the scanner
to start searching for a line number only after a single ':'.
./perf probe -x ./cxx-example -L \
"std::vector<int, std::allocator<int> >::at:1"
Signed-off-by: Holger Hans Peter Freyther <holgar+kernel@google.com>
---
tools/perf/util/probe-event.c | 57 ++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 56 insertions(+), 1 deletion(-)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index e1dbc98..39a2d47 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1237,6 +1237,59 @@ static bool is_c_func_name(const char *name)
return true;
}
+/* Symbols in demangled CXX function names */
+static inline bool is_cxx_symbol(const char symbol)
+{
+ switch (symbol) {
+ case '_':
+ case ' ':
+ case '&':
+ case '*':
+ case '@':
+ case ',':
+ case ':':
+ case '<':
+ case '>':
+ case '(':
+ case ')':
+ return true;
+ default:
+ return false;
+ }
+}
+
+/* Is name a C++ name? */
+static bool is_cxx_func_name(const char *name)
+{
+ /* C name or a mangled name */
+ if (is_c_func_name(name))
+ return true;
+ while (*++name != '\0') {
+ if (!isalpha(*name) && !isdigit(*name) && !is_cxx_symbol(*name))
+ return false;
+ }
+ return true;
+}
+
+/*
+ * Find the first ':' that isn't part of a C++ namespace or class
+ * name.
+ */
+static char *first_non_cxx_ns(char *name)
+{
+ while (*name) {
+ char cur = *name, nxt = *(name + 1);
+
+ if (cur == ':' && nxt == ':')
+ name += 2;
+ else if (cur == ':')
+ return name;
+
+ name += 1;
+ }
+ return NULL;
+}
+
/*
* Stuff 'lr' according to the line range described by 'arg'.
* The line range syntax is described by:
@@ -1255,7 +1308,7 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
lr->start = 0;
lr->end = INT_MAX;
- range = strchr(name, ':');
+ range = first_non_cxx_ns(name);
if (range) {
*range++ = '\0';
@@ -1309,6 +1362,8 @@ int parse_line_range_desc(const char *arg, struct line_range *lr)
lr->file = name;
else if (is_c_func_name(name))/* We reuse it for checking funcname */
lr->function = name;
+ else if (is_cxx_func_name(name))
+ lr->function = name;
else { /* Invalid name */
semantic_error("'%s' is not a valid function name.\n", name);
err = -EINVAL;
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 3/6] perf probe: Make listing of C++ functions work
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
2018-05-14 4:19 ` [RFC 1/6] perf probe: Do not exclude mangled C++ funcs Holger Freyther
2018-05-14 4:19 ` [RFC 2/6] perf probe: Parse linerange for C++ functions Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 4:19 ` [RFC 4/6] perf probe: Show variables for C++ functions Holger Freyther
` (4 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
If die_match_name does not match, attempt to demangle the linkage name.
To use the generic demangling API we require to have a struct dso. Store
it inside the debuginfo and pass it to the relevant callbacks.
./perf probe -x ./foo -L \
"std::vector<int, std::allocator<int> >::at:2-3"
<...::at@/usr/include/c++/5/bits/stl_vector.h:2>
2 _M_range_check(__n);
3 return (*this)[__n];
Signed-off-by: Holger Hans Peter Freyther <holgar+kernel@google.com>
---
tools/perf/util/probe-finder.c | 55 ++++++++++++++++++++++++++++++++++--------
tools/perf/util/probe-finder.h | 3 +++
2 files changed, 48 insertions(+), 10 deletions(-)
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index c37fbef..c73dccc 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -96,7 +96,7 @@ static int debuginfo__init_offline_dwarf(struct debuginfo *dbg,
return -ENOENT;
}
-static struct debuginfo *__debuginfo__new(const char *path)
+static struct debuginfo *__debuginfo__new(const char *path, struct dso *dso)
{
struct debuginfo *dbg = zalloc(sizeof(*dbg));
if (!dbg)
@@ -104,8 +104,10 @@ static struct debuginfo *__debuginfo__new(const char *path)
if (debuginfo__init_offline_dwarf(dbg, path) < 0)
zfree(&dbg);
- if (dbg)
+ if (dbg) {
pr_debug("Open Debuginfo file: %s\n", path);
+ dbg->dso = dso__get(dso);
+ }
return dbg;
}
@@ -135,13 +137,15 @@ struct debuginfo *debuginfo__new(const char *path)
if (dso__read_binary_type_filename(dso, *type, &nil,
buf, PATH_MAX) < 0)
continue;
- dinfo = __debuginfo__new(buf);
+ dinfo = __debuginfo__new(buf, dso);
}
- dso__put(dso);
out:
/* if failed to open all distro debuginfo, open given binary */
- return dinfo ? : __debuginfo__new(path);
+ if (!dinfo)
+ dinfo = __debuginfo__new(path, dso);
+ dso__put(dso);
+ return dinfo;
}
void debuginfo__delete(struct debuginfo *dbg)
@@ -149,6 +153,7 @@ void debuginfo__delete(struct debuginfo *dbg)
if (dbg) {
if (dbg->dwfl)
dwfl_end(dbg->dwfl);
+ dso__put(dbg->dso);
free(dbg);
}
}
@@ -167,6 +172,32 @@ static struct probe_trace_arg_ref *alloc_trace_arg_ref(long offs)
}
/*
+ * Check if the the demangled linkage_name matches the function. E.g. the
+ * linkage name of _ZNKSt6vectorIiSaIiEE4sizeEv matching the c++ function name
+ * of std::vector<int, std::allocator<int> >::size() const.
+ */
+static bool matches_demangled(struct debuginfo *dbg, Dwarf_Die *dw_die,
+ const char *function)
+{
+ const char *name;
+ char *demangled;
+ bool res;
+
+ name = die_get_linkage_name(dw_die);
+ if (!name)
+ return false;
+
+ demangled = dso__demangle_sym(dbg->dso, 0, name);
+ if (!demangled)
+ return false;
+
+ res = strglobmatch(demangled, function);
+ free(demangled);
+ return res;
+}
+
+
+/*
* Convert a location into trace_arg.
* If tvar == NULL, this just checks variable can be converted.
* If fentry == true and vr_die is a parameter, do huristic search
@@ -975,6 +1006,7 @@ static int probe_point_inline_cb(Dwarf_Die *in_die, void *data)
struct dwarf_callback_param {
void *data;
int retval;
+ struct debuginfo *dbg;
};
/* Search function from function name */
@@ -1721,7 +1753,8 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
return DWARF_CB_OK;
if (die_is_func_def(sp_die) &&
- die_match_name(sp_die, lr->function)) {
+ (die_match_name(sp_die, lr->function) ||
+ matches_demangled(param->dbg, sp_die, lr->function))) {
lf->fname = dwarf_decl_file(sp_die);
dwarf_decl_line(sp_die, &lr->offset);
pr_debug("fname: %s, lineno:%d\n", lf->fname, lr->offset);
@@ -1744,9 +1777,11 @@ static int line_range_search_cb(Dwarf_Die *sp_die, void *data)
return DWARF_CB_OK;
}
-static int find_line_range_by_func(struct line_finder *lf)
+static int find_line_range_by_func(struct debuginfo *dbg,
+ struct line_finder *lf)
{
- struct dwarf_callback_param param = {.data = (void *)lf, .retval = 0};
+ struct dwarf_callback_param param = {
+ .data = (void *)lf, .retval = 0, .dbg = dbg};
dwarf_getfuncs(&lf->cu_die, line_range_search_cb, ¶m, 0);
return param.retval;
}
@@ -1766,7 +1801,7 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
.function = lr->function, .file = lr->file,
.cu_die = &lf.cu_die, .sp_die = &lf.sp_die, .found = 0};
struct dwarf_callback_param line_range_param = {
- .data = (void *)&lf, .retval = 0};
+ .data = (void *)&lf, .retval = 0, .dbg = dbg};
dwarf_getpubnames(dbg->dbg, pubname_search_cb,
&pubname_param, 0);
@@ -1796,7 +1831,7 @@ int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr)
if (!lr->file || lf.fname) {
if (lr->function)
- ret = find_line_range_by_func(&lf);
+ ret = find_line_range_by_func(dbg, &lf);
else {
lf.lno_s = lr->start;
lf.lno_e = lr->end;
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h
index 1625298..e28acbd 100644
--- a/tools/perf/util/probe-finder.h
+++ b/tools/perf/util/probe-finder.h
@@ -14,6 +14,8 @@
#define PROBE_ARG_VARS "$vars"
#define PROBE_ARG_PARAMS "$params"
+struct dso;
+
static inline int is_c_varname(const char *name)
{
/* TODO */
@@ -32,6 +34,7 @@ struct debuginfo {
Dwfl_Module *mod;
Dwfl *dwfl;
Dwarf_Addr bias;
+ struct dso *dso;
};
/* This also tries to open distro debuginfo */
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 4/6] perf probe: Show variables for C++ functions
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
` (2 preceding siblings ...)
2018-05-14 4:19 ` [RFC 3/6] perf probe: Make listing of C++ functions work Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 4:19 ` [RFC 5/6] perf probe: Make listing of variables work " Holger Freyther
` (3 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
The demangled C++ function name contains spaces and using the generic
argc_split would split the function in the middle. Create a separate
version that counts the number of opening and closing '<', '>' for
templated functions.
$ ./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@google.com>
---
tools/perf/util/probe-event.c | 20 +++++++++++++--
tools/perf/util/string.c | 57 +++++++++++++++++++++++++++++++++++++++++++
tools/perf/util/string2.h | 1 +
3 files changed, 76 insertions(+), 2 deletions(-)
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 39a2d47..97d6b6a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1407,6 +1407,22 @@ static int parse_perf_probe_event_name(char **arg, struct perf_probe_event *pev)
return 0;
}
+/* Split the function name from @file, :line, %return but be C++ aware */
+static char *split_func_name(char *arg)
+{
+ char *ptr = arg;
+
+ while ((ptr = strpbrk_esc(ptr, ";:+@%"))) {
+ if (ptr[0] == ':' && ptr[1] == ':') {
+ ptr += 2;
+ continue;
+ }
+ return ptr;
+ }
+
+ return NULL;
+}
+
/* Parse probepoint definition. */
static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
{
@@ -1486,7 +1502,7 @@ static int parse_perf_probe_point(char *arg, struct perf_probe_event *pev)
file_spec = true;
}
- ptr = strpbrk_esc(arg, ";:+@%");
+ ptr = split_func_name(arg);
if (ptr) {
nc = *ptr;
*ptr++ = '\0';
@@ -1726,7 +1742,7 @@ int parse_perf_probe_command(const char *cmd, struct perf_probe_event *pev)
char **argv;
int argc, i, ret = 0;
- argv = argv_split(cmd, &argc);
+ argv = argv_split_cxx(cmd, &argc);
if (!argv) {
pr_debug("Failed to split arguments.\n");
return -ENOMEM;
diff --git a/tools/perf/util/string.c b/tools/perf/util/string.c
index d8bfd0c..bb96fe2 100644
--- a/tools/perf/util/string.c
+++ b/tools/perf/util/string.c
@@ -80,6 +80,23 @@ static const char *skip_arg(const char *cp)
return cp;
}
+static const char *skip_arg_cxx(const char *cp)
+{
+ int tmpl = 0;
+
+ while (*cp) {
+ if (tmpl == 0 && isspace(*cp))
+ break;
+ if (*cp == '<')
+ tmpl += 1;
+ if (*cp == '>')
+ tmpl -= 1;
+ cp++;
+ }
+
+ return cp;
+}
+
static int count_argc(const char *str)
{
int count = 0;
@@ -163,6 +180,46 @@ char **argv_split(const char *str, int *argcp)
return NULL;
}
+char **argv_split_cxx(const char *str, int *argcp)
+{
+ int argc = count_argc(str);
+ char **argv = calloc(argc + 1, sizeof(*argv));
+ char **argvp;
+
+ if (argv == NULL)
+ goto out;
+
+ argvp = argv;
+
+ while (*str) {
+ str = skip_sep(str);
+
+ if (*str) {
+ const char *p = str;
+ char *t;
+
+ str = skip_arg_cxx(str);
+
+ t = strndup(p, str-p);
+ if (t == NULL)
+ goto fail;
+ *argvp++ = t;
+ }
+ }
+ if (argcp)
+ *argcp = argvp - argv;
+ *argvp = NULL;
+
+out:
+ return argv;
+
+fail:
+ if (argcp)
+ *argcp = 0;
+ argv_free(argv);
+ return NULL;
+}
+
/* Character class matching */
static bool __match_charclass(const char *pat, char c, const char **npat)
{
diff --git a/tools/perf/util/string2.h b/tools/perf/util/string2.h
index 4c68a09..d32de6f 100644
--- a/tools/perf/util/string2.h
+++ b/tools/perf/util/string2.h
@@ -8,6 +8,7 @@
s64 perf_atoll(const char *str);
char **argv_split(const char *str, int *argcp);
+char **argv_split_cxx(const char *str, int *argvcp);
void argv_free(char **argv);
bool strglobmatch(const char *str, const char *pat);
bool strglobmatch_nocase(const char *str, const char *pat);
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 5/6] perf probe: Make listing of variables work for C++ functions
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
` (3 preceding siblings ...)
2018-05-14 4:19 ` [RFC 4/6] perf probe: Show variables for C++ functions Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 4:19 ` [RFC 6/6] perf probe: Make it possible to add a C++ uprobe Holger Freyther
` (2 subsequent siblings)
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
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@google.com>
---
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, ¶m);
}
/* 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
^ permalink raw reply related [flat|nested] 11+ messages in thread* [RFC 6/6] perf probe: Make it possible to add a C++ uprobe
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
` (4 preceding siblings ...)
2018-05-14 4:19 ` [RFC 5/6] perf probe: Make listing of variables work " Holger Freyther
@ 2018-05-14 4:19 ` Holger Freyther
2018-05-14 13:08 ` [RFC 0/6] perf probe: Attempt to improve C++ probing Masami Hiramatsu
2018-05-14 13:31 ` Masami Hiramatsu
7 siblings, 0 replies; 11+ messages in thread
From: Holger Freyther @ 2018-05-14 4:19 UTC (permalink / raw)
To: linux-kernel; +Cc: Holger Hans Peter Freyther
From: Holger Hans Peter Freyther <holgar+kernel@google.com>
If the linkage name looks like a common C++ ABI name use it instead of
the original function name. This makes adding a uprobe for a C++ symbol
possible.
./perf probe -x ./cxx-example "std::vector<int, std::allocator<int> >::at"
Added new event:
probe_foo:_ZNSt6vectorIiSaIiEE2atEm (on _ZN... in /cxx-example)
You can now use it in all perf tools, such as:
perf record -e probe_foo:_ZNSt6vectorIiSaIiEE2atEm -aR sleep 1
Signed-off-by: Holger Hans Peter Freyther <holgar+kernel@google.com>
---
tools/perf/util/probe-finder.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c
index 4ba4b18..4cfa3de 100644
--- a/tools/perf/util/probe-finder.c
+++ b/tools/perf/util/probe-finder.c
@@ -1317,6 +1317,7 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
struct perf_probe_point *pp = &pf->pev->point;
struct probe_trace_event *tev;
struct perf_probe_arg *args = NULL;
+ const char *linkage_name;
int ret, i;
/* Check number of tevs */
@@ -1333,6 +1334,16 @@ static int add_probe_trace_event(Dwarf_Die *sc_die, struct probe_finder *pf)
if (ret < 0)
goto end;
+ /*
+ * Adding a C++ name like std::vector<int, std::allocator<int> >::at
+ * will fail. Check if we want to use the linkage name instead.
+ */
+ linkage_name = die_get_linkage_name(&pf->sp_die);
+ if (linkage_name && strncmp(linkage_name, "_Z", 2) == 0) {
+ free(pp->function);
+ pp->function = strdup(linkage_name);
+ }
+
tev->point.realname = strdup(dwarf_diename(sc_die));
if (!tev->point.realname) {
ret = -ENOMEM;
--
2.7.4
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [RFC 0/6] perf probe: Attempt to improve C++ probing
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
` (5 preceding siblings ...)
2018-05-14 4:19 ` [RFC 6/6] perf probe: Make it possible to add a C++ uprobe Holger Freyther
@ 2018-05-14 13:08 ` Masami Hiramatsu
2018-05-14 13:31 ` Masami Hiramatsu
7 siblings, 0 replies; 11+ messages in thread
From: Masami Hiramatsu @ 2018-05-14 13:08 UTC (permalink / raw)
To: Holger Freyther; +Cc: linux-kernel, Holger Hans Peter Freyther
Hi Holger,
Thank you for your great work!
On Mon, 14 May 2018 12:19:34 +0800
Holger Freyther <automatic+kernel@freyther.de> wrote:
> From: Holger Hans Peter Freyther <holgar+kernel@google.com>
>
> Currently perf probe -x app --funcs will list and demangle C++ functions
> but the other probe actions can't work with them. When asking probe to not
> demangle it will not list any of the application symbols creating the
> impression that there are no symbols at all.
>
> Make --funcs --no-demangle list all C++ functions and modify the handling
> for listing code, variables and adding the uprobe work with the demangled
> C++ function name.
>
> I tried to keep this as minimal as possible but having to keep the dso in
> the debuginfo and passing it everywhere to be able to demangle the linkage
> name isn't pretty (and for C++ demangling the struct dso is not of much
> use. Maybe having a static "empty" dso could avoid a lot of the changes).
>
> Maybe the easiest first patch is to default to --no-demangle and change
> the DEFAULT_FUNC_FILTER to not include mangled C++ symbols. The remaining
> tooling would work then.
>
> This has seen very little testing outside the following commands.
>
> My test set includes:
>
> ./perf probe -x . -L "std::vector<int, std::allocator<int> >::at"
> ./perf probe -x . -L "std::vector<int, std::allocator<int> >::at:2-3"
>
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::at"
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::at:2"
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::size%return"
OK, let me review it.
>
>
> Holger Hans Peter Freyther (6):
> perf probe: Do not exclude mangled C++ funcs
> perf probe: Parse linerange for C++ functions
> perf probe: Make listing of C++ functions work
> perf probe: Show variables for C++ functions
> perf probe: Make listing of variables work for C++ functions
> perf probe: Make it possible to add a C++ uprobe
>
> tools/perf/builtin-probe.c | 2 +-
> tools/perf/util/probe-event.c | 77 ++++++++++++++++++++-
> tools/perf/util/probe-finder.c | 152 ++++++++++++++++++++++++++++++-----------
> tools/perf/util/probe-finder.h | 3 +
> tools/perf/util/string.c | 57 ++++++++++++++++
> tools/perf/util/string2.h | 1 +
> 6 files changed, 247 insertions(+), 45 deletions(-)
>
> --
> 2.7.4
>
--
Masami Hiramatsu <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [RFC 0/6] perf probe: Attempt to improve C++ probing
2018-05-14 4:19 [RFC 0/6] perf probe: Attempt to improve C++ probing Holger Freyther
` (6 preceding siblings ...)
2018-05-14 13:08 ` [RFC 0/6] perf probe: Attempt to improve C++ probing Masami Hiramatsu
@ 2018-05-14 13:31 ` Masami Hiramatsu
2018-05-15 14:10 ` Arnaldo Carvalho de Melo
7 siblings, 1 reply; 11+ messages in thread
From: Masami Hiramatsu @ 2018-05-14 13:31 UTC (permalink / raw)
To: Holger Freyther, Arnaldo Carvalho de Melo
Cc: linux-kernel, Holger Hans Peter Freyther
On Mon, 14 May 2018 12:19:34 +0800
Holger Freyther <automatic+kernel@freyther.de> wrote:
> From: Holger Hans Peter Freyther <holgar+kernel@google.com>
>
> Currently perf probe -x app --funcs will list and demangle C++ functions
> but the other probe actions can't work with them. When asking probe to not
> demangle it will not list any of the application symbols creating the
> impression that there are no symbols at all.
>
> Make --funcs --no-demangle list all C++ functions and modify the handling
> for listing code, variables and adding the uprobe work with the demangled
> C++ function name.
>
> I tried to keep this as minimal as possible but having to keep the dso in
> the debuginfo and passing it everywhere to be able to demangle the linkage
> name isn't pretty (and for C++ demangling the struct dso is not of much
> use. Maybe having a static "empty" dso could avoid a lot of the changes).
>
> Maybe the easiest first patch is to default to --no-demangle and change
> the DEFAULT_FUNC_FILTER to not include mangled C++ symbols. The remaining
> tooling would work then.
>
> This has seen very little testing outside the following commands.
>
> My test set includes:
>
> ./perf probe -x . -L "std::vector<int, std::allocator<int> >::at"
> ./perf probe -x . -L "std::vector<int, std::allocator<int> >::at:2-3"
>
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::at"
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::at:2"
> ./perf probe -x . -V "std::vector<int, std::allocator<int> >::size%return"
OK, this series looks good to me :)
Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
for this series.
Arnaldo, could you pull this series?
Thank you!
--
Masami Hiramatsu <mhiramat@kernel.org>
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [RFC 0/6] perf probe: Attempt to improve C++ probing
2018-05-14 13:31 ` Masami Hiramatsu
@ 2018-05-15 14:10 ` Arnaldo Carvalho de Melo
0 siblings, 0 replies; 11+ messages in thread
From: Arnaldo Carvalho de Melo @ 2018-05-15 14:10 UTC (permalink / raw)
To: Masami Hiramatsu
Cc: Holger Freyther, linux-kernel, Holger Hans Peter Freyther
Em Mon, May 14, 2018 at 10:31:07PM +0900, Masami Hiramatsu escreveu:
> On Mon, 14 May 2018 12:19:34 +0800 Holger Freyther <automatic+kernel@freyther.de> wrote:
> > ./perf probe -x . -V "std::vector<int, std::allocator<int> >::size%return"
> OK, this series looks good to me :)
> Acked-by: Masami Hiramatsu <mhiramat@kernel.org>
> for this series.
> Arnaldo, could you pull this series?
Sure, I'm just waiting for Holger to comment on Namhyung points,
Thanks,
- Arnaldo
^ permalink raw reply [flat|nested] 11+ messages in thread