diff options
Diffstat (limited to 'tools/perf')
-rw-r--r-- | tools/perf/Documentation/perf-record.txt | 4 | ||||
-rw-r--r-- | tools/perf/Makefile.perf | 4 | ||||
-rw-r--r-- | tools/perf/builtin-kmem.c | 1 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 4 | ||||
-rw-r--r-- | tools/perf/builtin-sched.c | 17 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 166 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 15 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.h | 3 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 6 |
9 files changed, 152 insertions, 68 deletions
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt index 27fc3617c6a4..5054d9147f0f 100644 --- a/tools/perf/Documentation/perf-record.txt +++ b/tools/perf/Documentation/perf-record.txt | |||
@@ -430,6 +430,10 @@ that gets then processed, possibly via a perf script, to decide if that | |||
430 | particular perf.data snapshot should be kept or not. | 430 | particular perf.data snapshot should be kept or not. |
431 | 431 | ||
432 | Implies --timestamp-filename, --no-buildid and --no-buildid-cache. | 432 | Implies --timestamp-filename, --no-buildid and --no-buildid-cache. |
433 | The reason for the latter two is to reduce the data file switching | ||
434 | overhead. You can still switch them on with: | ||
435 | |||
436 | --switch-output --no-no-buildid --no-no-buildid-cache | ||
433 | 437 | ||
434 | --dry-run:: | 438 | --dry-run:: |
435 | Parse options then exit. --dry-run can be used to detect errors in cmdline | 439 | Parse options then exit. --dry-run can be used to detect errors in cmdline |
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf index 8fc24824705e..8bb16aa9d661 100644 --- a/tools/perf/Makefile.perf +++ b/tools/perf/Makefile.perf | |||
@@ -704,9 +704,9 @@ install-tests: all install-gtk | |||
704 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ | 704 | $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr'; \ |
705 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' | 705 | $(INSTALL) tests/attr/* '$(DESTDIR_SQ)$(perfexec_instdir_SQ)/tests/attr' |
706 | 706 | ||
707 | install-bin: install-tools install-tests | 707 | install-bin: install-tools install-tests install-traceevent-plugins |
708 | 708 | ||
709 | install: install-bin try-install-man install-traceevent-plugins | 709 | install: install-bin try-install-man |
710 | 710 | ||
711 | install-python_ext: | 711 | install-python_ext: |
712 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' | 712 | $(PYTHON_WORD) util/setup.py --quiet install --root='/$(DESTDIR_SQ)' |
diff --git a/tools/perf/builtin-kmem.c b/tools/perf/builtin-kmem.c index 35a02f8e5a4a..915869e00d86 100644 --- a/tools/perf/builtin-kmem.c +++ b/tools/perf/builtin-kmem.c | |||
@@ -655,7 +655,6 @@ static const struct { | |||
655 | { "__GFP_RECLAIM", "R" }, | 655 | { "__GFP_RECLAIM", "R" }, |
656 | { "__GFP_DIRECT_RECLAIM", "DR" }, | 656 | { "__GFP_DIRECT_RECLAIM", "DR" }, |
657 | { "__GFP_KSWAPD_RECLAIM", "KR" }, | 657 | { "__GFP_KSWAPD_RECLAIM", "KR" }, |
658 | { "__GFP_OTHER_NODE", "ON" }, | ||
659 | }; | 658 | }; |
660 | 659 | ||
661 | static size_t max_gfp_len; | 660 | static size_t max_gfp_len; |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 74d6a035133a..4ec10e9427d9 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -1405,7 +1405,7 @@ static bool dry_run; | |||
1405 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', | 1405 | * perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record', |
1406 | * using pipes, etc. | 1406 | * using pipes, etc. |
1407 | */ | 1407 | */ |
1408 | struct option __record_options[] = { | 1408 | static struct option __record_options[] = { |
1409 | OPT_CALLBACK('e', "event", &record.evlist, "event", | 1409 | OPT_CALLBACK('e', "event", &record.evlist, "event", |
1410 | "event selector. use 'perf list' to list available events", | 1410 | "event selector. use 'perf list' to list available events", |
1411 | parse_events_option), | 1411 | parse_events_option), |
@@ -1636,7 +1636,7 @@ int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused) | |||
1636 | * overhead. Still generate buildid if they are required | 1636 | * overhead. Still generate buildid if they are required |
1637 | * explicitly using | 1637 | * explicitly using |
1638 | * | 1638 | * |
1639 | * perf record --signal-trigger --no-no-buildid \ | 1639 | * perf record --switch-output --no-no-buildid \ |
1640 | * --no-no-buildid-cache | 1640 | * --no-no-buildid-cache |
1641 | * | 1641 | * |
1642 | * Following code equals to: | 1642 | * Following code equals to: |
diff --git a/tools/perf/builtin-sched.c b/tools/perf/builtin-sched.c index d53e706a6f17..5b134b0d1ff3 100644 --- a/tools/perf/builtin-sched.c +++ b/tools/perf/builtin-sched.c | |||
@@ -209,6 +209,7 @@ struct perf_sched { | |||
209 | u64 skipped_samples; | 209 | u64 skipped_samples; |
210 | const char *time_str; | 210 | const char *time_str; |
211 | struct perf_time_interval ptime; | 211 | struct perf_time_interval ptime; |
212 | struct perf_time_interval hist_time; | ||
212 | }; | 213 | }; |
213 | 214 | ||
214 | /* per thread run time data */ | 215 | /* per thread run time data */ |
@@ -2460,6 +2461,11 @@ static int timehist_sched_change_event(struct perf_tool *tool, | |||
2460 | timehist_print_sample(sched, sample, &al, thread, t); | 2461 | timehist_print_sample(sched, sample, &al, thread, t); |
2461 | 2462 | ||
2462 | out: | 2463 | out: |
2464 | if (sched->hist_time.start == 0 && t >= ptime->start) | ||
2465 | sched->hist_time.start = t; | ||
2466 | if (ptime->end == 0 || t <= ptime->end) | ||
2467 | sched->hist_time.end = t; | ||
2468 | |||
2463 | if (tr) { | 2469 | if (tr) { |
2464 | /* time of this sched_switch event becomes last time task seen */ | 2470 | /* time of this sched_switch event becomes last time task seen */ |
2465 | tr->last_time = sample->time; | 2471 | tr->last_time = sample->time; |
@@ -2624,6 +2630,7 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2624 | struct thread *t; | 2630 | struct thread *t; |
2625 | struct thread_runtime *r; | 2631 | struct thread_runtime *r; |
2626 | int i; | 2632 | int i; |
2633 | u64 hist_time = sched->hist_time.end - sched->hist_time.start; | ||
2627 | 2634 | ||
2628 | memset(&totals, 0, sizeof(totals)); | 2635 | memset(&totals, 0, sizeof(totals)); |
2629 | 2636 | ||
@@ -2665,7 +2672,7 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2665 | totals.sched_count += r->run_stats.n; | 2672 | totals.sched_count += r->run_stats.n; |
2666 | printf(" CPU %2d idle for ", i); | 2673 | printf(" CPU %2d idle for ", i); |
2667 | print_sched_time(r->total_run_time, 6); | 2674 | print_sched_time(r->total_run_time, 6); |
2668 | printf(" msec\n"); | 2675 | printf(" msec (%6.2f%%)\n", 100.0 * r->total_run_time / hist_time); |
2669 | } else | 2676 | } else |
2670 | printf(" CPU %2d idle entire time window\n", i); | 2677 | printf(" CPU %2d idle entire time window\n", i); |
2671 | } | 2678 | } |
@@ -2701,12 +2708,16 @@ static void timehist_print_summary(struct perf_sched *sched, | |||
2701 | 2708 | ||
2702 | printf("\n" | 2709 | printf("\n" |
2703 | " Total number of unique tasks: %" PRIu64 "\n" | 2710 | " Total number of unique tasks: %" PRIu64 "\n" |
2704 | "Total number of context switches: %" PRIu64 "\n" | 2711 | "Total number of context switches: %" PRIu64 "\n", |
2705 | " Total run time (msec): ", | ||
2706 | totals.task_count, totals.sched_count); | 2712 | totals.task_count, totals.sched_count); |
2707 | 2713 | ||
2714 | printf(" Total run time (msec): "); | ||
2708 | print_sched_time(totals.total_run_time, 2); | 2715 | print_sched_time(totals.total_run_time, 2); |
2709 | printf("\n"); | 2716 | printf("\n"); |
2717 | |||
2718 | printf(" Total scheduling time (msec): "); | ||
2719 | print_sched_time(hist_time, 2); | ||
2720 | printf(" (x %d)\n", sched->max_cpu); | ||
2710 | } | 2721 | } |
2711 | 2722 | ||
2712 | typedef int (*sched_handler)(struct perf_tool *tool, | 2723 | typedef int (*sched_handler)(struct perf_tool *tool, |
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index d281ae2b54e8..6a6f44dd594b 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c | |||
@@ -163,7 +163,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
163 | 163 | ||
164 | /* A file path -- this is an offline module */ | 164 | /* A file path -- this is an offline module */ |
165 | if (module && strchr(module, '/')) | 165 | if (module && strchr(module, '/')) |
166 | return machine__findnew_module_map(host_machine, 0, module); | 166 | return dso__new_map(module); |
167 | 167 | ||
168 | if (!module) | 168 | if (!module) |
169 | module = "kernel"; | 169 | module = "kernel"; |
@@ -173,6 +173,7 @@ static struct map *kernel_get_module_map(const char *module) | |||
173 | if (strncmp(pos->dso->short_name + 1, module, | 173 | if (strncmp(pos->dso->short_name + 1, module, |
174 | pos->dso->short_name_len - 2) == 0 && | 174 | pos->dso->short_name_len - 2) == 0 && |
175 | module[pos->dso->short_name_len - 2] == '\0') { | 175 | module[pos->dso->short_name_len - 2] == '\0') { |
176 | map__get(pos); | ||
176 | return pos; | 177 | return pos; |
177 | } | 178 | } |
178 | } | 179 | } |
@@ -188,15 +189,6 @@ struct map *get_target_map(const char *target, bool user) | |||
188 | return kernel_get_module_map(target); | 189 | return kernel_get_module_map(target); |
189 | } | 190 | } |
190 | 191 | ||
191 | static void put_target_map(struct map *map, bool user) | ||
192 | { | ||
193 | if (map && user) { | ||
194 | /* Only the user map needs to be released */ | ||
195 | map__put(map); | ||
196 | } | ||
197 | } | ||
198 | |||
199 | |||
200 | static int convert_exec_to_group(const char *exec, char **result) | 192 | static int convert_exec_to_group(const char *exec, char **result) |
201 | { | 193 | { |
202 | char *ptr1, *ptr2, *exec_copy; | 194 | char *ptr1, *ptr2, *exec_copy; |
@@ -268,21 +260,6 @@ static bool kprobe_warn_out_range(const char *symbol, unsigned long address) | |||
268 | } | 260 | } |
269 | 261 | ||
270 | /* | 262 | /* |
271 | * NOTE: | ||
272 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
273 | * maps to 'struct module' from linux/module.h. This section contains | ||
274 | * actual module name which will be used by kernel after loading it. | ||
275 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
276 | * exposed to user-space. Offset of 'name' has remained same from long | ||
277 | * time, so hardcoding it here. | ||
278 | */ | ||
279 | #ifdef __LP64__ | ||
280 | #define MOD_NAME_OFFSET 24 | ||
281 | #else | ||
282 | #define MOD_NAME_OFFSET 12 | ||
283 | #endif | ||
284 | |||
285 | /* | ||
286 | * @module can be module name of module file path. In case of path, | 263 | * @module can be module name of module file path. In case of path, |
287 | * inspect elf and find out what is actual module name. | 264 | * inspect elf and find out what is actual module name. |
288 | * Caller has to free mod_name after using it. | 265 | * Caller has to free mod_name after using it. |
@@ -296,6 +273,7 @@ static char *find_module_name(const char *module) | |||
296 | Elf_Data *data; | 273 | Elf_Data *data; |
297 | Elf_Scn *sec; | 274 | Elf_Scn *sec; |
298 | char *mod_name = NULL; | 275 | char *mod_name = NULL; |
276 | int name_offset; | ||
299 | 277 | ||
300 | fd = open(module, O_RDONLY); | 278 | fd = open(module, O_RDONLY); |
301 | if (fd < 0) | 279 | if (fd < 0) |
@@ -317,7 +295,21 @@ static char *find_module_name(const char *module) | |||
317 | if (!data || !data->d_buf) | 295 | if (!data || !data->d_buf) |
318 | goto ret_err; | 296 | goto ret_err; |
319 | 297 | ||
320 | mod_name = strdup((char *)data->d_buf + MOD_NAME_OFFSET); | 298 | /* |
299 | * NOTE: | ||
300 | * '.gnu.linkonce.this_module' section of kernel module elf directly | ||
301 | * maps to 'struct module' from linux/module.h. This section contains | ||
302 | * actual module name which will be used by kernel after loading it. | ||
303 | * But, we cannot use 'struct module' here since linux/module.h is not | ||
304 | * exposed to user-space. Offset of 'name' has remained same from long | ||
305 | * time, so hardcoding it here. | ||
306 | */ | ||
307 | if (ehdr.e_ident[EI_CLASS] == ELFCLASS32) | ||
308 | name_offset = 12; | ||
309 | else /* expect ELFCLASS64 by default */ | ||
310 | name_offset = 24; | ||
311 | |||
312 | mod_name = strdup((char *)data->d_buf + name_offset); | ||
321 | 313 | ||
322 | ret_err: | 314 | ret_err: |
323 | elf_end(elf); | 315 | elf_end(elf); |
@@ -412,7 +404,7 @@ static int find_alternative_probe_point(struct debuginfo *dinfo, | |||
412 | } | 404 | } |
413 | 405 | ||
414 | out: | 406 | out: |
415 | put_target_map(map, uprobes); | 407 | map__put(map); |
416 | return ret; | 408 | return ret; |
417 | 409 | ||
418 | } | 410 | } |
@@ -618,6 +610,67 @@ error: | |||
618 | return ret ? : -ENOENT; | 610 | return ret ? : -ENOENT; |
619 | } | 611 | } |
620 | 612 | ||
613 | /* Adjust symbol name and address */ | ||
614 | static int post_process_probe_trace_point(struct probe_trace_point *tp, | ||
615 | struct map *map, unsigned long offs) | ||
616 | { | ||
617 | struct symbol *sym; | ||
618 | u64 addr = tp->address + tp->offset - offs; | ||
619 | |||
620 | sym = map__find_symbol(map, addr); | ||
621 | if (!sym) | ||
622 | return -ENOENT; | ||
623 | |||
624 | if (strcmp(sym->name, tp->symbol)) { | ||
625 | /* If we have no realname, use symbol for it */ | ||
626 | if (!tp->realname) | ||
627 | tp->realname = tp->symbol; | ||
628 | else | ||
629 | free(tp->symbol); | ||
630 | tp->symbol = strdup(sym->name); | ||
631 | if (!tp->symbol) | ||
632 | return -ENOMEM; | ||
633 | } | ||
634 | tp->offset = addr - sym->start; | ||
635 | tp->address -= offs; | ||
636 | |||
637 | return 0; | ||
638 | } | ||
639 | |||
640 | /* | ||
641 | * Rename DWARF symbols to ELF symbols -- gcc sometimes optimizes functions | ||
642 | * and generate new symbols with suffixes such as .constprop.N or .isra.N | ||
643 | * etc. Since those symbols are not recorded in DWARF, we have to find | ||
644 | * correct generated symbols from offline ELF binary. | ||
645 | * For online kernel or uprobes we don't need this because those are | ||
646 | * rebased on _text, or already a section relative address. | ||
647 | */ | ||
648 | static int | ||
649 | post_process_offline_probe_trace_events(struct probe_trace_event *tevs, | ||
650 | int ntevs, const char *pathname) | ||
651 | { | ||
652 | struct map *map; | ||
653 | unsigned long stext = 0; | ||
654 | int i, ret = 0; | ||
655 | |||
656 | /* Prepare a map for offline binary */ | ||
657 | map = dso__new_map(pathname); | ||
658 | if (!map || get_text_start_address(pathname, &stext) < 0) { | ||
659 | pr_warning("Failed to get ELF symbols for %s\n", pathname); | ||
660 | return -EINVAL; | ||
661 | } | ||
662 | |||
663 | for (i = 0; i < ntevs; i++) { | ||
664 | ret = post_process_probe_trace_point(&tevs[i].point, | ||
665 | map, stext); | ||
666 | if (ret < 0) | ||
667 | break; | ||
668 | } | ||
669 | map__put(map); | ||
670 | |||
671 | return ret; | ||
672 | } | ||
673 | |||
621 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | 674 | static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, |
622 | int ntevs, const char *exec) | 675 | int ntevs, const char *exec) |
623 | { | 676 | { |
@@ -645,18 +698,31 @@ static int add_exec_to_probe_trace_events(struct probe_trace_event *tevs, | |||
645 | return ret; | 698 | return ret; |
646 | } | 699 | } |
647 | 700 | ||
648 | static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | 701 | static int |
649 | int ntevs, const char *module) | 702 | post_process_module_probe_trace_events(struct probe_trace_event *tevs, |
703 | int ntevs, const char *module, | ||
704 | struct debuginfo *dinfo) | ||
650 | { | 705 | { |
706 | Dwarf_Addr text_offs = 0; | ||
651 | int i, ret = 0; | 707 | int i, ret = 0; |
652 | char *mod_name = NULL; | 708 | char *mod_name = NULL; |
709 | struct map *map; | ||
653 | 710 | ||
654 | if (!module) | 711 | if (!module) |
655 | return 0; | 712 | return 0; |
656 | 713 | ||
657 | mod_name = find_module_name(module); | 714 | map = get_target_map(module, false); |
715 | if (!map || debuginfo__get_text_offset(dinfo, &text_offs, true) < 0) { | ||
716 | pr_warning("Failed to get ELF symbols for %s\n", module); | ||
717 | return -EINVAL; | ||
718 | } | ||
658 | 719 | ||
720 | mod_name = find_module_name(module); | ||
659 | for (i = 0; i < ntevs; i++) { | 721 | for (i = 0; i < ntevs; i++) { |
722 | ret = post_process_probe_trace_point(&tevs[i].point, | ||
723 | map, (unsigned long)text_offs); | ||
724 | if (ret < 0) | ||
725 | break; | ||
660 | tevs[i].point.module = | 726 | tevs[i].point.module = |
661 | strdup(mod_name ? mod_name : module); | 727 | strdup(mod_name ? mod_name : module); |
662 | if (!tevs[i].point.module) { | 728 | if (!tevs[i].point.module) { |
@@ -666,6 +732,8 @@ static int add_module_to_probe_trace_events(struct probe_trace_event *tevs, | |||
666 | } | 732 | } |
667 | 733 | ||
668 | free(mod_name); | 734 | free(mod_name); |
735 | map__put(map); | ||
736 | |||
669 | return ret; | 737 | return ret; |
670 | } | 738 | } |
671 | 739 | ||
@@ -679,7 +747,8 @@ post_process_kernel_probe_trace_events(struct probe_trace_event *tevs, | |||
679 | 747 | ||
680 | /* Skip post process if the target is an offline kernel */ | 748 | /* Skip post process if the target is an offline kernel */ |
681 | if (symbol_conf.ignore_vmlinux_buildid) | 749 | if (symbol_conf.ignore_vmlinux_buildid) |
682 | return 0; | 750 | return post_process_offline_probe_trace_events(tevs, ntevs, |
751 | symbol_conf.vmlinux_name); | ||
683 | 752 | ||
684 | reloc_sym = kernel_get_ref_reloc_sym(); | 753 | reloc_sym = kernel_get_ref_reloc_sym(); |
685 | if (!reloc_sym) { | 754 | if (!reloc_sym) { |
@@ -722,7 +791,7 @@ arch__post_process_probe_trace_events(struct perf_probe_event *pev __maybe_unuse | |||
722 | static int post_process_probe_trace_events(struct perf_probe_event *pev, | 791 | static int post_process_probe_trace_events(struct perf_probe_event *pev, |
723 | struct probe_trace_event *tevs, | 792 | struct probe_trace_event *tevs, |
724 | int ntevs, const char *module, | 793 | int ntevs, const char *module, |
725 | bool uprobe) | 794 | bool uprobe, struct debuginfo *dinfo) |
726 | { | 795 | { |
727 | int ret; | 796 | int ret; |
728 | 797 | ||
@@ -730,7 +799,8 @@ static int post_process_probe_trace_events(struct perf_probe_event *pev, | |||
730 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module); | 799 | ret = add_exec_to_probe_trace_events(tevs, ntevs, module); |
731 | else if (module) | 800 | else if (module) |
732 | /* Currently ref_reloc_sym based probe is not for drivers */ | 801 | /* Currently ref_reloc_sym based probe is not for drivers */ |
733 | ret = add_module_to_probe_trace_events(tevs, ntevs, module); | 802 | ret = post_process_module_probe_trace_events(tevs, ntevs, |
803 | module, dinfo); | ||
734 | else | 804 | else |
735 | ret = post_process_kernel_probe_trace_events(tevs, ntevs); | 805 | ret = post_process_kernel_probe_trace_events(tevs, ntevs); |
736 | 806 | ||
@@ -774,30 +844,27 @@ static int try_to_find_probe_trace_events(struct perf_probe_event *pev, | |||
774 | } | 844 | } |
775 | } | 845 | } |
776 | 846 | ||
777 | debuginfo__delete(dinfo); | ||
778 | |||
779 | if (ntevs > 0) { /* Succeeded to find trace events */ | 847 | if (ntevs > 0) { /* Succeeded to find trace events */ |
780 | pr_debug("Found %d probe_trace_events.\n", ntevs); | 848 | pr_debug("Found %d probe_trace_events.\n", ntevs); |
781 | ret = post_process_probe_trace_events(pev, *tevs, ntevs, | 849 | ret = post_process_probe_trace_events(pev, *tevs, ntevs, |
782 | pev->target, pev->uprobes); | 850 | pev->target, pev->uprobes, dinfo); |
783 | if (ret < 0 || ret == ntevs) { | 851 | if (ret < 0 || ret == ntevs) { |
852 | pr_debug("Post processing failed or all events are skipped. (%d)\n", ret); | ||
784 | clear_probe_trace_events(*tevs, ntevs); | 853 | clear_probe_trace_events(*tevs, ntevs); |
785 | zfree(tevs); | 854 | zfree(tevs); |
855 | ntevs = 0; | ||
786 | } | 856 | } |
787 | if (ret != ntevs) | ||
788 | return ret < 0 ? ret : ntevs; | ||
789 | ntevs = 0; | ||
790 | /* Fall through */ | ||
791 | } | 857 | } |
792 | 858 | ||
859 | debuginfo__delete(dinfo); | ||
860 | |||
793 | if (ntevs == 0) { /* No error but failed to find probe point. */ | 861 | if (ntevs == 0) { /* No error but failed to find probe point. */ |
794 | pr_warning("Probe point '%s' not found.\n", | 862 | pr_warning("Probe point '%s' not found.\n", |
795 | synthesize_perf_probe_point(&pev->point)); | 863 | synthesize_perf_probe_point(&pev->point)); |
796 | return -ENOENT; | 864 | return -ENOENT; |
797 | } | 865 | } else if (ntevs < 0) { |
798 | /* Error path : ntevs < 0 */ | 866 | /* Error path : ntevs < 0 */ |
799 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); | 867 | pr_debug("An error occurred in debuginfo analysis (%d).\n", ntevs); |
800 | if (ntevs < 0) { | ||
801 | if (ntevs == -EBADF) | 868 | if (ntevs == -EBADF) |
802 | pr_warning("Warning: No dwarf info found in the vmlinux - " | 869 | pr_warning("Warning: No dwarf info found in the vmlinux - " |
803 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); | 870 | "please rebuild kernel with CONFIG_DEBUG_INFO=y.\n"); |
@@ -2869,7 +2936,7 @@ static int find_probe_trace_events_from_map(struct perf_probe_event *pev, | |||
2869 | } | 2936 | } |
2870 | 2937 | ||
2871 | out: | 2938 | out: |
2872 | put_target_map(map, pev->uprobes); | 2939 | map__put(map); |
2873 | free(syms); | 2940 | free(syms); |
2874 | return ret; | 2941 | return ret; |
2875 | 2942 | ||
@@ -3362,10 +3429,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
3362 | return ret; | 3429 | return ret; |
3363 | 3430 | ||
3364 | /* Get a symbol map */ | 3431 | /* Get a symbol map */ |
3365 | if (user) | 3432 | map = get_target_map(target, user); |
3366 | map = dso__new_map(target); | ||
3367 | else | ||
3368 | map = kernel_get_module_map(target); | ||
3369 | if (!map) { | 3433 | if (!map) { |
3370 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); | 3434 | pr_err("Failed to get a map for %s\n", (target) ? : "kernel"); |
3371 | return -EINVAL; | 3435 | return -EINVAL; |
@@ -3397,9 +3461,7 @@ int show_available_funcs(const char *target, struct strfilter *_filter, | |||
3397 | } | 3461 | } |
3398 | 3462 | ||
3399 | end: | 3463 | end: |
3400 | if (user) { | 3464 | map__put(map); |
3401 | map__put(map); | ||
3402 | } | ||
3403 | exit_probe_symbol_maps(); | 3465 | exit_probe_symbol_maps(); |
3404 | 3466 | ||
3405 | return ret; | 3467 | return ret; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index df4debe564da..0d9d6e0803b8 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -1501,7 +1501,8 @@ int debuginfo__find_available_vars_at(struct debuginfo *dbg, | |||
1501 | } | 1501 | } |
1502 | 1502 | ||
1503 | /* For the kernel module, we need a special code to get a DIE */ | 1503 | /* For the kernel module, we need a special code to get a DIE */ |
1504 | static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) | 1504 | int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, |
1505 | bool adjust_offset) | ||
1505 | { | 1506 | { |
1506 | int n, i; | 1507 | int n, i; |
1507 | Elf32_Word shndx; | 1508 | Elf32_Word shndx; |
@@ -1530,6 +1531,8 @@ static int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs) | |||
1530 | if (!shdr) | 1531 | if (!shdr) |
1531 | return -ENOENT; | 1532 | return -ENOENT; |
1532 | *offs = shdr->sh_addr; | 1533 | *offs = shdr->sh_addr; |
1534 | if (adjust_offset) | ||
1535 | *offs -= shdr->sh_offset; | ||
1533 | } | 1536 | } |
1534 | } | 1537 | } |
1535 | return 0; | 1538 | return 0; |
@@ -1543,16 +1546,12 @@ int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, | |||
1543 | Dwarf_Addr _addr = 0, baseaddr = 0; | 1546 | Dwarf_Addr _addr = 0, baseaddr = 0; |
1544 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; | 1547 | const char *fname = NULL, *func = NULL, *basefunc = NULL, *tmp; |
1545 | int baseline = 0, lineno = 0, ret = 0; | 1548 | int baseline = 0, lineno = 0, ret = 0; |
1546 | bool reloc = false; | ||
1547 | 1549 | ||
1548 | retry: | 1550 | /* We always need to relocate the address for aranges */ |
1551 | if (debuginfo__get_text_offset(dbg, &baseaddr, false) == 0) | ||
1552 | addr += baseaddr; | ||
1549 | /* Find cu die */ | 1553 | /* Find cu die */ |
1550 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { | 1554 | if (!dwarf_addrdie(dbg->dbg, (Dwarf_Addr)addr, &cudie)) { |
1551 | if (!reloc && debuginfo__get_text_offset(dbg, &baseaddr) == 0) { | ||
1552 | addr += baseaddr; | ||
1553 | reloc = true; | ||
1554 | goto retry; | ||
1555 | } | ||
1556 | pr_warning("Failed to find debug information for address %lx\n", | 1555 | pr_warning("Failed to find debug information for address %lx\n", |
1557 | addr); | 1556 | addr); |
1558 | ret = -EINVAL; | 1557 | ret = -EINVAL; |
diff --git a/tools/perf/util/probe-finder.h b/tools/perf/util/probe-finder.h index f1d8558f498e..2956c5198652 100644 --- a/tools/perf/util/probe-finder.h +++ b/tools/perf/util/probe-finder.h | |||
@@ -46,6 +46,9 @@ int debuginfo__find_trace_events(struct debuginfo *dbg, | |||
46 | int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, | 46 | int debuginfo__find_probe_point(struct debuginfo *dbg, unsigned long addr, |
47 | struct perf_probe_point *ppt); | 47 | struct perf_probe_point *ppt); |
48 | 48 | ||
49 | int debuginfo__get_text_offset(struct debuginfo *dbg, Dwarf_Addr *offs, | ||
50 | bool adjust_offset); | ||
51 | |||
49 | /* Find a line range */ | 52 | /* Find a line range */ |
50 | int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr); | 53 | int debuginfo__find_line_range(struct debuginfo *dbg, struct line_range *lr); |
51 | 54 | ||
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c index 99400b0e8f2a..adbc6c02c3aa 100644 --- a/tools/perf/util/symbol-elf.c +++ b/tools/perf/util/symbol-elf.c | |||
@@ -537,6 +537,12 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
537 | break; | 537 | break; |
538 | } else { | 538 | } else { |
539 | int n = namesz + descsz; | 539 | int n = namesz + descsz; |
540 | |||
541 | if (n > (int)sizeof(bf)) { | ||
542 | n = sizeof(bf); | ||
543 | pr_debug("%s: truncating reading of build id in sysfs file %s: n_namesz=%u, n_descsz=%u.\n", | ||
544 | __func__, filename, nhdr.n_namesz, nhdr.n_descsz); | ||
545 | } | ||
540 | if (read(fd, bf, n) != n) | 546 | if (read(fd, bf, n) != n) |
541 | break; | 547 | break; |
542 | } | 548 | } |