aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2015-03-06 02:31:20 -0500
committerArnaldo Carvalho de Melo <acme@redhat.com>2015-03-12 11:39:52 -0400
commit9b118acae310f57baee770b5db402500d8695e50 (patch)
tree112249226fb4b48fecf3b95c49c2358e6f69d2f1 /tools
parent4a6b362f36e68618ee4d3cdb361d05a5e80af023 (diff)
perf probe: Fix to handle aliased symbols in glibc
Fix perf probe to handle aliased symbols correctly in glibc. In the glibc, several symbols are defined as an alias of __libc_XXX, e.g. malloc is an alias of __libc_malloc. In such cases, dwarf has no subroutine instances of the alias functions (e.g. no "malloc" instance), but the map has that symbol and its address. Thus, if we search the alieased symbol in debuginfo, we always fail to find it, but it is in the map. To solve this problem, this fails back to address-based alternative search, which searches the symbol in the map, translates its address to alternative (correct) function name by using debuginfo, and retry to find the alternative function point from debuginfo. This adds fail-back process to --vars, --lines and --add options. So, now you can use those on malloc@libc :) Without this patch; ----- # ./perf probe -x /usr/lib64/libc-2.17.so -V malloc Failed to find the address of malloc Error: Failed to show vars. # ./perf probe -x /usr/lib64/libc-2.17.so -a "malloc bytes" Probe point 'malloc' not found in debuginfo. Error: Failed to add events. ----- With this patch; ----- # ./perf probe -x /usr/lib64/libc-2.17.so -V malloc Available variables at malloc @<__libc_malloc+0> size_t bytes # ./perf probe -x /usr/lib64/libc-2.17.so -a "malloc bytes" Added new event: probe_libc:malloc (on malloc in /usr/lib64/libc-2.17.so with bytes) You can now use it in all perf tools, such as: perf record -e probe_libc:malloc -aR sleep 1 ----- Reported-by: Arnaldo Carvalho de Melo <acme@kernel.org> Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Cc: David Ahern <dsahern@gmail.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Naohiro Aota <naota@elisp.net> Cc: Peter Zijlstra <peterz@infradead.org> Link: http://lkml.kernel.org/r/20150306073120.6904.13779.stgit@localhost.localdomain Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/util/probe-event.c140
1 files changed, 124 insertions, 16 deletions
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index 1c570c2fa7cc..b8f45782126a 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -178,6 +178,25 @@ static struct map *kernel_get_module_map(const char *module)
178 return NULL; 178 return NULL;
179} 179}
180 180
181static struct map *get_target_map(const char *target, bool user)
182{
183 /* Init maps of given executable or kernel */
184 if (user)
185 return dso__new_map(target);
186 else
187 return kernel_get_module_map(target);
188}
189
190static void put_target_map(struct map *map, bool user)
191{
192 if (map && user) {
193 /* Only the user map needs to be released */
194 dso__delete(map->dso);
195 map__delete(map);
196 }
197}
198
199
181static struct dso *kernel_get_module_dso(const char *module) 200static struct dso *kernel_get_module_dso(const char *module)
182{ 201{
183 struct dso *dso; 202 struct dso *dso;
@@ -249,6 +268,13 @@ out:
249 return ret; 268 return ret;
250} 269}
251 270
271static void clear_perf_probe_point(struct perf_probe_point *pp)
272{
273 free(pp->file);
274 free(pp->function);
275 free(pp->lazy_line);
276}
277
252static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs) 278static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
253{ 279{
254 int i; 280 int i;
@@ -258,6 +284,74 @@ static void clear_probe_trace_events(struct probe_trace_event *tevs, int ntevs)
258} 284}
259 285
260#ifdef HAVE_DWARF_SUPPORT 286#ifdef HAVE_DWARF_SUPPORT
287/*
288 * Some binaries like glibc have special symbols which are on the symbol
289 * table, but not in the debuginfo. If we can find the address of the
290 * symbol from map, we can translate the address back to the probe point.
291 */
292static int find_alternative_probe_point(struct debuginfo *dinfo,
293 struct perf_probe_point *pp,
294 struct perf_probe_point *result,
295 const char *target, bool uprobes)
296{
297 struct map *map = NULL;
298 struct symbol *sym;
299 u64 address = 0;
300 int ret = -ENOENT;
301
302 /* This can work only for function-name based one */
303 if (!pp->function || pp->file)
304 return -ENOTSUP;
305
306 map = get_target_map(target, uprobes);
307 if (!map)
308 return -EINVAL;
309
310 /* Find the address of given function */
311 map__for_each_symbol_by_name(map, pp->function, sym) {
312 if (sym->binding == STB_GLOBAL || sym->binding == STB_LOCAL) {
313 address = sym->start;
314 break;
315 }
316 }
317 if (!address) {
318 ret = -ENOENT;
319 goto out;
320 }
321 pr_debug("Symbol %s address found : %lx\n", pp->function, address);
322
323 ret = debuginfo__find_probe_point(dinfo, (unsigned long)address,
324 result);
325 if (ret <= 0)
326 ret = (!ret) ? -ENOENT : ret;
327 else {
328 result->offset += pp->offset;
329 result->line += pp->line;
330 ret = 0;
331 }
332
333out:
334 put_target_map(map, uprobes);
335 return ret;
336
337}
338
339static int get_alternative_probe_event(struct debuginfo *dinfo,
340 struct perf_probe_event *pev,
341 struct perf_probe_point *tmp,
342 const char *target)
343{
344 int ret;
345
346 memcpy(tmp, &pev->point, sizeof(*tmp));
347 memset(&pev->point, 0, sizeof(pev->point));
348 ret = find_alternative_probe_point(dinfo, tmp, &pev->point,
349 target, pev->uprobes);
350 if (ret < 0)
351 memcpy(&pev->point, tmp, sizeof(*tmp));
352
353 return ret;
354}
261 355
262/* Open new debuginfo of given module */ 356/* Open new debuginfo of given module */
263static struct debuginfo *open_debuginfo(const char *module, bool silent) 357static struct debuginfo *open_debuginfo(const char *module, bool silent)
@@ -466,6 +560,7 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
466 int max_tevs, const char *target) 560 int max_tevs, const char *target)
467{ 561{
468 bool need_dwarf = perf_probe_event_need_dwarf(pev); 562 bool need_dwarf = perf_probe_event_need_dwarf(pev);
563 struct perf_probe_point tmp;
469 struct debuginfo *dinfo; 564 struct debuginfo *dinfo;
470 int ntevs, ret = 0; 565 int ntevs, ret = 0;
471 566
@@ -482,6 +577,20 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev,
482 /* Searching trace events corresponding to a probe event */ 577 /* Searching trace events corresponding to a probe event */
483 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs); 578 ntevs = debuginfo__find_trace_events(dinfo, pev, tevs, max_tevs);
484 579
580 if (ntevs == 0) { /* Not found, retry with an alternative */
581 ret = get_alternative_probe_event(dinfo, pev, &tmp, target);
582 if (!ret) {
583 ntevs = debuginfo__find_trace_events(dinfo, pev,
584 tevs, max_tevs);
585 /*
586 * Write back to the original probe_event for
587 * setting appropriate (user given) event name
588 */
589 clear_perf_probe_point(&pev->point);
590 memcpy(&pev->point, &tmp, sizeof(tmp));
591 }
592 }
593
485 debuginfo__delete(dinfo); 594 debuginfo__delete(dinfo);
486 595
487 if (ntevs > 0) { /* Succeeded to find trace events */ 596 if (ntevs > 0) { /* Succeeded to find trace events */
@@ -719,12 +828,13 @@ int show_line_range(struct line_range *lr, const char *module, bool user)
719static int show_available_vars_at(struct debuginfo *dinfo, 828static int show_available_vars_at(struct debuginfo *dinfo,
720 struct perf_probe_event *pev, 829 struct perf_probe_event *pev,
721 int max_vls, struct strfilter *_filter, 830 int max_vls, struct strfilter *_filter,
722 bool externs) 831 bool externs, const char *target)
723{ 832{
724 char *buf; 833 char *buf;
725 int ret, i, nvars; 834 int ret, i, nvars;
726 struct str_node *node; 835 struct str_node *node;
727 struct variable_list *vls = NULL, *vl; 836 struct variable_list *vls = NULL, *vl;
837 struct perf_probe_point tmp;
728 const char *var; 838 const char *var;
729 839
730 buf = synthesize_perf_probe_point(&pev->point); 840 buf = synthesize_perf_probe_point(&pev->point);
@@ -734,6 +844,15 @@ static int show_available_vars_at(struct debuginfo *dinfo,
734 844
735 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls, 845 ret = debuginfo__find_available_vars_at(dinfo, pev, &vls,
736 max_vls, externs); 846 max_vls, externs);
847 if (!ret) { /* Not found, retry with an alternative */
848 ret = get_alternative_probe_event(dinfo, pev, &tmp, target);
849 if (!ret) {
850 ret = debuginfo__find_available_vars_at(dinfo, pev,
851 &vls, max_vls, externs);
852 /* Release the old probe_point */
853 clear_perf_probe_point(&tmp);
854 }
855 }
737 if (ret <= 0) { 856 if (ret <= 0) {
738 if (ret == 0 || ret == -ENOENT) { 857 if (ret == 0 || ret == -ENOENT) {
739 pr_err("Failed to find the address of %s\n", buf); 858 pr_err("Failed to find the address of %s\n", buf);
@@ -796,7 +915,7 @@ int show_available_vars(struct perf_probe_event *pevs, int npevs,
796 915
797 for (i = 0; i < npevs && ret >= 0; i++) 916 for (i = 0; i < npevs && ret >= 0; i++)
798 ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter, 917 ret = show_available_vars_at(dinfo, &pevs[i], max_vls, _filter,
799 externs); 918 externs, module);
800 919
801 debuginfo__delete(dinfo); 920 debuginfo__delete(dinfo);
802out: 921out:
@@ -1742,15 +1861,12 @@ static int convert_to_perf_probe_event(struct probe_trace_event *tev,
1742 1861
1743void clear_perf_probe_event(struct perf_probe_event *pev) 1862void clear_perf_probe_event(struct perf_probe_event *pev)
1744{ 1863{
1745 struct perf_probe_point *pp = &pev->point;
1746 struct perf_probe_arg_field *field, *next; 1864 struct perf_probe_arg_field *field, *next;
1747 int i; 1865 int i;
1748 1866
1749 free(pev->event); 1867 free(pev->event);
1750 free(pev->group); 1868 free(pev->group);
1751 free(pp->file); 1869 clear_perf_probe_point(&pev->point);
1752 free(pp->function);
1753 free(pp->lazy_line);
1754 1870
1755 for (i = 0; i < pev->nargs; i++) { 1871 for (i = 0; i < pev->nargs; i++) {
1756 free(pev->args[i].name); 1872 free(pev->args[i].name);
@@ -2367,11 +2483,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2367 int num_matched_functions; 2483 int num_matched_functions;
2368 int ret, i; 2484 int ret, i;
2369 2485
2370 /* Init maps of given executable or kernel */ 2486 map = get_target_map(target, pev->uprobes);
2371 if (pev->uprobes)
2372 map = dso__new_map(target);
2373 else
2374 map = kernel_get_module_map(target);
2375 if (!map) { 2487 if (!map) {
2376 ret = -EINVAL; 2488 ret = -EINVAL;
2377 goto out; 2489 goto out;
@@ -2464,11 +2576,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev,
2464 } 2576 }
2465 2577
2466out: 2578out:
2467 if (map && pev->uprobes) { 2579 put_target_map(map, pev->uprobes);
2468 /* Only when using uprobe(exec) map needs to be released */
2469 dso__delete(map->dso);
2470 map__delete(map);
2471 }
2472 return ret; 2580 return ret;
2473 2581
2474nomem_out: 2582nomem_out: