aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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: