diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/Makefile | 9 | ||||
-rw-r--r-- | tools/perf/builtin-record.c | 3 | ||||
-rw-r--r-- | tools/perf/builtin-test.c | 2 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 9 | ||||
-rw-r--r-- | tools/perf/util/event.c | 5 | ||||
-rw-r--r-- | tools/perf/util/event.h | 2 | ||||
-rw-r--r-- | tools/perf/util/evlist.c | 13 | ||||
-rw-r--r-- | tools/perf/util/evlist.h | 1 | ||||
-rw-r--r-- | tools/perf/util/evsel.c | 57 | ||||
-rw-r--r-- | tools/perf/util/probe-finder.c | 2 | ||||
-rw-r--r-- | tools/perf/util/python.c | 2 | ||||
-rw-r--r-- | tools/perf/util/session.h | 3 | ||||
-rw-r--r-- | tools/perf/util/sort.c | 10 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 153 |
14 files changed, 213 insertions, 58 deletions
diff --git a/tools/perf/Makefile b/tools/perf/Makefile index 3b8f7b80376b..e9d5c271db69 100644 --- a/tools/perf/Makefile +++ b/tools/perf/Makefile | |||
@@ -30,6 +30,8 @@ endif | |||
30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. | 30 | # Define EXTRA_CFLAGS=-m64 or EXTRA_CFLAGS=-m32 as appropriate for cross-builds. |
31 | # | 31 | # |
32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. | 32 | # Define NO_DWARF if you do not want debug-info analysis feature at all. |
33 | # | ||
34 | # Define WERROR=0 to disable treating any warnings as errors. | ||
33 | 35 | ||
34 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE | 36 | $(OUTPUT)PERF-VERSION-FILE: .FORCE-PERF-VERSION-FILE |
35 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) | 37 | @$(SHELL_PATH) util/PERF-VERSION-GEN $(OUTPUT) |
@@ -63,6 +65,11 @@ ifeq ($(ARCH),x86_64) | |||
63 | endif | 65 | endif |
64 | endif | 66 | endif |
65 | 67 | ||
68 | # Treat warnings as errors unless directed not to | ||
69 | ifneq ($(WERROR),0) | ||
70 | CFLAGS_WERROR := -Werror | ||
71 | endif | ||
72 | |||
66 | # | 73 | # |
67 | # Include saner warnings here, which can catch bugs: | 74 | # Include saner warnings here, which can catch bugs: |
68 | # | 75 | # |
@@ -95,7 +102,7 @@ ifndef PERF_DEBUG | |||
95 | CFLAGS_OPTIMIZE = -O6 | 102 | CFLAGS_OPTIMIZE = -O6 |
96 | endif | 103 | endif |
97 | 104 | ||
98 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) | 105 | CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) |
99 | EXTLIBS = -lpthread -lrt -lelf -lm | 106 | EXTLIBS = -lpthread -lrt -lelf -lm |
100 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 | 107 | ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 |
101 | ALL_LDFLAGS = $(LDFLAGS) | 108 | ALL_LDFLAGS = $(LDFLAGS) |
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c index 042117f8fffa..dd6467872f60 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -174,6 +174,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | |||
174 | struct perf_event_attr *attr = &evsel->attr; | 174 | struct perf_event_attr *attr = &evsel->attr; |
175 | int track = !evsel->idx; /* only the first counter needs these */ | 175 | int track = !evsel->idx; /* only the first counter needs these */ |
176 | 176 | ||
177 | attr->disabled = 1; | ||
177 | attr->inherit = !no_inherit; | 178 | attr->inherit = !no_inherit; |
178 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 179 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
179 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 180 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
@@ -686,6 +687,8 @@ static int __cmd_record(int argc, const char **argv) | |||
686 | } | 687 | } |
687 | } | 688 | } |
688 | 689 | ||
690 | perf_evlist__enable(evsel_list); | ||
691 | |||
689 | /* | 692 | /* |
690 | * Let the child rip | 693 | * Let the child rip |
691 | */ | 694 | */ |
diff --git a/tools/perf/builtin-test.c b/tools/perf/builtin-test.c index 55f4c76f2821..efe696f936e2 100644 --- a/tools/perf/builtin-test.c +++ b/tools/perf/builtin-test.c | |||
@@ -561,7 +561,7 @@ static int test__basic_mmap(void) | |||
561 | } | 561 | } |
562 | 562 | ||
563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, | 563 | err = perf_event__parse_sample(event, attr.sample_type, sample_size, |
564 | false, &sample); | 564 | false, &sample, false); |
565 | if (err) { | 565 | if (err) { |
566 | pr_err("Can't parse sample, err = %d\n", err); | 566 | pr_err("Can't parse sample, err = %d\n", err); |
567 | goto out_munmap; | 567 | goto out_munmap; |
diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index 23c4f71c407a..5ede7d7c9239 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c | |||
@@ -191,7 +191,8 @@ static void __zero_source_counters(struct sym_entry *syme) | |||
191 | symbol__annotate_zero_histograms(sym); | 191 | symbol__annotate_zero_histograms(sym); |
192 | } | 192 | } |
193 | 193 | ||
194 | static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | 194 | static void record_precise_ip(struct sym_entry *syme, struct map *map, |
195 | int counter, u64 ip) | ||
195 | { | 196 | { |
196 | struct annotation *notes; | 197 | struct annotation *notes; |
197 | struct symbol *sym; | 198 | struct symbol *sym; |
@@ -205,8 +206,8 @@ static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) | |||
205 | if (pthread_mutex_trylock(¬es->lock)) | 206 | if (pthread_mutex_trylock(¬es->lock)) |
206 | return; | 207 | return; |
207 | 208 | ||
208 | ip = syme->map->map_ip(syme->map, ip); | 209 | ip = map->map_ip(map, ip); |
209 | symbol__inc_addr_samples(sym, syme->map, counter, ip); | 210 | symbol__inc_addr_samples(sym, map, counter, ip); |
210 | 211 | ||
211 | pthread_mutex_unlock(¬es->lock); | 212 | pthread_mutex_unlock(¬es->lock); |
212 | } | 213 | } |
@@ -810,7 +811,7 @@ static void perf_event__process_sample(const union perf_event *event, | |||
810 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); | 811 | evsel = perf_evlist__id2evsel(top.evlist, sample->id); |
811 | assert(evsel != NULL); | 812 | assert(evsel != NULL); |
812 | syme->count[evsel->idx]++; | 813 | syme->count[evsel->idx]++; |
813 | record_precise_ip(syme, evsel->idx, ip); | 814 | record_precise_ip(syme, al.map, evsel->idx, ip); |
814 | pthread_mutex_lock(&top.active_symbols_lock); | 815 | pthread_mutex_lock(&top.active_symbols_lock); |
815 | if (list_empty(&syme->node) || !syme->node.next) { | 816 | if (list_empty(&syme->node) || !syme->node.next) { |
816 | static bool first = true; | 817 | static bool first = true; |
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 3c1b8a632101..437f8ca679a0 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c | |||
@@ -169,12 +169,17 @@ static int perf_event__synthesize_mmap_events(union perf_event *event, | |||
169 | continue; | 169 | continue; |
170 | pbf += n + 3; | 170 | pbf += n + 3; |
171 | if (*pbf == 'x') { /* vm_exec */ | 171 | if (*pbf == 'x') { /* vm_exec */ |
172 | char anonstr[] = "//anon\n"; | ||
172 | char *execname = strchr(bf, '/'); | 173 | char *execname = strchr(bf, '/'); |
173 | 174 | ||
174 | /* Catch VDSO */ | 175 | /* Catch VDSO */ |
175 | if (execname == NULL) | 176 | if (execname == NULL) |
176 | execname = strstr(bf, "[vdso]"); | 177 | execname = strstr(bf, "[vdso]"); |
177 | 178 | ||
179 | /* Catch anonymous mmaps */ | ||
180 | if ((execname == NULL) && !strstr(bf, "[")) | ||
181 | execname = anonstr; | ||
182 | |||
178 | if (execname == NULL) | 183 | if (execname == NULL) |
179 | continue; | 184 | continue; |
180 | 185 | ||
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h index 1d7f66488a88..357a85b85248 100644 --- a/tools/perf/util/event.h +++ b/tools/perf/util/event.h | |||
@@ -186,6 +186,6 @@ const char *perf_event__name(unsigned int id); | |||
186 | 186 | ||
187 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 187 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
188 | int sample_size, bool sample_id_all, | 188 | int sample_size, bool sample_id_all, |
189 | struct perf_sample *sample); | 189 | struct perf_sample *sample, bool swapped); |
190 | 190 | ||
191 | #endif /* __PERF_RECORD_H */ | 191 | #endif /* __PERF_RECORD_H */ |
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c index c12bd476c6f7..72e9f4886b6d 100644 --- a/tools/perf/util/evlist.c +++ b/tools/perf/util/evlist.c | |||
@@ -113,6 +113,19 @@ void perf_evlist__disable(struct perf_evlist *evlist) | |||
113 | } | 113 | } |
114 | } | 114 | } |
115 | 115 | ||
116 | void perf_evlist__enable(struct perf_evlist *evlist) | ||
117 | { | ||
118 | int cpu, thread; | ||
119 | struct perf_evsel *pos; | ||
120 | |||
121 | for (cpu = 0; cpu < evlist->cpus->nr; cpu++) { | ||
122 | list_for_each_entry(pos, &evlist->entries, node) { | ||
123 | for (thread = 0; thread < evlist->threads->nr; thread++) | ||
124 | ioctl(FD(pos, cpu, thread), PERF_EVENT_IOC_ENABLE); | ||
125 | } | ||
126 | } | ||
127 | } | ||
128 | |||
116 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) | 129 | int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) |
117 | { | 130 | { |
118 | int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; | 131 | int nfds = evlist->cpus->nr * evlist->threads->nr * evlist->nr_entries; |
diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h index ce85ae9ae57a..f34915002745 100644 --- a/tools/perf/util/evlist.h +++ b/tools/perf/util/evlist.h | |||
@@ -54,6 +54,7 @@ int perf_evlist__mmap(struct perf_evlist *evlist, int pages, bool overwrite); | |||
54 | void perf_evlist__munmap(struct perf_evlist *evlist); | 54 | void perf_evlist__munmap(struct perf_evlist *evlist); |
55 | 55 | ||
56 | void perf_evlist__disable(struct perf_evlist *evlist); | 56 | void perf_evlist__disable(struct perf_evlist *evlist); |
57 | void perf_evlist__enable(struct perf_evlist *evlist); | ||
57 | 58 | ||
58 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, | 59 | static inline void perf_evlist__set_maps(struct perf_evlist *evlist, |
59 | struct cpu_map *cpus, | 60 | struct cpu_map *cpus, |
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c index a03a36b7908a..e389815078d3 100644 --- a/tools/perf/util/evsel.c +++ b/tools/perf/util/evsel.c | |||
@@ -7,6 +7,8 @@ | |||
7 | * Released under the GPL v2. (and only v2, not any later version) | 7 | * Released under the GPL v2. (and only v2, not any later version) |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <byteswap.h> | ||
11 | #include "asm/bug.h" | ||
10 | #include "evsel.h" | 12 | #include "evsel.h" |
11 | #include "evlist.h" | 13 | #include "evlist.h" |
12 | #include "util.h" | 14 | #include "util.h" |
@@ -342,10 +344,20 @@ static bool sample_overlap(const union perf_event *event, | |||
342 | 344 | ||
343 | int perf_event__parse_sample(const union perf_event *event, u64 type, | 345 | int perf_event__parse_sample(const union perf_event *event, u64 type, |
344 | int sample_size, bool sample_id_all, | 346 | int sample_size, bool sample_id_all, |
345 | struct perf_sample *data) | 347 | struct perf_sample *data, bool swapped) |
346 | { | 348 | { |
347 | const u64 *array; | 349 | const u64 *array; |
348 | 350 | ||
351 | /* | ||
352 | * used for cross-endian analysis. See git commit 65014ab3 | ||
353 | * for why this goofiness is needed. | ||
354 | */ | ||
355 | union { | ||
356 | u64 val64; | ||
357 | u32 val32[2]; | ||
358 | } u; | ||
359 | |||
360 | |||
349 | data->cpu = data->pid = data->tid = -1; | 361 | data->cpu = data->pid = data->tid = -1; |
350 | data->stream_id = data->id = data->time = -1ULL; | 362 | data->stream_id = data->id = data->time = -1ULL; |
351 | 363 | ||
@@ -366,9 +378,16 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
366 | } | 378 | } |
367 | 379 | ||
368 | if (type & PERF_SAMPLE_TID) { | 380 | if (type & PERF_SAMPLE_TID) { |
369 | u32 *p = (u32 *)array; | 381 | u.val64 = *array; |
370 | data->pid = p[0]; | 382 | if (swapped) { |
371 | data->tid = p[1]; | 383 | /* undo swap of u64, then swap on individual u32s */ |
384 | u.val64 = bswap_64(u.val64); | ||
385 | u.val32[0] = bswap_32(u.val32[0]); | ||
386 | u.val32[1] = bswap_32(u.val32[1]); | ||
387 | } | ||
388 | |||
389 | data->pid = u.val32[0]; | ||
390 | data->tid = u.val32[1]; | ||
372 | array++; | 391 | array++; |
373 | } | 392 | } |
374 | 393 | ||
@@ -395,8 +414,15 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
395 | } | 414 | } |
396 | 415 | ||
397 | if (type & PERF_SAMPLE_CPU) { | 416 | if (type & PERF_SAMPLE_CPU) { |
398 | u32 *p = (u32 *)array; | 417 | |
399 | data->cpu = *p; | 418 | u.val64 = *array; |
419 | if (swapped) { | ||
420 | /* undo swap of u64, then swap on individual u32s */ | ||
421 | u.val64 = bswap_64(u.val64); | ||
422 | u.val32[0] = bswap_32(u.val32[0]); | ||
423 | } | ||
424 | |||
425 | data->cpu = u.val32[0]; | ||
400 | array++; | 426 | array++; |
401 | } | 427 | } |
402 | 428 | ||
@@ -423,18 +449,27 @@ int perf_event__parse_sample(const union perf_event *event, u64 type, | |||
423 | } | 449 | } |
424 | 450 | ||
425 | if (type & PERF_SAMPLE_RAW) { | 451 | if (type & PERF_SAMPLE_RAW) { |
426 | u32 *p = (u32 *)array; | 452 | const u64 *pdata; |
453 | |||
454 | u.val64 = *array; | ||
455 | if (WARN_ONCE(swapped, | ||
456 | "Endianness of raw data not corrected!\n")) { | ||
457 | /* undo swap of u64, then swap on individual u32s */ | ||
458 | u.val64 = bswap_64(u.val64); | ||
459 | u.val32[0] = bswap_32(u.val32[0]); | ||
460 | u.val32[1] = bswap_32(u.val32[1]); | ||
461 | } | ||
427 | 462 | ||
428 | if (sample_overlap(event, array, sizeof(u32))) | 463 | if (sample_overlap(event, array, sizeof(u32))) |
429 | return -EFAULT; | 464 | return -EFAULT; |
430 | 465 | ||
431 | data->raw_size = *p; | 466 | data->raw_size = u.val32[0]; |
432 | p++; | 467 | pdata = (void *) array + sizeof(u32); |
433 | 468 | ||
434 | if (sample_overlap(event, p, data->raw_size)) | 469 | if (sample_overlap(event, pdata, data->raw_size)) |
435 | return -EFAULT; | 470 | return -EFAULT; |
436 | 471 | ||
437 | data->raw_data = p; | 472 | data->raw_data = (void *) pdata; |
438 | } | 473 | } |
439 | 474 | ||
440 | return 0; | 475 | return 0; |
diff --git a/tools/perf/util/probe-finder.c b/tools/perf/util/probe-finder.c index 555fc3864b90..5d732621a462 100644 --- a/tools/perf/util/probe-finder.c +++ b/tools/perf/util/probe-finder.c | |||
@@ -659,7 +659,7 @@ static int find_variable(Dwarf_Die *sc_die, struct probe_finder *pf) | |||
659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) | 659 | if (!die_find_variable_at(&pf->cu_die, pf->pvar->var, 0, &vr_die)) |
660 | ret = -ENOENT; | 660 | ret = -ENOENT; |
661 | } | 661 | } |
662 | if (ret == 0) | 662 | if (ret >= 0) |
663 | ret = convert_variable(&vr_die, pf); | 663 | ret = convert_variable(&vr_die, pf); |
664 | 664 | ||
665 | if (ret < 0) | 665 | if (ret < 0) |
diff --git a/tools/perf/util/python.c b/tools/perf/util/python.c index cbc8f215d4b7..7624324efad4 100644 --- a/tools/perf/util/python.c +++ b/tools/perf/util/python.c | |||
@@ -803,7 +803,7 @@ static PyObject *pyrf_evlist__read_on_cpu(struct pyrf_evlist *pevlist, | |||
803 | first = list_entry(evlist->entries.next, struct perf_evsel, node); | 803 | first = list_entry(evlist->entries.next, struct perf_evsel, node); |
804 | err = perf_event__parse_sample(event, first->attr.sample_type, | 804 | err = perf_event__parse_sample(event, first->attr.sample_type, |
805 | perf_evsel__sample_size(first), | 805 | perf_evsel__sample_size(first), |
806 | sample_id_all, &pevent->sample); | 806 | sample_id_all, &pevent->sample, false); |
807 | if (err) | 807 | if (err) |
808 | return PyErr_Format(PyExc_OSError, | 808 | return PyErr_Format(PyExc_OSError, |
809 | "perf: can't parse sample, err=%d", err); | 809 | "perf: can't parse sample, err=%d", err); |
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h index 170601e67d6b..974d0cbee5e9 100644 --- a/tools/perf/util/session.h +++ b/tools/perf/util/session.h | |||
@@ -162,7 +162,8 @@ static inline int perf_session__parse_sample(struct perf_session *session, | |||
162 | { | 162 | { |
163 | return perf_event__parse_sample(event, session->sample_type, | 163 | return perf_event__parse_sample(event, session->sample_type, |
164 | session->sample_size, | 164 | session->sample_size, |
165 | session->sample_id_all, sample); | 165 | session->sample_id_all, sample, |
166 | session->header.needs_swap); | ||
166 | } | 167 | } |
167 | 168 | ||
168 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, | 169 | struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, |
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c index 401e220566fd..1ee8f1e40f18 100644 --- a/tools/perf/util/sort.c +++ b/tools/perf/util/sort.c | |||
@@ -151,11 +151,17 @@ sort__sym_cmp(struct hist_entry *left, struct hist_entry *right) | |||
151 | { | 151 | { |
152 | u64 ip_l, ip_r; | 152 | u64 ip_l, ip_r; |
153 | 153 | ||
154 | if (!left->ms.sym && !right->ms.sym) | ||
155 | return right->level - left->level; | ||
156 | |||
157 | if (!left->ms.sym || !right->ms.sym) | ||
158 | return cmp_null(left->ms.sym, right->ms.sym); | ||
159 | |||
154 | if (left->ms.sym == right->ms.sym) | 160 | if (left->ms.sym == right->ms.sym) |
155 | return 0; | 161 | return 0; |
156 | 162 | ||
157 | ip_l = left->ms.sym ? left->ms.sym->start : left->ip; | 163 | ip_l = left->ms.sym->start; |
158 | ip_r = right->ms.sym ? right->ms.sym->start : right->ip; | 164 | ip_r = right->ms.sym->start; |
159 | 165 | ||
160 | return (int64_t)(ip_r - ip_l); | 166 | return (int64_t)(ip_r - ip_l); |
161 | } | 167 | } |
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 245e60d6b4e7..077df15ee705 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -76,16 +76,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | |||
76 | 76 | ||
77 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 77 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
78 | { | 78 | { |
79 | symbol_type = toupper(symbol_type); | ||
80 | |||
79 | switch (map_type) { | 81 | switch (map_type) { |
80 | case MAP__FUNCTION: | 82 | case MAP__FUNCTION: |
81 | return symbol_type == 'T' || symbol_type == 'W'; | 83 | return symbol_type == 'T' || symbol_type == 'W'; |
82 | case MAP__VARIABLE: | 84 | case MAP__VARIABLE: |
83 | return symbol_type == 'D' || symbol_type == 'd'; | 85 | return symbol_type == 'D'; |
84 | default: | 86 | default: |
85 | return false; | 87 | return false; |
86 | } | 88 | } |
87 | } | 89 | } |
88 | 90 | ||
91 | static int prefix_underscores_count(const char *str) | ||
92 | { | ||
93 | const char *tail = str; | ||
94 | |||
95 | while (*tail == '_') | ||
96 | tail++; | ||
97 | |||
98 | return tail - str; | ||
99 | } | ||
100 | |||
101 | #define SYMBOL_A 0 | ||
102 | #define SYMBOL_B 1 | ||
103 | |||
104 | static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | ||
105 | { | ||
106 | s64 a; | ||
107 | s64 b; | ||
108 | |||
109 | /* Prefer a symbol with non zero length */ | ||
110 | a = syma->end - syma->start; | ||
111 | b = symb->end - symb->start; | ||
112 | if ((b == 0) && (a > 0)) | ||
113 | return SYMBOL_A; | ||
114 | else if ((a == 0) && (b > 0)) | ||
115 | return SYMBOL_B; | ||
116 | |||
117 | /* Prefer a non weak symbol over a weak one */ | ||
118 | a = syma->binding == STB_WEAK; | ||
119 | b = symb->binding == STB_WEAK; | ||
120 | if (b && !a) | ||
121 | return SYMBOL_A; | ||
122 | if (a && !b) | ||
123 | return SYMBOL_B; | ||
124 | |||
125 | /* Prefer a global symbol over a non global one */ | ||
126 | a = syma->binding == STB_GLOBAL; | ||
127 | b = symb->binding == STB_GLOBAL; | ||
128 | if (a && !b) | ||
129 | return SYMBOL_A; | ||
130 | if (b && !a) | ||
131 | return SYMBOL_B; | ||
132 | |||
133 | /* Prefer a symbol with less underscores */ | ||
134 | a = prefix_underscores_count(syma->name); | ||
135 | b = prefix_underscores_count(symb->name); | ||
136 | if (b > a) | ||
137 | return SYMBOL_A; | ||
138 | else if (a > b) | ||
139 | return SYMBOL_B; | ||
140 | |||
141 | /* If all else fails, choose the symbol with the longest name */ | ||
142 | if (strlen(syma->name) >= strlen(symb->name)) | ||
143 | return SYMBOL_A; | ||
144 | else | ||
145 | return SYMBOL_B; | ||
146 | } | ||
147 | |||
148 | static void symbols__fixup_duplicate(struct rb_root *symbols) | ||
149 | { | ||
150 | struct rb_node *nd; | ||
151 | struct symbol *curr, *next; | ||
152 | |||
153 | nd = rb_first(symbols); | ||
154 | |||
155 | while (nd) { | ||
156 | curr = rb_entry(nd, struct symbol, rb_node); | ||
157 | again: | ||
158 | nd = rb_next(&curr->rb_node); | ||
159 | next = rb_entry(nd, struct symbol, rb_node); | ||
160 | |||
161 | if (!nd) | ||
162 | break; | ||
163 | |||
164 | if (curr->start != next->start) | ||
165 | continue; | ||
166 | |||
167 | if (choose_best_symbol(curr, next) == SYMBOL_A) { | ||
168 | rb_erase(&next->rb_node, symbols); | ||
169 | goto again; | ||
170 | } else { | ||
171 | nd = rb_next(&curr->rb_node); | ||
172 | rb_erase(&curr->rb_node, symbols); | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
89 | static void symbols__fixup_end(struct rb_root *symbols) | 177 | static void symbols__fixup_end(struct rb_root *symbols) |
90 | { | 178 | { |
91 | struct rb_node *nd, *prevnd = rb_first(symbols); | 179 | struct rb_node *nd, *prevnd = rb_first(symbols); |
@@ -440,18 +528,11 @@ int kallsyms__parse(const char *filename, void *arg, | |||
440 | char *line = NULL; | 528 | char *line = NULL; |
441 | size_t n; | 529 | size_t n; |
442 | int err = -1; | 530 | int err = -1; |
443 | u64 prev_start = 0; | ||
444 | char prev_symbol_type = 0; | ||
445 | char *prev_symbol_name; | ||
446 | FILE *file = fopen(filename, "r"); | 531 | FILE *file = fopen(filename, "r"); |
447 | 532 | ||
448 | if (file == NULL) | 533 | if (file == NULL) |
449 | goto out_failure; | 534 | goto out_failure; |
450 | 535 | ||
451 | prev_symbol_name = malloc(KSYM_NAME_LEN); | ||
452 | if (prev_symbol_name == NULL) | ||
453 | goto out_close; | ||
454 | |||
455 | err = 0; | 536 | err = 0; |
456 | 537 | ||
457 | while (!feof(file)) { | 538 | while (!feof(file)) { |
@@ -472,7 +553,7 @@ int kallsyms__parse(const char *filename, void *arg, | |||
472 | if (len + 2 >= line_len) | 553 | if (len + 2 >= line_len) |
473 | continue; | 554 | continue; |
474 | 555 | ||
475 | symbol_type = toupper(line[len]); | 556 | symbol_type = line[len]; |
476 | len += 2; | 557 | len += 2; |
477 | symbol_name = line + len; | 558 | symbol_name = line + len; |
478 | len = line_len - len; | 559 | len = line_len - len; |
@@ -482,24 +563,18 @@ int kallsyms__parse(const char *filename, void *arg, | |||
482 | break; | 563 | break; |
483 | } | 564 | } |
484 | 565 | ||
485 | if (prev_symbol_type) { | 566 | /* |
486 | u64 end = start; | 567 | * module symbols are not sorted so we add all |
487 | if (end != prev_start) | 568 | * symbols with zero length and rely on |
488 | --end; | 569 | * symbols__fixup_end() to fix it up. |
489 | err = process_symbol(arg, prev_symbol_name, | 570 | */ |
490 | prev_symbol_type, prev_start, end); | 571 | err = process_symbol(arg, symbol_name, |
491 | if (err) | 572 | symbol_type, start, start); |
492 | break; | 573 | if (err) |
493 | } | 574 | break; |
494 | |||
495 | memcpy(prev_symbol_name, symbol_name, len + 1); | ||
496 | prev_symbol_type = symbol_type; | ||
497 | prev_start = start; | ||
498 | } | 575 | } |
499 | 576 | ||
500 | free(prev_symbol_name); | ||
501 | free(line); | 577 | free(line); |
502 | out_close: | ||
503 | fclose(file); | 578 | fclose(file); |
504 | return err; | 579 | return err; |
505 | 580 | ||
@@ -705,6 +780,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
705 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 780 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
706 | return -1; | 781 | return -1; |
707 | 782 | ||
783 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
784 | symbols__fixup_end(&dso->symbols[map->type]); | ||
785 | |||
708 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 786 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
709 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; | 787 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; |
710 | else | 788 | else |
@@ -1094,8 +1172,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1094 | if (dso->has_build_id) { | 1172 | if (dso->has_build_id) { |
1095 | u8 build_id[BUILD_ID_SIZE]; | 1173 | u8 build_id[BUILD_ID_SIZE]; |
1096 | 1174 | ||
1097 | if (elf_read_build_id(elf, build_id, | 1175 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) |
1098 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | ||
1099 | goto out_elf_end; | 1176 | goto out_elf_end; |
1100 | 1177 | ||
1101 | if (!dso__build_id_equal(dso, build_id)) | 1178 | if (!dso__build_id_equal(dso, build_id)) |
@@ -1113,6 +1190,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1113 | } | 1190 | } |
1114 | 1191 | ||
1115 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | 1192 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); |
1193 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1194 | opdsec = NULL; | ||
1116 | if (opdsec) | 1195 | if (opdsec) |
1117 | opddata = elf_rawdata(opdsec, NULL); | 1196 | opddata = elf_rawdata(opdsec, NULL); |
1118 | 1197 | ||
@@ -1278,6 +1357,7 @@ new_symbol: | |||
1278 | * For misannotated, zeroed, ASM function sizes. | 1357 | * For misannotated, zeroed, ASM function sizes. |
1279 | */ | 1358 | */ |
1280 | if (nr > 0) { | 1359 | if (nr > 0) { |
1360 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1281 | symbols__fixup_end(&dso->symbols[map->type]); | 1361 | symbols__fixup_end(&dso->symbols[map->type]); |
1282 | if (kmap) { | 1362 | if (kmap) { |
1283 | /* | 1363 | /* |
@@ -1364,8 +1444,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1364 | ptr = data->d_buf; | 1444 | ptr = data->d_buf; |
1365 | while (ptr < (data->d_buf + data->d_size)) { | 1445 | while (ptr < (data->d_buf + data->d_size)) { |
1366 | GElf_Nhdr *nhdr = ptr; | 1446 | GElf_Nhdr *nhdr = ptr; |
1367 | int namesz = NOTE_ALIGN(nhdr->n_namesz), | 1447 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), |
1368 | descsz = NOTE_ALIGN(nhdr->n_descsz); | 1448 | descsz = NOTE_ALIGN(nhdr->n_descsz); |
1369 | const char *name; | 1449 | const char *name; |
1370 | 1450 | ||
1371 | ptr += sizeof(*nhdr); | 1451 | ptr += sizeof(*nhdr); |
@@ -1374,8 +1454,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1374 | if (nhdr->n_type == NT_GNU_BUILD_ID && | 1454 | if (nhdr->n_type == NT_GNU_BUILD_ID && |
1375 | nhdr->n_namesz == sizeof("GNU")) { | 1455 | nhdr->n_namesz == sizeof("GNU")) { |
1376 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | 1456 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { |
1377 | memcpy(bf, ptr, BUILD_ID_SIZE); | 1457 | size_t sz = min(size, descsz); |
1378 | err = BUILD_ID_SIZE; | 1458 | memcpy(bf, ptr, sz); |
1459 | memset(bf + sz, 0, size - sz); | ||
1460 | err = descsz; | ||
1379 | break; | 1461 | break; |
1380 | } | 1462 | } |
1381 | } | 1463 | } |
@@ -1427,7 +1509,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1427 | while (1) { | 1509 | while (1) { |
1428 | char bf[BUFSIZ]; | 1510 | char bf[BUFSIZ]; |
1429 | GElf_Nhdr nhdr; | 1511 | GElf_Nhdr nhdr; |
1430 | int namesz, descsz; | 1512 | size_t namesz, descsz; |
1431 | 1513 | ||
1432 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | 1514 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) |
1433 | break; | 1515 | break; |
@@ -1436,15 +1518,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1436 | descsz = NOTE_ALIGN(nhdr.n_descsz); | 1518 | descsz = NOTE_ALIGN(nhdr.n_descsz); |
1437 | if (nhdr.n_type == NT_GNU_BUILD_ID && | 1519 | if (nhdr.n_type == NT_GNU_BUILD_ID && |
1438 | nhdr.n_namesz == sizeof("GNU")) { | 1520 | nhdr.n_namesz == sizeof("GNU")) { |
1439 | if (read(fd, bf, namesz) != namesz) | 1521 | if (read(fd, bf, namesz) != (ssize_t)namesz) |
1440 | break; | 1522 | break; |
1441 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | 1523 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { |
1442 | if (read(fd, build_id, | 1524 | size_t sz = min(descsz, size); |
1443 | BUILD_ID_SIZE) == BUILD_ID_SIZE) { | 1525 | if (read(fd, build_id, sz) == (ssize_t)sz) { |
1526 | memset(build_id + sz, 0, size - sz); | ||
1444 | err = 0; | 1527 | err = 0; |
1445 | break; | 1528 | break; |
1446 | } | 1529 | } |
1447 | } else if (read(fd, bf, descsz) != descsz) | 1530 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) |
1448 | break; | 1531 | break; |
1449 | } else { | 1532 | } else { |
1450 | int n = namesz + descsz; | 1533 | int n = namesz + descsz; |