diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 18:34:13 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-07-31 18:34:13 -0400 |
| commit | bca1a5c0eabe0f17081760c61e8d08e73dd6b6a6 (patch) | |
| tree | f939c6f42bf459786eb0050578044fdde56fec90 /tools | |
| parent | ec7a19bfec544aa73e347369232f9bd654954aa3 (diff) | |
| parent | 194f8dcbe9629d8e9346cf96345a9c0bbf0e67ae (diff) | |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull perf updates from Ingo Molnar:
"The biggest changes are Intel Nehalem-EX PMU uncore support, uprobes
updates/cleanups/fixes from Oleg and diverse tooling updates (mostly
fixes) now that Arnaldo is back from vacation."
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (40 commits)
uprobes: __replace_page() needs munlock_vma_page()
uprobes: Rename vma_address() and make it return "unsigned long"
uprobes: Fix register_for_each_vma()->vma_address() check
uprobes: Introduce vaddr_to_offset(vma, vaddr)
uprobes: Teach build_probe_list() to consider the range
uprobes: Remove insert_vm_struct()->uprobe_mmap()
uprobes: Remove copy_vma()->uprobe_mmap()
uprobes: Fix overflow in vma_address()/find_active_uprobe()
uprobes: Suppress uprobe_munmap() from mmput()
uprobes: Uprobe_mmap/munmap needs list_for_each_entry_safe()
uprobes: Clean up and document write_opcode()->lock_page(old_page)
uprobes: Kill write_opcode()->lock_page(new_page)
uprobes: __replace_page() should not use page_address_in_vma()
uprobes: Don't recheck vma/f_mapping in write_opcode()
perf/x86: Fix missing struct before structure name
perf/x86: Fix format definition of SNB-EP uncore QPI box
perf/x86: Make bitfield unsigned
perf/x86: Fix LLC-* and node-* events on Intel SandyBridge
perf/x86: Add Intel Nehalem-EX uncore support
perf/x86: Fix typo in format definition of uncore PCU filter
...
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/lib/traceevent/.gitignore | 1 | ||||
| -rw-r--r-- | tools/lib/traceevent/Makefile | 14 | ||||
| -rw-r--r-- | tools/perf/Makefile | 4 | ||||
| -rw-r--r-- | tools/perf/builtin-test.c | 4 | ||||
| -rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
| -rw-r--r-- | tools/perf/ui/browsers/hists.c | 4 | ||||
| -rw-r--r-- | tools/perf/util/annotate.c | 15 | ||||
| -rw-r--r-- | tools/perf/util/dso-test-data.c | 153 | ||||
| -rw-r--r-- | tools/perf/util/evlist.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/header.c | 6 | ||||
| -rw-r--r-- | tools/perf/util/hist.c | 7 | ||||
| -rw-r--r-- | tools/perf/util/map.c | 41 | ||||
| -rw-r--r-- | tools/perf/util/map.h | 1 | ||||
| -rw-r--r-- | tools/perf/util/parse-events.c | 2 | ||||
| -rw-r--r-- | tools/perf/util/session.c | 5 | ||||
| -rw-r--r-- | tools/perf/util/symbol.c | 447 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 54 | ||||
| -rw-r--r-- | tools/perf/util/target.c | 11 |
18 files changed, 657 insertions, 116 deletions
diff --git a/tools/lib/traceevent/.gitignore b/tools/lib/traceevent/.gitignore new file mode 100644 index 000000000000..35f56be5a4cd --- /dev/null +++ b/tools/lib/traceevent/.gitignore | |||
| @@ -0,0 +1 @@ | |||
| TRACEEVENT-CFLAGS | |||
diff --git a/tools/lib/traceevent/Makefile b/tools/lib/traceevent/Makefile index 46c2f6b7b123..14131cb0522d 100644 --- a/tools/lib/traceevent/Makefile +++ b/tools/lib/traceevent/Makefile | |||
| @@ -207,7 +207,7 @@ libtraceevent.so: $(PEVENT_LIB_OBJS) | |||
| 207 | libtraceevent.a: $(PEVENT_LIB_OBJS) | 207 | libtraceevent.a: $(PEVENT_LIB_OBJS) |
| 208 | $(Q)$(do_build_static_lib) | 208 | $(Q)$(do_build_static_lib) |
| 209 | 209 | ||
| 210 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c | 210 | $(PEVENT_LIB_OBJS): %.o: $(src)/%.c TRACEEVENT-CFLAGS |
| 211 | $(Q)$(do_fpic_compile) | 211 | $(Q)$(do_fpic_compile) |
| 212 | 212 | ||
| 213 | define make_version.h | 213 | define make_version.h |
| @@ -272,6 +272,16 @@ ifneq ($(dep_includes),) | |||
| 272 | include $(dep_includes) | 272 | include $(dep_includes) |
| 273 | endif | 273 | endif |
| 274 | 274 | ||
| 275 | ### Detect environment changes | ||
| 276 | TRACK_CFLAGS = $(subst ','\'',$(CFLAGS)):$(ARCH):$(CROSS_COMPILE) | ||
| 277 | |||
| 278 | TRACEEVENT-CFLAGS: force | ||
| 279 | @FLAGS='$(TRACK_CFLAGS)'; \ | ||
| 280 | if test x"$$FLAGS" != x"`cat TRACEEVENT-CFLAGS 2>/dev/null`" ; then \ | ||
| 281 | echo 1>&2 " * new build flags or cross compiler"; \ | ||
| 282 | echo "$$FLAGS" >TRACEEVENT-CFLAGS; \ | ||
| 283 | fi | ||
| 284 | |||
| 275 | tags: force | 285 | tags: force |
| 276 | $(RM) tags | 286 | $(RM) tags |
| 277 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ | 287 | find . -name '*.[ch]' | xargs ctags --extra=+f --c-kinds=+px \ |
| @@ -297,7 +307,7 @@ install: install_lib | |||
| 297 | 307 | ||
| 298 | clean: | 308 | clean: |
| 299 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d | 309 | $(RM) *.o *~ $(TARGETS) *.a *.so $(VERSION_FILES) .*.d |
| 300 | $(RM) tags TAGS | 310 | $(RM) TRACEEVENT-CFLAGS tags TAGS |
| 301 | 311 | ||
| 302 | endif # skip-makefile | 312 | endif # skip-makefile |
| 303 | 313 | ||
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 75d74e5db8d5..77f124fe57ad 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
| @@ -354,6 +354,7 @@ LIB_OBJS += $(OUTPUT)util/usage.o | |||
| 354 | LIB_OBJS += $(OUTPUT)util/wrapper.o | 354 | LIB_OBJS += $(OUTPUT)util/wrapper.o |
| 355 | LIB_OBJS += $(OUTPUT)util/sigchain.o | 355 | LIB_OBJS += $(OUTPUT)util/sigchain.o |
| 356 | LIB_OBJS += $(OUTPUT)util/symbol.o | 356 | LIB_OBJS += $(OUTPUT)util/symbol.o |
| 357 | LIB_OBJS += $(OUTPUT)util/dso-test-data.o | ||
| 357 | LIB_OBJS += $(OUTPUT)util/color.o | 358 | LIB_OBJS += $(OUTPUT)util/color.o |
| 358 | LIB_OBJS += $(OUTPUT)util/pager.o | 359 | LIB_OBJS += $(OUTPUT)util/pager.o |
| 359 | LIB_OBJS += $(OUTPUT)util/header.o | 360 | LIB_OBJS += $(OUTPUT)util/header.o |
| @@ -803,6 +804,9 @@ $(OUTPUT)ui/browsers/map.o: ui/browsers/map.c $(OUTPUT)PERF-CFLAGS | |||
| 803 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS | 804 | $(OUTPUT)util/rbtree.o: ../../lib/rbtree.c $(OUTPUT)PERF-CFLAGS |
| 804 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< | 805 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -DETC_PERFCONFIG='"$(ETC_PERFCONFIG_SQ)"' $< |
| 805 | 806 | ||
| 807 | $(OUTPUT)util/parse-events.o: util/parse-events.c $(OUTPUT)PERF-CFLAGS | ||
| 808 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) -Wno-redundant-decls $< | ||
| 809 | |||
| 806 | $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS | 810 | $(OUTPUT)util/scripting-engines/trace-event-perl.o: util/scripting-engines/trace-event-perl.c $(OUTPUT)PERF-CFLAGS |
| 807 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< | 811 | $(QUIET_CC)$(CC) -o $@ -c $(ALL_CFLAGS) $(PERL_EMBED_CCOPTS) -Wno-redundant-decls -Wno-strict-prototypes -Wno-unused-parameter -Wno-shadow $< |
| 808 | 812 | ||
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 5ce30305462b..d909eb74a0eb 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
| @@ -1142,6 +1142,10 @@ static struct test { | |||
| 1142 | .func = test__perf_pmu, | 1142 | .func = test__perf_pmu, |
| 1143 | }, | 1143 | }, |
| 1144 | { | 1144 | { |
| 1145 | .desc = "Test dso data interface", | ||
| 1146 | .func = dso__test_data, | ||
| 1147 | }, | ||
| 1148 | { | ||
| 1145 | .func = NULL, | 1149 | .func = NULL, |
| 1146 | }, | 1150 | }, |
| 1147 | }; | 1151 | }; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index e3cab5f088f8..35e86c6df713 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
| @@ -125,7 +125,7 @@ static int perf_top__parse_source(struct perf_top *top, struct hist_entry *he) | |||
| 125 | /* | 125 | /* |
| 126 | * We can't annotate with just /proc/kallsyms | 126 | * We can't annotate with just /proc/kallsyms |
| 127 | */ | 127 | */ |
| 128 | if (map->dso->symtab_type == SYMTAB__KALLSYMS) { | 128 | if (map->dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { |
| 129 | pr_err("Can't annotate %s: No vmlinux file was found in the " | 129 | pr_err("Can't annotate %s: No vmlinux file was found in the " |
| 130 | "path\n", sym->name); | 130 | "path\n", sym->name); |
| 131 | sleep(1); | 131 | sleep(1); |
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c index 482f0517b61e..413bd62eedb1 100644 --- a/tools/perf/ui/browsers/hists.c +++ b/tools/perf/ui/browsers/hists.c | |||
| @@ -978,8 +978,8 @@ static int hist_browser__dump(struct hist_browser *browser) | |||
| 978 | fp = fopen(filename, "w"); | 978 | fp = fopen(filename, "w"); |
| 979 | if (fp == NULL) { | 979 | if (fp == NULL) { |
| 980 | char bf[64]; | 980 | char bf[64]; |
| 981 | strerror_r(errno, bf, sizeof(bf)); | 981 | const char *err = strerror_r(errno, bf, sizeof(bf)); |
| 982 | ui_helpline__fpush("Couldn't write to %s: %s", filename, bf); | 982 | ui_helpline__fpush("Couldn't write to %s: %s", filename, err); |
| 983 | return -1; | 983 | return -1; |
| 984 | } | 984 | } |
| 985 | 985 | ||
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index 8069dfb5ba77..3a282c0057d2 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
| @@ -426,7 +426,18 @@ int symbol__alloc_hist(struct symbol *sym) | |||
| 426 | { | 426 | { |
| 427 | struct annotation *notes = symbol__annotation(sym); | 427 | struct annotation *notes = symbol__annotation(sym); |
| 428 | const size_t size = symbol__size(sym); | 428 | const size_t size = symbol__size(sym); |
| 429 | size_t sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); | 429 | size_t sizeof_sym_hist; |
| 430 | |||
| 431 | /* Check for overflow when calculating sizeof_sym_hist */ | ||
| 432 | if (size > (SIZE_MAX - sizeof(struct sym_hist)) / sizeof(u64)) | ||
| 433 | return -1; | ||
| 434 | |||
| 435 | sizeof_sym_hist = (sizeof(struct sym_hist) + size * sizeof(u64)); | ||
| 436 | |||
| 437 | /* Check for overflow in zalloc argument */ | ||
| 438 | if (sizeof_sym_hist > (SIZE_MAX - sizeof(*notes->src)) | ||
| 439 | / symbol_conf.nr_events) | ||
| 440 | return -1; | ||
| 430 | 441 | ||
| 431 | notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); | 442 | notes->src = zalloc(sizeof(*notes->src) + symbol_conf.nr_events * sizeof_sym_hist); |
| 432 | if (notes->src == NULL) | 443 | if (notes->src == NULL) |
| @@ -777,7 +788,7 @@ fallback: | |||
| 777 | free_filename = false; | 788 | free_filename = false; |
| 778 | } | 789 | } |
| 779 | 790 | ||
| 780 | if (dso->symtab_type == SYMTAB__KALLSYMS) { | 791 | if (dso->symtab_type == DSO_BINARY_TYPE__KALLSYMS) { |
| 781 | char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; | 792 | char bf[BUILD_ID_SIZE * 2 + 16] = " with build id "; |
| 782 | char *build_id_msg = NULL; | 793 | char *build_id_msg = NULL; |
| 783 | 794 | ||
diff --git a/tools/perf/util/dso-test-data.c b/tools/perf/util/dso-test-data.c new file mode 100644 index 000000000000..541cdc72c7df --- /dev/null +++ b/tools/perf/util/dso-test-data.c | |||
| @@ -0,0 +1,153 @@ | |||
| 1 | #include "util.h" | ||
| 2 | |||
| 3 | #include <stdlib.h> | ||
| 4 | #include <sys/types.h> | ||
| 5 | #include <sys/stat.h> | ||
| 6 | #include <fcntl.h> | ||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include "symbol.h" | ||
| 10 | |||
| 11 | #define TEST_ASSERT_VAL(text, cond) \ | ||
| 12 | do { \ | ||
| 13 | if (!(cond)) { \ | ||
| 14 | pr_debug("FAILED %s:%d %s\n", __FILE__, __LINE__, text); \ | ||
| 15 | return -1; \ | ||
| 16 | } \ | ||
| 17 | } while (0) | ||
| 18 | |||
| 19 | static char *test_file(int size) | ||
| 20 | { | ||
| 21 | static char buf_templ[] = "/tmp/test-XXXXXX"; | ||
| 22 | char *templ = buf_templ; | ||
| 23 | int fd, i; | ||
| 24 | unsigned char *buf; | ||
| 25 | |||
| 26 | fd = mkostemp(templ, O_CREAT|O_WRONLY|O_TRUNC); | ||
| 27 | |||
| 28 | buf = malloc(size); | ||
| 29 | if (!buf) { | ||
| 30 | close(fd); | ||
| 31 | return NULL; | ||
| 32 | } | ||
| 33 | |||
| 34 | for (i = 0; i < size; i++) | ||
| 35 | buf[i] = (unsigned char) ((int) i % 10); | ||
| 36 | |||
| 37 | if (size != write(fd, buf, size)) | ||
| 38 | templ = NULL; | ||
| 39 | |||
| 40 | close(fd); | ||
| 41 | return templ; | ||
| 42 | } | ||
| 43 | |||
| 44 | #define TEST_FILE_SIZE (DSO__DATA_CACHE_SIZE * 20) | ||
| 45 | |||
| 46 | struct test_data_offset { | ||
| 47 | off_t offset; | ||
| 48 | u8 data[10]; | ||
| 49 | int size; | ||
| 50 | }; | ||
| 51 | |||
| 52 | struct test_data_offset offsets[] = { | ||
| 53 | /* Fill first cache page. */ | ||
| 54 | { | ||
| 55 | .offset = 10, | ||
| 56 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 57 | .size = 10, | ||
| 58 | }, | ||
| 59 | /* Read first cache page. */ | ||
| 60 | { | ||
| 61 | .offset = 10, | ||
| 62 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 63 | .size = 10, | ||
| 64 | }, | ||
| 65 | /* Fill cache boundary pages. */ | ||
| 66 | { | ||
| 67 | .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10, | ||
| 68 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 69 | .size = 10, | ||
| 70 | }, | ||
| 71 | /* Read cache boundary pages. */ | ||
| 72 | { | ||
| 73 | .offset = DSO__DATA_CACHE_SIZE - DSO__DATA_CACHE_SIZE % 10, | ||
| 74 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 75 | .size = 10, | ||
| 76 | }, | ||
| 77 | /* Fill final cache page. */ | ||
| 78 | { | ||
| 79 | .offset = TEST_FILE_SIZE - 10, | ||
| 80 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 81 | .size = 10, | ||
| 82 | }, | ||
| 83 | /* Read final cache page. */ | ||
| 84 | { | ||
| 85 | .offset = TEST_FILE_SIZE - 10, | ||
| 86 | .data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, | ||
| 87 | .size = 10, | ||
| 88 | }, | ||
| 89 | /* Read final cache page. */ | ||
| 90 | { | ||
| 91 | .offset = TEST_FILE_SIZE - 3, | ||
| 92 | .data = { 7, 8, 9, 0, 0, 0, 0, 0, 0, 0 }, | ||
| 93 | .size = 3, | ||
| 94 | }, | ||
| 95 | }; | ||
| 96 | |||
| 97 | int dso__test_data(void) | ||
| 98 | { | ||
| 99 | struct machine machine; | ||
| 100 | struct dso *dso; | ||
| 101 | char *file = test_file(TEST_FILE_SIZE); | ||
| 102 | size_t i; | ||
| 103 | |||
| 104 | TEST_ASSERT_VAL("No test file", file); | ||
| 105 | |||
| 106 | memset(&machine, 0, sizeof(machine)); | ||
| 107 | |||
| 108 | dso = dso__new((const char *)file); | ||
| 109 | |||
| 110 | /* Basic 10 bytes tests. */ | ||
| 111 | for (i = 0; i < ARRAY_SIZE(offsets); i++) { | ||
| 112 | struct test_data_offset *data = &offsets[i]; | ||
| 113 | ssize_t size; | ||
| 114 | u8 buf[10]; | ||
| 115 | |||
| 116 | memset(buf, 0, 10); | ||
| 117 | size = dso__data_read_offset(dso, &machine, data->offset, | ||
| 118 | buf, 10); | ||
| 119 | |||
| 120 | TEST_ASSERT_VAL("Wrong size", size == data->size); | ||
| 121 | TEST_ASSERT_VAL("Wrong data", !memcmp(buf, data->data, 10)); | ||
| 122 | } | ||
| 123 | |||
| 124 | /* Read cross multiple cache pages. */ | ||
| 125 | { | ||
| 126 | ssize_t size; | ||
| 127 | int c; | ||
| 128 | u8 *buf; | ||
| 129 | |||
| 130 | buf = malloc(TEST_FILE_SIZE); | ||
| 131 | TEST_ASSERT_VAL("ENOMEM\n", buf); | ||
| 132 | |||
| 133 | /* First iteration to fill caches, second one to read them. */ | ||
| 134 | for (c = 0; c < 2; c++) { | ||
| 135 | memset(buf, 0, TEST_FILE_SIZE); | ||
| 136 | size = dso__data_read_offset(dso, &machine, 10, | ||
| 137 | buf, TEST_FILE_SIZE); | ||
| 138 | |||
| 139 | TEST_ASSERT_VAL("Wrong size", | ||
| 140 | size == (TEST_FILE_SIZE - 10)); | ||
| 141 | |||
| 142 | for (i = 0; i < (size_t)size; i++) | ||
| 143 | TEST_ASSERT_VAL("Wrong data", | ||
| 144 | buf[i] == (i % 10)); | ||
| 145 | } | ||
| 146 | |||
| 147 | free(buf); | ||
| 148 | } | ||
| 149 | |||
| 150 | dso__delete(dso); | ||
| 151 | unlink(file); | ||
| 152 | return 0; | ||
| 153 | } | ||
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index f74e9560350e..3edfd3483816 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
| @@ -214,7 +214,7 @@ int perf_evlist__add_tracepoints(struct perf_evlist *evlist, | |||
| 214 | attrs[i].type = PERF_TYPE_TRACEPOINT; | 214 | attrs[i].type = PERF_TYPE_TRACEPOINT; |
| 215 | attrs[i].config = err; | 215 | attrs[i].config = err; |
| 216 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | | 216 | attrs[i].sample_type = (PERF_SAMPLE_RAW | PERF_SAMPLE_TIME | |
| 217 | PERF_SAMPLE_CPU); | 217 | PERF_SAMPLE_CPU | PERF_SAMPLE_PERIOD); |
| 218 | attrs[i].sample_period = 1; | 218 | attrs[i].sample_period = 1; |
| 219 | } | 219 | } |
| 220 | 220 | ||
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c index 5a47aba46759..3a6d20443330 100644 --- a/tools/perf/util/header.c +++ b/tools/perf/util/header.c | |||
| @@ -1212,6 +1212,12 @@ static void print_event_desc(struct perf_header *ph, int fd, FILE *fp) | |||
| 1212 | attr.exclude_user, | 1212 | attr.exclude_user, |
| 1213 | attr.exclude_kernel); | 1213 | attr.exclude_kernel); |
| 1214 | 1214 | ||
| 1215 | fprintf(fp, ", excl_host = %d, excl_guest = %d", | ||
| 1216 | attr.exclude_host, | ||
| 1217 | attr.exclude_guest); | ||
| 1218 | |||
| 1219 | fprintf(fp, ", precise_ip = %d", attr.precise_ip); | ||
| 1220 | |||
| 1215 | if (nr) | 1221 | if (nr) |
| 1216 | fprintf(fp, ", id = {"); | 1222 | fprintf(fp, ", id = {"); |
| 1217 | 1223 | ||
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c index 514e2a4b367d..f247ef2789a4 100644 --- a/tools/perf/util/hist.c +++ b/tools/perf/util/hist.c | |||
| @@ -708,7 +708,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, | |||
| 708 | bool printed = false; | 708 | bool printed = false; |
| 709 | struct rb_node *node; | 709 | struct rb_node *node; |
| 710 | int i = 0; | 710 | int i = 0; |
| 711 | int ret; | 711 | int ret = 0; |
| 712 | 712 | ||
| 713 | /* | 713 | /* |
| 714 | * If have one single callchain root, don't bother printing | 714 | * If have one single callchain root, don't bother printing |
| @@ -747,8 +747,11 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root, | |||
| 747 | root = &cnode->rb_root; | 747 | root = &cnode->rb_root; |
| 748 | } | 748 | } |
| 749 | 749 | ||
| 750 | return __callchain__fprintf_graph(fp, root, total_samples, | 750 | ret += __callchain__fprintf_graph(fp, root, total_samples, |
| 751 | 1, 1, left_margin); | 751 | 1, 1, left_margin); |
| 752 | ret += fprintf(fp, "\n"); | ||
| 753 | |||
| 754 | return ret; | ||
| 752 | } | 755 | } |
| 753 | 756 | ||
| 754 | static size_t __callchain__fprintf_flat(FILE *fp, | 757 | static size_t __callchain__fprintf_flat(FILE *fp, |
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index a1f4e3669142..cc33486ad9e2 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <stdio.h> | 7 | #include <stdio.h> |
| 8 | #include <unistd.h> | 8 | #include <unistd.h> |
| 9 | #include "map.h" | 9 | #include "map.h" |
| 10 | #include "thread.h" | ||
| 11 | #include "strlist.h" | ||
| 10 | 12 | ||
| 11 | const char *map_type__name[MAP__NR_TYPES] = { | 13 | const char *map_type__name[MAP__NR_TYPES] = { |
| 12 | [MAP__FUNCTION] = "Functions", | 14 | [MAP__FUNCTION] = "Functions", |
| @@ -585,7 +587,21 @@ int machine__init(struct machine *self, const char *root_dir, pid_t pid) | |||
| 585 | self->kmaps.machine = self; | 587 | self->kmaps.machine = self; |
| 586 | self->pid = pid; | 588 | self->pid = pid; |
| 587 | self->root_dir = strdup(root_dir); | 589 | self->root_dir = strdup(root_dir); |
| 588 | return self->root_dir == NULL ? -ENOMEM : 0; | 590 | if (self->root_dir == NULL) |
| 591 | return -ENOMEM; | ||
| 592 | |||
| 593 | if (pid != HOST_KERNEL_ID) { | ||
| 594 | struct thread *thread = machine__findnew_thread(self, pid); | ||
| 595 | char comm[64]; | ||
| 596 | |||
| 597 | if (thread == NULL) | ||
| 598 | return -ENOMEM; | ||
| 599 | |||
| 600 | snprintf(comm, sizeof(comm), "[guest/%d]", pid); | ||
| 601 | thread__set_comm(thread, comm); | ||
| 602 | } | ||
| 603 | |||
| 604 | return 0; | ||
| 589 | } | 605 | } |
| 590 | 606 | ||
| 591 | static void dsos__delete(struct list_head *self) | 607 | static void dsos__delete(struct list_head *self) |
| @@ -680,7 +696,15 @@ struct machine *machines__findnew(struct rb_root *self, pid_t pid) | |||
| 680 | (symbol_conf.guestmount)) { | 696 | (symbol_conf.guestmount)) { |
| 681 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); | 697 | sprintf(path, "%s/%d", symbol_conf.guestmount, pid); |
| 682 | if (access(path, R_OK)) { | 698 | if (access(path, R_OK)) { |
| 683 | pr_err("Can't access file %s\n", path); | 699 | static struct strlist *seen; |
| 700 | |||
| 701 | if (!seen) | ||
| 702 | seen = strlist__new(true, NULL); | ||
| 703 | |||
| 704 | if (!strlist__has_entry(seen, path)) { | ||
| 705 | pr_err("Can't access file %s\n", path); | ||
| 706 | strlist__add(seen, path); | ||
| 707 | } | ||
| 684 | machine = NULL; | 708 | machine = NULL; |
| 685 | goto out; | 709 | goto out; |
| 686 | } | 710 | } |
| @@ -714,3 +738,16 @@ char *machine__mmap_name(struct machine *self, char *bf, size_t size) | |||
| 714 | 738 | ||
| 715 | return bf; | 739 | return bf; |
| 716 | } | 740 | } |
| 741 | |||
| 742 | void machines__set_id_hdr_size(struct rb_root *machines, u16 id_hdr_size) | ||
| 743 | { | ||
| 744 | struct rb_node *node; | ||
| 745 | struct machine *machine; | ||
| 746 | |||
| 747 | for (node = rb_first(machines); node; node = rb_next(node)) { | ||
| 748 | machine = rb_entry(node, struct machine, rb_node); | ||
| 749 | machine->id_hdr_size = id_hdr_size; | ||
| 750 | } | ||
| 751 | |||
| 752 | return; | ||
| 753 | } | ||
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index c14c665d9a25..03a1e9b08b21 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
| @@ -151,6 +151,7 @@ struct machine *machines__add(struct rb_root *self, pid_t pid, | |||
| 151 | struct machine *machines__find_host(struct rb_root *self); | 151 | struct machine *machines__find_host(struct rb_root *self); |
| 152 | struct machine *machines__find(struct rb_root *self, pid_t pid); | 152 | struct machine *machines__find(struct rb_root *self, pid_t pid); |
| 153 | struct machine *machines__findnew(struct rb_root *self, pid_t pid); | 153 | struct machine *machines__findnew(struct rb_root *self, pid_t pid); |
| 154 | void machines__set_id_hdr_size(struct rb_root *self, u16 id_hdr_size); | ||
| 154 | char *machine__mmap_name(struct machine *self, char *bf, size_t size); | 155 | char *machine__mmap_name(struct machine *self, char *bf, size_t size); |
| 155 | int machine__init(struct machine *self, const char *root_dir, pid_t pid); | 156 | int machine__init(struct machine *self, const char *root_dir, pid_t pid); |
| 156 | void machine__exit(struct machine *self); | 157 | void machine__exit(struct machine *self); |
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c index 1aa721d7c10f..74a5af4d33ec 100644 --- a/tools/perf/util/parse-events.c +++ b/tools/perf/util/parse-events.c | |||
| @@ -377,6 +377,7 @@ static int add_tracepoint(struct list_head **list, int *idx, | |||
| 377 | attr.sample_type |= PERF_SAMPLE_RAW; | 377 | attr.sample_type |= PERF_SAMPLE_RAW; |
| 378 | attr.sample_type |= PERF_SAMPLE_TIME; | 378 | attr.sample_type |= PERF_SAMPLE_TIME; |
| 379 | attr.sample_type |= PERF_SAMPLE_CPU; | 379 | attr.sample_type |= PERF_SAMPLE_CPU; |
| 380 | attr.sample_type |= PERF_SAMPLE_PERIOD; | ||
| 380 | attr.sample_period = 1; | 381 | attr.sample_period = 1; |
| 381 | 382 | ||
| 382 | snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); | 383 | snprintf(name, MAX_NAME_LEN, "%s:%s", sys_name, evt_name); |
| @@ -489,6 +490,7 @@ int parse_events_add_breakpoint(struct list_head **list, int *idx, | |||
| 489 | attr.bp_len = HW_BREAKPOINT_LEN_4; | 490 | attr.bp_len = HW_BREAKPOINT_LEN_4; |
| 490 | 491 | ||
| 491 | attr.type = PERF_TYPE_BREAKPOINT; | 492 | attr.type = PERF_TYPE_BREAKPOINT; |
| 493 | attr.sample_period = 1; | ||
| 492 | 494 | ||
| 493 | return add_event(list, idx, &attr, NULL); | 495 | return add_event(list, idx, &attr, NULL); |
| 494 | } | 496 | } |
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c index 8e485592ca20..8e4f0755d2aa 100644 --- a/tools/perf/util/session.c +++ b/tools/perf/util/session.c | |||
| @@ -87,6 +87,7 @@ void perf_session__update_sample_type(struct perf_session *self) | |||
| 87 | self->sample_id_all = perf_evlist__sample_id_all(self->evlist); | 87 | self->sample_id_all = perf_evlist__sample_id_all(self->evlist); |
| 88 | self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); | 88 | self->id_hdr_size = perf_evlist__id_hdr_size(self->evlist); |
| 89 | self->host_machine.id_hdr_size = self->id_hdr_size; | 89 | self->host_machine.id_hdr_size = self->id_hdr_size; |
| 90 | machines__set_id_hdr_size(&self->machines, self->id_hdr_size); | ||
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | int perf_session__create_kernel_maps(struct perf_session *self) | 93 | int perf_session__create_kernel_maps(struct perf_session *self) |
| @@ -918,7 +919,9 @@ static struct machine * | |||
| 918 | { | 919 | { |
| 919 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; | 920 | const u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK; |
| 920 | 921 | ||
| 921 | if (cpumode == PERF_RECORD_MISC_GUEST_KERNEL && perf_guest) { | 922 | if (perf_guest && |
| 923 | ((cpumode == PERF_RECORD_MISC_GUEST_KERNEL) || | ||
| 924 | (cpumode == PERF_RECORD_MISC_GUEST_USER))) { | ||
| 922 | u32 pid; | 925 | u32 pid; |
| 923 | 926 | ||
| 924 | if (event->header.type == PERF_RECORD_MMAP) | 927 | if (event->header.type == PERF_RECORD_MMAP) |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 50958bbeb26a..fdad4eeeb429 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #define NT_GNU_BUILD_ID 3 | 29 | #define NT_GNU_BUILD_ID 3 |
| 30 | #endif | 30 | #endif |
| 31 | 31 | ||
| 32 | static void dso_cache__free(struct rb_root *root); | ||
| 32 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | 33 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); |
| 33 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); | 34 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); |
| 34 | static void dsos__add(struct list_head *head, struct dso *dso); | 35 | static void dsos__add(struct list_head *head, struct dso *dso); |
| @@ -48,6 +49,31 @@ struct symbol_conf symbol_conf = { | |||
| 48 | .symfs = "", | 49 | .symfs = "", |
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| 52 | static enum dso_binary_type binary_type_symtab[] = { | ||
| 53 | DSO_BINARY_TYPE__KALLSYMS, | ||
| 54 | DSO_BINARY_TYPE__GUEST_KALLSYMS, | ||
| 55 | DSO_BINARY_TYPE__JAVA_JIT, | ||
| 56 | DSO_BINARY_TYPE__DEBUGLINK, | ||
| 57 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
| 58 | DSO_BINARY_TYPE__FEDORA_DEBUGINFO, | ||
| 59 | DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, | ||
| 60 | DSO_BINARY_TYPE__BUILDID_DEBUGINFO, | ||
| 61 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
| 62 | DSO_BINARY_TYPE__GUEST_KMODULE, | ||
| 63 | DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, | ||
| 64 | DSO_BINARY_TYPE__NOT_FOUND, | ||
| 65 | }; | ||
| 66 | |||
| 67 | #define DSO_BINARY_TYPE__SYMTAB_CNT sizeof(binary_type_symtab) | ||
| 68 | |||
| 69 | static enum dso_binary_type binary_type_data[] = { | ||
| 70 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
| 71 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
| 72 | DSO_BINARY_TYPE__NOT_FOUND, | ||
| 73 | }; | ||
| 74 | |||
| 75 | #define DSO_BINARY_TYPE__DATA_CNT sizeof(binary_type_data) | ||
| 76 | |||
| 51 | int dso__name_len(const struct dso *dso) | 77 | int dso__name_len(const struct dso *dso) |
| 52 | { | 78 | { |
| 53 | if (!dso) | 79 | if (!dso) |
| @@ -318,7 +344,9 @@ struct dso *dso__new(const char *name) | |||
| 318 | dso__set_short_name(dso, dso->name); | 344 | dso__set_short_name(dso, dso->name); |
| 319 | for (i = 0; i < MAP__NR_TYPES; ++i) | 345 | for (i = 0; i < MAP__NR_TYPES; ++i) |
| 320 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; | 346 | dso->symbols[i] = dso->symbol_names[i] = RB_ROOT; |
| 321 | dso->symtab_type = SYMTAB__NOT_FOUND; | 347 | dso->cache = RB_ROOT; |
| 348 | dso->symtab_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
| 349 | dso->data_type = DSO_BINARY_TYPE__NOT_FOUND; | ||
| 322 | dso->loaded = 0; | 350 | dso->loaded = 0; |
| 323 | dso->sorted_by_name = 0; | 351 | dso->sorted_by_name = 0; |
| 324 | dso->has_build_id = 0; | 352 | dso->has_build_id = 0; |
| @@ -352,6 +380,7 @@ void dso__delete(struct dso *dso) | |||
| 352 | free((char *)dso->short_name); | 380 | free((char *)dso->short_name); |
| 353 | if (dso->lname_alloc) | 381 | if (dso->lname_alloc) |
| 354 | free(dso->long_name); | 382 | free(dso->long_name); |
| 383 | dso_cache__free(&dso->cache); | ||
| 355 | free(dso); | 384 | free(dso); |
| 356 | } | 385 | } |
| 357 | 386 | ||
| @@ -806,9 +835,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
| 806 | symbols__fixup_end(&dso->symbols[map->type]); | 835 | symbols__fixup_end(&dso->symbols[map->type]); |
| 807 | 836 | ||
| 808 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 837 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
| 809 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; | 838 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KALLSYMS; |
| 810 | else | 839 | else |
| 811 | dso->symtab_type = SYMTAB__KALLSYMS; | 840 | dso->symtab_type = DSO_BINARY_TYPE__KALLSYMS; |
| 812 | 841 | ||
| 813 | return dso__split_kallsyms(dso, map, filter); | 842 | return dso__split_kallsyms(dso, map, filter); |
| 814 | } | 843 | } |
| @@ -1660,32 +1689,110 @@ out: | |||
| 1660 | char dso__symtab_origin(const struct dso *dso) | 1689 | char dso__symtab_origin(const struct dso *dso) |
| 1661 | { | 1690 | { |
| 1662 | static const char origin[] = { | 1691 | static const char origin[] = { |
| 1663 | [SYMTAB__KALLSYMS] = 'k', | 1692 | [DSO_BINARY_TYPE__KALLSYMS] = 'k', |
| 1664 | [SYMTAB__JAVA_JIT] = 'j', | 1693 | [DSO_BINARY_TYPE__JAVA_JIT] = 'j', |
| 1665 | [SYMTAB__DEBUGLINK] = 'l', | 1694 | [DSO_BINARY_TYPE__DEBUGLINK] = 'l', |
| 1666 | [SYMTAB__BUILD_ID_CACHE] = 'B', | 1695 | [DSO_BINARY_TYPE__BUILD_ID_CACHE] = 'B', |
| 1667 | [SYMTAB__FEDORA_DEBUGINFO] = 'f', | 1696 | [DSO_BINARY_TYPE__FEDORA_DEBUGINFO] = 'f', |
| 1668 | [SYMTAB__UBUNTU_DEBUGINFO] = 'u', | 1697 | [DSO_BINARY_TYPE__UBUNTU_DEBUGINFO] = 'u', |
| 1669 | [SYMTAB__BUILDID_DEBUGINFO] = 'b', | 1698 | [DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b', |
| 1670 | [SYMTAB__SYSTEM_PATH_DSO] = 'd', | 1699 | [DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd', |
| 1671 | [SYMTAB__SYSTEM_PATH_KMODULE] = 'K', | 1700 | [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K', |
| 1672 | [SYMTAB__GUEST_KALLSYMS] = 'g', | 1701 | [DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g', |
| 1673 | [SYMTAB__GUEST_KMODULE] = 'G', | 1702 | [DSO_BINARY_TYPE__GUEST_KMODULE] = 'G', |
| 1674 | }; | 1703 | }; |
| 1675 | 1704 | ||
| 1676 | if (dso == NULL || dso->symtab_type == SYMTAB__NOT_FOUND) | 1705 | if (dso == NULL || dso->symtab_type == DSO_BINARY_TYPE__NOT_FOUND) |
| 1677 | return '!'; | 1706 | return '!'; |
| 1678 | return origin[dso->symtab_type]; | 1707 | return origin[dso->symtab_type]; |
| 1679 | } | 1708 | } |
| 1680 | 1709 | ||
| 1710 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
| 1711 | char *root_dir, char *file, size_t size) | ||
| 1712 | { | ||
| 1713 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
| 1714 | int ret = 0; | ||
| 1715 | |||
| 1716 | switch (type) { | ||
| 1717 | case DSO_BINARY_TYPE__DEBUGLINK: { | ||
| 1718 | char *debuglink; | ||
| 1719 | |||
| 1720 | strncpy(file, dso->long_name, size); | ||
| 1721 | debuglink = file + dso->long_name_len; | ||
| 1722 | while (debuglink != file && *debuglink != '/') | ||
| 1723 | debuglink--; | ||
| 1724 | if (*debuglink == '/') | ||
| 1725 | debuglink++; | ||
| 1726 | filename__read_debuglink(dso->long_name, debuglink, | ||
| 1727 | size - (debuglink - file)); | ||
| 1728 | } | ||
| 1729 | break; | ||
| 1730 | case DSO_BINARY_TYPE__BUILD_ID_CACHE: | ||
| 1731 | /* skip the locally configured cache if a symfs is given */ | ||
| 1732 | if (symbol_conf.symfs[0] || | ||
| 1733 | (dso__build_id_filename(dso, file, size) == NULL)) | ||
| 1734 | ret = -1; | ||
| 1735 | break; | ||
| 1736 | |||
| 1737 | case DSO_BINARY_TYPE__FEDORA_DEBUGINFO: | ||
| 1738 | snprintf(file, size, "%s/usr/lib/debug%s.debug", | ||
| 1739 | symbol_conf.symfs, dso->long_name); | ||
| 1740 | break; | ||
| 1741 | |||
| 1742 | case DSO_BINARY_TYPE__UBUNTU_DEBUGINFO: | ||
| 1743 | snprintf(file, size, "%s/usr/lib/debug%s", | ||
| 1744 | symbol_conf.symfs, dso->long_name); | ||
| 1745 | break; | ||
| 1746 | |||
| 1747 | case DSO_BINARY_TYPE__BUILDID_DEBUGINFO: | ||
| 1748 | if (!dso->has_build_id) { | ||
| 1749 | ret = -1; | ||
| 1750 | break; | ||
| 1751 | } | ||
| 1752 | |||
| 1753 | build_id__sprintf(dso->build_id, | ||
| 1754 | sizeof(dso->build_id), | ||
| 1755 | build_id_hex); | ||
| 1756 | snprintf(file, size, | ||
| 1757 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
| 1758 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | ||
| 1759 | break; | ||
| 1760 | |||
| 1761 | case DSO_BINARY_TYPE__SYSTEM_PATH_DSO: | ||
| 1762 | snprintf(file, size, "%s%s", | ||
| 1763 | symbol_conf.symfs, dso->long_name); | ||
| 1764 | break; | ||
| 1765 | |||
| 1766 | case DSO_BINARY_TYPE__GUEST_KMODULE: | ||
| 1767 | snprintf(file, size, "%s%s%s", symbol_conf.symfs, | ||
| 1768 | root_dir, dso->long_name); | ||
| 1769 | break; | ||
| 1770 | |||
| 1771 | case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE: | ||
| 1772 | snprintf(file, size, "%s%s", symbol_conf.symfs, | ||
| 1773 | dso->long_name); | ||
| 1774 | break; | ||
| 1775 | |||
| 1776 | default: | ||
| 1777 | case DSO_BINARY_TYPE__KALLSYMS: | ||
| 1778 | case DSO_BINARY_TYPE__GUEST_KALLSYMS: | ||
| 1779 | case DSO_BINARY_TYPE__JAVA_JIT: | ||
| 1780 | case DSO_BINARY_TYPE__NOT_FOUND: | ||
| 1781 | ret = -1; | ||
| 1782 | break; | ||
| 1783 | } | ||
| 1784 | |||
| 1785 | return ret; | ||
| 1786 | } | ||
| 1787 | |||
| 1681 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | 1788 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) |
| 1682 | { | 1789 | { |
| 1683 | int size = PATH_MAX; | ||
| 1684 | char *name; | 1790 | char *name; |
| 1685 | int ret = -1; | 1791 | int ret = -1; |
| 1686 | int fd; | 1792 | int fd; |
| 1793 | u_int i; | ||
| 1687 | struct machine *machine; | 1794 | struct machine *machine; |
| 1688 | const char *root_dir; | 1795 | char *root_dir = (char *) ""; |
| 1689 | int want_symtab; | 1796 | int want_symtab; |
| 1690 | 1797 | ||
| 1691 | dso__set_loaded(dso, map->type); | 1798 | dso__set_loaded(dso, map->type); |
| @@ -1700,7 +1807,7 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
| 1700 | else | 1807 | else |
| 1701 | machine = NULL; | 1808 | machine = NULL; |
| 1702 | 1809 | ||
| 1703 | name = malloc(size); | 1810 | name = malloc(PATH_MAX); |
| 1704 | if (!name) | 1811 | if (!name) |
| 1705 | return -1; | 1812 | return -1; |
| 1706 | 1813 | ||
| @@ -1719,81 +1826,27 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter) | |||
| 1719 | } | 1826 | } |
| 1720 | 1827 | ||
| 1721 | ret = dso__load_perf_map(dso, map, filter); | 1828 | ret = dso__load_perf_map(dso, map, filter); |
| 1722 | dso->symtab_type = ret > 0 ? SYMTAB__JAVA_JIT : | 1829 | dso->symtab_type = ret > 0 ? DSO_BINARY_TYPE__JAVA_JIT : |
| 1723 | SYMTAB__NOT_FOUND; | 1830 | DSO_BINARY_TYPE__NOT_FOUND; |
| 1724 | return ret; | 1831 | return ret; |
| 1725 | } | 1832 | } |
| 1726 | 1833 | ||
| 1834 | if (machine) | ||
| 1835 | root_dir = machine->root_dir; | ||
| 1836 | |||
| 1727 | /* Iterate over candidate debug images. | 1837 | /* Iterate over candidate debug images. |
| 1728 | * On the first pass, only load images if they have a full symtab. | 1838 | * On the first pass, only load images if they have a full symtab. |
| 1729 | * Failing that, do a second pass where we accept .dynsym also | 1839 | * Failing that, do a second pass where we accept .dynsym also |
| 1730 | */ | 1840 | */ |
| 1731 | want_symtab = 1; | 1841 | want_symtab = 1; |
| 1732 | restart: | 1842 | restart: |
| 1733 | for (dso->symtab_type = SYMTAB__DEBUGLINK; | 1843 | for (i = 0; i < DSO_BINARY_TYPE__SYMTAB_CNT; i++) { |
| 1734 | dso->symtab_type != SYMTAB__NOT_FOUND; | ||
| 1735 | dso->symtab_type++) { | ||
| 1736 | switch (dso->symtab_type) { | ||
| 1737 | case SYMTAB__DEBUGLINK: { | ||
| 1738 | char *debuglink; | ||
| 1739 | strncpy(name, dso->long_name, size); | ||
| 1740 | debuglink = name + dso->long_name_len; | ||
| 1741 | while (debuglink != name && *debuglink != '/') | ||
| 1742 | debuglink--; | ||
| 1743 | if (*debuglink == '/') | ||
| 1744 | debuglink++; | ||
| 1745 | filename__read_debuglink(dso->long_name, debuglink, | ||
| 1746 | size - (debuglink - name)); | ||
| 1747 | } | ||
| 1748 | break; | ||
| 1749 | case SYMTAB__BUILD_ID_CACHE: | ||
| 1750 | /* skip the locally configured cache if a symfs is given */ | ||
| 1751 | if (symbol_conf.symfs[0] || | ||
| 1752 | (dso__build_id_filename(dso, name, size) == NULL)) { | ||
| 1753 | continue; | ||
| 1754 | } | ||
| 1755 | break; | ||
| 1756 | case SYMTAB__FEDORA_DEBUGINFO: | ||
| 1757 | snprintf(name, size, "%s/usr/lib/debug%s.debug", | ||
| 1758 | symbol_conf.symfs, dso->long_name); | ||
| 1759 | break; | ||
| 1760 | case SYMTAB__UBUNTU_DEBUGINFO: | ||
| 1761 | snprintf(name, size, "%s/usr/lib/debug%s", | ||
| 1762 | symbol_conf.symfs, dso->long_name); | ||
| 1763 | break; | ||
| 1764 | case SYMTAB__BUILDID_DEBUGINFO: { | ||
| 1765 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | ||
| 1766 | 1844 | ||
| 1767 | if (!dso->has_build_id) | 1845 | dso->symtab_type = binary_type_symtab[i]; |
| 1768 | continue; | ||
| 1769 | 1846 | ||
| 1770 | build_id__sprintf(dso->build_id, | 1847 | if (dso__binary_type_file(dso, dso->symtab_type, |
| 1771 | sizeof(dso->build_id), | 1848 | root_dir, name, PATH_MAX)) |
| 1772 | build_id_hex); | 1849 | continue; |
| 1773 | snprintf(name, size, | ||
| 1774 | "%s/usr/lib/debug/.build-id/%.2s/%s.debug", | ||
| 1775 | symbol_conf.symfs, build_id_hex, build_id_hex + 2); | ||
| 1776 | } | ||
| 1777 | break; | ||
| 1778 | case SYMTAB__SYSTEM_PATH_DSO: | ||
| 1779 | snprintf(name, size, "%s%s", | ||
| 1780 | symbol_conf.symfs, dso->long_name); | ||
| 1781 | break; | ||
| 1782 | case SYMTAB__GUEST_KMODULE: | ||
| 1783 | if (map->groups && machine) | ||
| 1784 | root_dir = machine->root_dir; | ||
| 1785 | else | ||
| 1786 | root_dir = ""; | ||
| 1787 | snprintf(name, size, "%s%s%s", symbol_conf.symfs, | ||
| 1788 | root_dir, dso->long_name); | ||
| 1789 | break; | ||
| 1790 | |||
| 1791 | case SYMTAB__SYSTEM_PATH_KMODULE: | ||
| 1792 | snprintf(name, size, "%s%s", symbol_conf.symfs, | ||
| 1793 | dso->long_name); | ||
| 1794 | break; | ||
| 1795 | default:; | ||
| 1796 | } | ||
| 1797 | 1850 | ||
| 1798 | /* Name is now the name of the next image to try */ | 1851 | /* Name is now the name of the next image to try */ |
| 1799 | fd = open(name, O_RDONLY); | 1852 | fd = open(name, O_RDONLY); |
| @@ -2010,9 +2063,9 @@ struct map *machine__new_module(struct machine *machine, u64 start, | |||
| 2010 | return NULL; | 2063 | return NULL; |
| 2011 | 2064 | ||
| 2012 | if (machine__is_host(machine)) | 2065 | if (machine__is_host(machine)) |
| 2013 | dso->symtab_type = SYMTAB__SYSTEM_PATH_KMODULE; | 2066 | dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE; |
| 2014 | else | 2067 | else |
| 2015 | dso->symtab_type = SYMTAB__GUEST_KMODULE; | 2068 | dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE; |
| 2016 | map_groups__insert(&machine->kmaps, map); | 2069 | map_groups__insert(&machine->kmaps, map); |
| 2017 | return map; | 2070 | return map; |
| 2018 | } | 2071 | } |
| @@ -2564,8 +2617,15 @@ int machine__create_kernel_maps(struct machine *machine) | |||
| 2564 | __machine__create_kernel_maps(machine, kernel) < 0) | 2617 | __machine__create_kernel_maps(machine, kernel) < 0) |
| 2565 | return -1; | 2618 | return -1; |
| 2566 | 2619 | ||
| 2567 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) | 2620 | if (symbol_conf.use_modules && machine__create_modules(machine) < 0) { |
| 2568 | pr_debug("Problems creating module maps, continuing anyway...\n"); | 2621 | if (machine__is_host(machine)) |
| 2622 | pr_debug("Problems creating module maps, " | ||
| 2623 | "continuing anyway...\n"); | ||
| 2624 | else | ||
| 2625 | pr_debug("Problems creating module maps for guest %d, " | ||
| 2626 | "continuing anyway...\n", machine->pid); | ||
| 2627 | } | ||
| 2628 | |||
| 2569 | /* | 2629 | /* |
| 2570 | * Now that we have all the maps created, just set the ->end of them: | 2630 | * Now that we have all the maps created, just set the ->end of them: |
| 2571 | */ | 2631 | */ |
| @@ -2905,3 +2965,218 @@ struct map *dso__new_map(const char *name) | |||
| 2905 | 2965 | ||
| 2906 | return map; | 2966 | return map; |
| 2907 | } | 2967 | } |
| 2968 | |||
| 2969 | static int open_dso(struct dso *dso, struct machine *machine) | ||
| 2970 | { | ||
| 2971 | char *root_dir = (char *) ""; | ||
| 2972 | char *name; | ||
| 2973 | int fd; | ||
| 2974 | |||
| 2975 | name = malloc(PATH_MAX); | ||
| 2976 | if (!name) | ||
| 2977 | return -ENOMEM; | ||
| 2978 | |||
| 2979 | if (machine) | ||
| 2980 | root_dir = machine->root_dir; | ||
| 2981 | |||
| 2982 | if (dso__binary_type_file(dso, dso->data_type, | ||
| 2983 | root_dir, name, PATH_MAX)) { | ||
| 2984 | free(name); | ||
| 2985 | return -EINVAL; | ||
| 2986 | } | ||
| 2987 | |||
| 2988 | fd = open(name, O_RDONLY); | ||
| 2989 | free(name); | ||
| 2990 | return fd; | ||
| 2991 | } | ||
| 2992 | |||
| 2993 | int dso__data_fd(struct dso *dso, struct machine *machine) | ||
| 2994 | { | ||
| 2995 | int i = 0; | ||
| 2996 | |||
| 2997 | if (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND) | ||
| 2998 | return open_dso(dso, machine); | ||
| 2999 | |||
| 3000 | do { | ||
| 3001 | int fd; | ||
| 3002 | |||
| 3003 | dso->data_type = binary_type_data[i++]; | ||
| 3004 | |||
| 3005 | fd = open_dso(dso, machine); | ||
| 3006 | if (fd >= 0) | ||
| 3007 | return fd; | ||
| 3008 | |||
| 3009 | } while (dso->data_type != DSO_BINARY_TYPE__NOT_FOUND); | ||
| 3010 | |||
| 3011 | return -EINVAL; | ||
| 3012 | } | ||
| 3013 | |||
| 3014 | static void | ||
| 3015 | dso_cache__free(struct rb_root *root) | ||
| 3016 | { | ||
| 3017 | struct rb_node *next = rb_first(root); | ||
| 3018 | |||
| 3019 | while (next) { | ||
| 3020 | struct dso_cache *cache; | ||
| 3021 | |||
| 3022 | cache = rb_entry(next, struct dso_cache, rb_node); | ||
| 3023 | next = rb_next(&cache->rb_node); | ||
| 3024 | rb_erase(&cache->rb_node, root); | ||
| 3025 | free(cache); | ||
| 3026 | } | ||
| 3027 | } | ||
| 3028 | |||
| 3029 | static struct dso_cache* | ||
| 3030 | dso_cache__find(struct rb_root *root, u64 offset) | ||
| 3031 | { | ||
| 3032 | struct rb_node **p = &root->rb_node; | ||
| 3033 | struct rb_node *parent = NULL; | ||
| 3034 | struct dso_cache *cache; | ||
| 3035 | |||
| 3036 | while (*p != NULL) { | ||
| 3037 | u64 end; | ||
| 3038 | |||
| 3039 | parent = *p; | ||
| 3040 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
| 3041 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
| 3042 | |||
| 3043 | if (offset < cache->offset) | ||
| 3044 | p = &(*p)->rb_left; | ||
| 3045 | else if (offset >= end) | ||
| 3046 | p = &(*p)->rb_right; | ||
| 3047 | else | ||
| 3048 | return cache; | ||
| 3049 | } | ||
| 3050 | return NULL; | ||
| 3051 | } | ||
| 3052 | |||
| 3053 | static void | ||
| 3054 | dso_cache__insert(struct rb_root *root, struct dso_cache *new) | ||
| 3055 | { | ||
| 3056 | struct rb_node **p = &root->rb_node; | ||
| 3057 | struct rb_node *parent = NULL; | ||
| 3058 | struct dso_cache *cache; | ||
| 3059 | u64 offset = new->offset; | ||
| 3060 | |||
| 3061 | while (*p != NULL) { | ||
| 3062 | u64 end; | ||
| 3063 | |||
| 3064 | parent = *p; | ||
| 3065 | cache = rb_entry(parent, struct dso_cache, rb_node); | ||
| 3066 | end = cache->offset + DSO__DATA_CACHE_SIZE; | ||
| 3067 | |||
| 3068 | if (offset < cache->offset) | ||
| 3069 | p = &(*p)->rb_left; | ||
| 3070 | else if (offset >= end) | ||
| 3071 | p = &(*p)->rb_right; | ||
| 3072 | } | ||
| 3073 | |||
| 3074 | rb_link_node(&new->rb_node, parent, p); | ||
| 3075 | rb_insert_color(&new->rb_node, root); | ||
| 3076 | } | ||
| 3077 | |||
| 3078 | static ssize_t | ||
| 3079 | dso_cache__memcpy(struct dso_cache *cache, u64 offset, | ||
| 3080 | u8 *data, u64 size) | ||
| 3081 | { | ||
| 3082 | u64 cache_offset = offset - cache->offset; | ||
| 3083 | u64 cache_size = min(cache->size - cache_offset, size); | ||
| 3084 | |||
| 3085 | memcpy(data, cache->data + cache_offset, cache_size); | ||
| 3086 | return cache_size; | ||
| 3087 | } | ||
| 3088 | |||
| 3089 | static ssize_t | ||
| 3090 | dso_cache__read(struct dso *dso, struct machine *machine, | ||
| 3091 | u64 offset, u8 *data, ssize_t size) | ||
| 3092 | { | ||
| 3093 | struct dso_cache *cache; | ||
| 3094 | ssize_t ret; | ||
| 3095 | int fd; | ||
| 3096 | |||
| 3097 | fd = dso__data_fd(dso, machine); | ||
| 3098 | if (fd < 0) | ||
| 3099 | return -1; | ||
| 3100 | |||
| 3101 | do { | ||
| 3102 | u64 cache_offset; | ||
| 3103 | |||
| 3104 | ret = -ENOMEM; | ||
| 3105 | |||
| 3106 | cache = zalloc(sizeof(*cache) + DSO__DATA_CACHE_SIZE); | ||
| 3107 | if (!cache) | ||
| 3108 | break; | ||
| 3109 | |||
| 3110 | cache_offset = offset & DSO__DATA_CACHE_MASK; | ||
| 3111 | ret = -EINVAL; | ||
| 3112 | |||
| 3113 | if (-1 == lseek(fd, cache_offset, SEEK_SET)) | ||
| 3114 | break; | ||
| 3115 | |||
| 3116 | ret = read(fd, cache->data, DSO__DATA_CACHE_SIZE); | ||
| 3117 | if (ret <= 0) | ||
| 3118 | break; | ||
| 3119 | |||
| 3120 | cache->offset = cache_offset; | ||
| 3121 | cache->size = ret; | ||
| 3122 | dso_cache__insert(&dso->cache, cache); | ||
| 3123 | |||
| 3124 | ret = dso_cache__memcpy(cache, offset, data, size); | ||
| 3125 | |||
| 3126 | } while (0); | ||
| 3127 | |||
| 3128 | if (ret <= 0) | ||
| 3129 | free(cache); | ||
| 3130 | |||
| 3131 | close(fd); | ||
| 3132 | return ret; | ||
| 3133 | } | ||
| 3134 | |||
| 3135 | static ssize_t dso_cache_read(struct dso *dso, struct machine *machine, | ||
| 3136 | u64 offset, u8 *data, ssize_t size) | ||
| 3137 | { | ||
| 3138 | struct dso_cache *cache; | ||
| 3139 | |||
| 3140 | cache = dso_cache__find(&dso->cache, offset); | ||
| 3141 | if (cache) | ||
| 3142 | return dso_cache__memcpy(cache, offset, data, size); | ||
| 3143 | else | ||
| 3144 | return dso_cache__read(dso, machine, offset, data, size); | ||
| 3145 | } | ||
| 3146 | |||
| 3147 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
| 3148 | u64 offset, u8 *data, ssize_t size) | ||
| 3149 | { | ||
| 3150 | ssize_t r = 0; | ||
| 3151 | u8 *p = data; | ||
| 3152 | |||
| 3153 | do { | ||
| 3154 | ssize_t ret; | ||
| 3155 | |||
| 3156 | ret = dso_cache_read(dso, machine, offset, p, size); | ||
| 3157 | if (ret < 0) | ||
| 3158 | return ret; | ||
| 3159 | |||
| 3160 | /* Reached EOF, return what we have. */ | ||
| 3161 | if (!ret) | ||
| 3162 | break; | ||
| 3163 | |||
| 3164 | BUG_ON(ret > size); | ||
| 3165 | |||
| 3166 | r += ret; | ||
| 3167 | p += ret; | ||
| 3168 | offset += ret; | ||
| 3169 | size -= ret; | ||
| 3170 | |||
| 3171 | } while (size); | ||
| 3172 | |||
| 3173 | return r; | ||
| 3174 | } | ||
| 3175 | |||
| 3176 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
| 3177 | struct machine *machine, u64 addr, | ||
| 3178 | u8 *data, ssize_t size) | ||
| 3179 | { | ||
| 3180 | u64 offset = map->map_ip(map, addr); | ||
| 3181 | return dso__data_read_offset(dso, machine, offset, data, size); | ||
| 3182 | } | ||
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index a884b99017f0..1fe733a1e21f 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -155,6 +155,21 @@ struct addr_location { | |||
| 155 | s32 cpu; | 155 | s32 cpu; |
| 156 | }; | 156 | }; |
| 157 | 157 | ||
| 158 | enum dso_binary_type { | ||
| 159 | DSO_BINARY_TYPE__KALLSYMS = 0, | ||
| 160 | DSO_BINARY_TYPE__GUEST_KALLSYMS, | ||
| 161 | DSO_BINARY_TYPE__JAVA_JIT, | ||
| 162 | DSO_BINARY_TYPE__DEBUGLINK, | ||
| 163 | DSO_BINARY_TYPE__BUILD_ID_CACHE, | ||
| 164 | DSO_BINARY_TYPE__FEDORA_DEBUGINFO, | ||
| 165 | DSO_BINARY_TYPE__UBUNTU_DEBUGINFO, | ||
| 166 | DSO_BINARY_TYPE__BUILDID_DEBUGINFO, | ||
| 167 | DSO_BINARY_TYPE__SYSTEM_PATH_DSO, | ||
| 168 | DSO_BINARY_TYPE__GUEST_KMODULE, | ||
| 169 | DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE, | ||
| 170 | DSO_BINARY_TYPE__NOT_FOUND, | ||
| 171 | }; | ||
| 172 | |||
| 158 | enum dso_kernel_type { | 173 | enum dso_kernel_type { |
| 159 | DSO_TYPE_USER = 0, | 174 | DSO_TYPE_USER = 0, |
| 160 | DSO_TYPE_KERNEL, | 175 | DSO_TYPE_KERNEL, |
| @@ -167,19 +182,31 @@ enum dso_swap_type { | |||
| 167 | DSO_SWAP__YES, | 182 | DSO_SWAP__YES, |
| 168 | }; | 183 | }; |
| 169 | 184 | ||
| 185 | #define DSO__DATA_CACHE_SIZE 4096 | ||
| 186 | #define DSO__DATA_CACHE_MASK ~(DSO__DATA_CACHE_SIZE - 1) | ||
| 187 | |||
| 188 | struct dso_cache { | ||
| 189 | struct rb_node rb_node; | ||
| 190 | u64 offset; | ||
| 191 | u64 size; | ||
| 192 | char data[0]; | ||
| 193 | }; | ||
| 194 | |||
| 170 | struct dso { | 195 | struct dso { |
| 171 | struct list_head node; | 196 | struct list_head node; |
| 172 | struct rb_root symbols[MAP__NR_TYPES]; | 197 | struct rb_root symbols[MAP__NR_TYPES]; |
| 173 | struct rb_root symbol_names[MAP__NR_TYPES]; | 198 | struct rb_root symbol_names[MAP__NR_TYPES]; |
| 199 | struct rb_root cache; | ||
| 174 | enum dso_kernel_type kernel; | 200 | enum dso_kernel_type kernel; |
| 175 | enum dso_swap_type needs_swap; | 201 | enum dso_swap_type needs_swap; |
| 202 | enum dso_binary_type symtab_type; | ||
| 203 | enum dso_binary_type data_type; | ||
| 176 | u8 adjust_symbols:1; | 204 | u8 adjust_symbols:1; |
| 177 | u8 has_build_id:1; | 205 | u8 has_build_id:1; |
| 178 | u8 hit:1; | 206 | u8 hit:1; |
| 179 | u8 annotate_warned:1; | 207 | u8 annotate_warned:1; |
| 180 | u8 sname_alloc:1; | 208 | u8 sname_alloc:1; |
| 181 | u8 lname_alloc:1; | 209 | u8 lname_alloc:1; |
| 182 | unsigned char symtab_type; | ||
| 183 | u8 sorted_by_name; | 210 | u8 sorted_by_name; |
| 184 | u8 loaded; | 211 | u8 loaded; |
| 185 | u8 build_id[BUILD_ID_SIZE]; | 212 | u8 build_id[BUILD_ID_SIZE]; |
| @@ -253,21 +280,6 @@ size_t dso__fprintf_symbols_by_name(struct dso *dso, | |||
| 253 | enum map_type type, FILE *fp); | 280 | enum map_type type, FILE *fp); |
| 254 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | 281 | size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); |
| 255 | 282 | ||
| 256 | enum symtab_type { | ||
| 257 | SYMTAB__KALLSYMS = 0, | ||
| 258 | SYMTAB__GUEST_KALLSYMS, | ||
| 259 | SYMTAB__JAVA_JIT, | ||
| 260 | SYMTAB__DEBUGLINK, | ||
| 261 | SYMTAB__BUILD_ID_CACHE, | ||
| 262 | SYMTAB__FEDORA_DEBUGINFO, | ||
| 263 | SYMTAB__UBUNTU_DEBUGINFO, | ||
| 264 | SYMTAB__BUILDID_DEBUGINFO, | ||
| 265 | SYMTAB__SYSTEM_PATH_DSO, | ||
| 266 | SYMTAB__GUEST_KMODULE, | ||
| 267 | SYMTAB__SYSTEM_PATH_KMODULE, | ||
| 268 | SYMTAB__NOT_FOUND, | ||
| 269 | }; | ||
| 270 | |||
| 271 | char dso__symtab_origin(const struct dso *dso); | 283 | char dso__symtab_origin(const struct dso *dso); |
| 272 | void dso__set_long_name(struct dso *dso, char *name); | 284 | void dso__set_long_name(struct dso *dso, char *name); |
| 273 | void dso__set_build_id(struct dso *dso, void *build_id); | 285 | void dso__set_build_id(struct dso *dso, void *build_id); |
| @@ -304,4 +316,14 @@ bool symbol_type__is_a(char symbol_type, enum map_type map_type); | |||
| 304 | 316 | ||
| 305 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); | 317 | size_t machine__fprintf_vmlinux_path(struct machine *machine, FILE *fp); |
| 306 | 318 | ||
| 319 | int dso__binary_type_file(struct dso *dso, enum dso_binary_type type, | ||
| 320 | char *root_dir, char *file, size_t size); | ||
| 321 | |||
| 322 | int dso__data_fd(struct dso *dso, struct machine *machine); | ||
| 323 | ssize_t dso__data_read_offset(struct dso *dso, struct machine *machine, | ||
| 324 | u64 offset, u8 *data, ssize_t size); | ||
| 325 | ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | ||
| 326 | struct machine *machine, u64 addr, | ||
| 327 | u8 *data, ssize_t size); | ||
| 328 | int dso__test_data(void); | ||
| 307 | #endif /* __PERF_SYMBOL */ | 329 | #endif /* __PERF_SYMBOL */ |
diff --git a/tools/perf/util/target.c b/tools/perf/util/target.c index 1064d5b148ad..3f59c496e64c 100644 --- a/tools/perf/util/target.c +++ b/tools/perf/util/target.c | |||
| @@ -110,8 +110,17 @@ int perf_target__strerror(struct perf_target *target, int errnum, | |||
| 110 | int idx; | 110 | int idx; |
| 111 | const char *msg; | 111 | const char *msg; |
| 112 | 112 | ||
| 113 | BUG_ON(buflen > 0); | ||
| 114 | |||
| 113 | if (errnum >= 0) { | 115 | if (errnum >= 0) { |
| 114 | strerror_r(errnum, buf, buflen); | 116 | const char *err = strerror_r(errnum, buf, buflen); |
| 117 | |||
| 118 | if (err != buf) { | ||
| 119 | size_t len = strlen(err); | ||
| 120 | char *c = mempcpy(buf, err, min(buflen - 1, len)); | ||
| 121 | *c = '\0'; | ||
| 122 | } | ||
| 123 | |||
| 115 | return 0; | 124 | return 0; |
| 116 | } | 125 | } |
| 117 | 126 | ||
