perf probe: Attempt to improve C++ probing
cover perf probe: Attempt to improve C++ probing
From: Holger Hans Peter Freyther <[email protected]>
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"
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(-)
Signature · 1 line
2.7.4
RFC 1/6 perf probe: Do not exclude mangled C++ funcs
From: Holger Hans Peter Freyther <[email protected]>
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 ...
--- tools/perf/builtin-probe.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
tools/perf/builtin-probe.c +1 -1
@@ -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 */
Signature · 1 line
2.7.4
RFC 2/6 perf probe: Parse linerange for C++ functions
In reply to Holger FreytherFrom: Holger Hans Peter Freyther <[email protected]>
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"
--- tools/perf/util/probe-event.c | 57 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-)
tools/perf/util/probe-event.c +56 -1
@@ -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 ;
Signature · 1 line
2.7.4
RFC 3/6 perf probe: Make listing of C++ functions work
In reply to Holger FreytherFrom: Holger Hans Peter Freyther <[email protected]>
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];--- tools/perf/util/probe-finder.c | 55 ++++++++++++++++++++++++++++++++++-------- tools/perf/util/probe-finder.h | 3 +++ 2 files changed, 48 insertions(+), 10 deletions(-)
tools/perf/util/probe-finder.c +45 -10
@@ -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;
tools/perf/util/probe-finder.h +3 -0
@@ -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 */
Signature · 1 line
2.7.4
RFC 4/6 perf probe: Show variables for C++ functions
In reply to Holger FreytherFrom: Holger Hans Peter Freyther <[email protected]>
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--- 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(-)
tools/perf/util/probe-event.c +18 -2
@@ -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 ;
tools/perf/util/string.c +57 -0
69 lines not on this page · raw message
tools/perf/util/string2.h +1 -0
@@ -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);
Signature · 1 line
2.7.4
RFC 5/6 perf probe: Make listing of variables work for C++ functions
In reply to Holger FreytherFrom: Holger Hans Peter Freyther <[email protected]>
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--- tools/perf/util/probe-finder.c | 88 +++++++++++++++++++++++++++--------------- 1 file changed, 56 insertions(+), 32 deletions(-)
tools/perf/util/probe-finder.c +56 -32
@@ -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};
Signature · 1 line
2.7.4
RFC 6/6 perf probe: Make it possible to add a C++ uprobe
In reply to Holger FreytherFrom: Holger Hans Peter Freyther <[email protected]>
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
--- tools/perf/util/probe-finder.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
tools/perf/util/probe-finder.c +11 -0
@@ -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 ;
Signature · 1 line
2.7.4
Hi Holger,
Thank you for your great work!
Quoted 22 lines · On Mon, 14 May 2018 12:19:34 +0800 Holger Freyther…
From: Holger Hans Peter Freyther <[email protected]>
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_FILTERto not include mangled C++ symbols. The remaining tooling would work then.This has seen very little testing outside the following commands.
Quoted 8 lines
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.
Quoted 21 lines
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++ uprobetools/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(-)Signature · 1 line
2.7.4
Signature · 1 line
Masami Hiramatsu <[email protected]>
Quoted 22 lines · On Mon, 14 May 2018 12:19:34 +0800 Holger Freyther…
From: Holger Hans Peter Freyther <[email protected]>
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_FILTERto not include mangled C++ symbols. The remaining tooling would work then.This has seen very little testing outside the following commands.
Quoted 8 lines
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 :)
for this series.
Arnaldo, could you pull this series?
Thank you!
Signature · 1 line
Masami Hiramatsu <[email protected]>
Arnaldo Carvalho de Melo
maintainerEm Mon, May 14, 2018 at 10:31:07PM +0900, Masami Hiramatsu escreveu:
Quoted 9 lines · On Mon, 14 May 2018 12:19:34 +0800 Holger Freyther…
Quoted 1 line
./perf probe -x . -V "std::vector<int, std::allocator<int> >::size%return"
OK, this series looks good to me :)
Acked-by Masami Hiramatsu <[email protected]>for this series.
Arnaldo, could you pull this series?
Sure, I'm just waiting for Holger to comment on Namhyung points,
Thanks,
- Arnaldo