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 | ||