diff options
author | David S. Miller <davem@davemloft.net> | 2011-10-07 13:38:43 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-10-07 13:38:43 -0400 |
commit | 88c5100c28b02c4b2b2c6f6fafbbd76d90f698b9 (patch) | |
tree | 08c4399e0341f7eb0ccb24e15f2cab687275c2a4 /tools | |
parent | 8083f0fc969d9b5353061a7a6f963405057e26b1 (diff) | |
parent | 3ee72ca99288f1de95ec9c570e43f531c8799f06 (diff) |
Merge branch 'master' of github.com:davem330/net
Conflicts:
net/batman-adv/soft-interface.c
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 6b0519f885e4..f4c3fbee4bad 100644 --- a/tools/perf/builtin-record.c +++ b/tools/perf/builtin-record.c | |||
@@ -161,6 +161,7 @@ static void config_attr(struct perf_evsel *evsel, struct perf_evlist *evlist) | |||
161 | struct perf_event_attr *attr = &evsel->attr; | 161 | struct perf_event_attr *attr = &evsel->attr; |
162 | int track = !evsel->idx; /* only the first counter needs these */ | 162 | int track = !evsel->idx; /* only the first counter needs these */ |
163 | 163 | ||
164 | attr->disabled = 1; | ||
164 | attr->inherit = !no_inherit; | 165 | attr->inherit = !no_inherit; |
165 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | | 166 | attr->read_format = PERF_FORMAT_TOTAL_TIME_ENABLED | |
166 | PERF_FORMAT_TOTAL_TIME_RUNNING | | 167 | PERF_FORMAT_TOTAL_TIME_RUNNING | |
@@ -671,6 +672,8 @@ static int __cmd_record(int argc, const char **argv) | |||
671 | } | 672 | } |
672 | } | 673 | } |
673 | 674 | ||
675 | perf_evlist__enable(evsel_list); | ||
676 | |||
674 | /* | 677 | /* |
675 | * Let the child rip | 678 | * Let the child rip |
676 | */ | 679 | */ |
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 a43433f08300..d28013b7d61c 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 469c0264ed29..40eeaf07725b 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -74,16 +74,104 @@ static void dso__set_sorted_by_name(struct dso *dso, enum map_type type) | |||
74 | 74 | ||
75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) | 75 | bool symbol_type__is_a(char symbol_type, enum map_type map_type) |
76 | { | 76 | { |
77 | symbol_type = toupper(symbol_type); | ||
78 | |||
77 | switch (map_type) { | 79 | switch (map_type) { |
78 | case MAP__FUNCTION: | 80 | case MAP__FUNCTION: |
79 | return symbol_type == 'T' || symbol_type == 'W'; | 81 | return symbol_type == 'T' || symbol_type == 'W'; |
80 | case MAP__VARIABLE: | 82 | case MAP__VARIABLE: |
81 | return symbol_type == 'D' || symbol_type == 'd'; | 83 | return symbol_type == 'D'; |
82 | default: | 84 | default: |
83 | return false; | 85 | return false; |
84 | } | 86 | } |
85 | } | 87 | } |
86 | 88 | ||
89 | static int prefix_underscores_count(const char *str) | ||
90 | { | ||
91 | const char *tail = str; | ||
92 | |||
93 | while (*tail == '_') | ||
94 | tail++; | ||
95 | |||
96 | return tail - str; | ||
97 | } | ||
98 | |||
99 | #define SYMBOL_A 0 | ||
100 | #define SYMBOL_B 1 | ||
101 | |||
102 | static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | ||
103 | { | ||
104 | s64 a; | ||
105 | s64 b; | ||
106 | |||
107 | /* Prefer a symbol with non zero length */ | ||
108 | a = syma->end - syma->start; | ||
109 | b = symb->end - symb->start; | ||
110 | if ((b == 0) && (a > 0)) | ||
111 | return SYMBOL_A; | ||
112 | else if ((a == 0) && (b > 0)) | ||
113 | return SYMBOL_B; | ||
114 | |||
115 | /* Prefer a non weak symbol over a weak one */ | ||
116 | a = syma->binding == STB_WEAK; | ||
117 | b = symb->binding == STB_WEAK; | ||
118 | if (b && !a) | ||
119 | return SYMBOL_A; | ||
120 | if (a && !b) | ||
121 | return SYMBOL_B; | ||
122 | |||
123 | /* Prefer a global symbol over a non global one */ | ||
124 | a = syma->binding == STB_GLOBAL; | ||
125 | b = symb->binding == STB_GLOBAL; | ||
126 | if (a && !b) | ||
127 | return SYMBOL_A; | ||
128 | if (b && !a) | ||
129 | return SYMBOL_B; | ||
130 | |||
131 | /* Prefer a symbol with less underscores */ | ||
132 | a = prefix_underscores_count(syma->name); | ||
133 | b = prefix_underscores_count(symb->name); | ||
134 | if (b > a) | ||
135 | return SYMBOL_A; | ||
136 | else if (a > b) | ||
137 | return SYMBOL_B; | ||
138 | |||
139 | /* If all else fails, choose the symbol with the longest name */ | ||
140 | if (strlen(syma->name) >= strlen(symb->name)) | ||
141 | return SYMBOL_A; | ||
142 | else | ||
143 | return SYMBOL_B; | ||
144 | } | ||
145 | |||
146 | static void symbols__fixup_duplicate(struct rb_root *symbols) | ||
147 | { | ||
148 | struct rb_node *nd; | ||
149 | struct symbol *curr, *next; | ||
150 | |||
151 | nd = rb_first(symbols); | ||
152 | |||
153 | while (nd) { | ||
154 | curr = rb_entry(nd, struct symbol, rb_node); | ||
155 | again: | ||
156 | nd = rb_next(&curr->rb_node); | ||
157 | next = rb_entry(nd, struct symbol, rb_node); | ||
158 | |||
159 | if (!nd) | ||
160 | break; | ||
161 | |||
162 | if (curr->start != next->start) | ||
163 | continue; | ||
164 | |||
165 | if (choose_best_symbol(curr, next) == SYMBOL_A) { | ||
166 | rb_erase(&next->rb_node, symbols); | ||
167 | goto again; | ||
168 | } else { | ||
169 | nd = rb_next(&curr->rb_node); | ||
170 | rb_erase(&curr->rb_node, symbols); | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | |||
87 | static void symbols__fixup_end(struct rb_root *symbols) | 175 | static void symbols__fixup_end(struct rb_root *symbols) |
88 | { | 176 | { |
89 | struct rb_node *nd, *prevnd = rb_first(symbols); | 177 | struct rb_node *nd, *prevnd = rb_first(symbols); |
@@ -438,18 +526,11 @@ int kallsyms__parse(const char *filename, void *arg, | |||
438 | char *line = NULL; | 526 | char *line = NULL; |
439 | size_t n; | 527 | size_t n; |
440 | int err = -1; | 528 | int err = -1; |
441 | u64 prev_start = 0; | ||
442 | char prev_symbol_type = 0; | ||
443 | char *prev_symbol_name; | ||
444 | FILE *file = fopen(filename, "r"); | 529 | FILE *file = fopen(filename, "r"); |
445 | 530 | ||
446 | if (file == NULL) | 531 | if (file == NULL) |
447 | goto out_failure; | 532 | goto out_failure; |
448 | 533 | ||
449 | prev_symbol_name = malloc(KSYM_NAME_LEN); | ||
450 | if (prev_symbol_name == NULL) | ||
451 | goto out_close; | ||
452 | |||
453 | err = 0; | 534 | err = 0; |
454 | 535 | ||
455 | while (!feof(file)) { | 536 | while (!feof(file)) { |
@@ -470,7 +551,7 @@ int kallsyms__parse(const char *filename, void *arg, | |||
470 | if (len + 2 >= line_len) | 551 | if (len + 2 >= line_len) |
471 | continue; | 552 | continue; |
472 | 553 | ||
473 | symbol_type = toupper(line[len]); | 554 | symbol_type = line[len]; |
474 | len += 2; | 555 | len += 2; |
475 | symbol_name = line + len; | 556 | symbol_name = line + len; |
476 | len = line_len - len; | 557 | len = line_len - len; |
@@ -480,24 +561,18 @@ int kallsyms__parse(const char *filename, void *arg, | |||
480 | break; | 561 | break; |
481 | } | 562 | } |
482 | 563 | ||
483 | if (prev_symbol_type) { | 564 | /* |
484 | u64 end = start; | 565 | * module symbols are not sorted so we add all |
485 | if (end != prev_start) | 566 | * symbols with zero length and rely on |
486 | --end; | 567 | * symbols__fixup_end() to fix it up. |
487 | err = process_symbol(arg, prev_symbol_name, | 568 | */ |
488 | prev_symbol_type, prev_start, end); | 569 | err = process_symbol(arg, symbol_name, |
489 | if (err) | 570 | symbol_type, start, start); |
490 | break; | 571 | if (err) |
491 | } | 572 | break; |
492 | |||
493 | memcpy(prev_symbol_name, symbol_name, len + 1); | ||
494 | prev_symbol_type = symbol_type; | ||
495 | prev_start = start; | ||
496 | } | 573 | } |
497 | 574 | ||
498 | free(prev_symbol_name); | ||
499 | free(line); | 575 | free(line); |
500 | out_close: | ||
501 | fclose(file); | 576 | fclose(file); |
502 | return err; | 577 | return err; |
503 | 578 | ||
@@ -703,6 +778,9 @@ int dso__load_kallsyms(struct dso *dso, const char *filename, | |||
703 | if (dso__load_all_kallsyms(dso, filename, map) < 0) | 778 | if (dso__load_all_kallsyms(dso, filename, map) < 0) |
704 | return -1; | 779 | return -1; |
705 | 780 | ||
781 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
782 | symbols__fixup_end(&dso->symbols[map->type]); | ||
783 | |||
706 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) | 784 | if (dso->kernel == DSO_TYPE_GUEST_KERNEL) |
707 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; | 785 | dso->symtab_type = SYMTAB__GUEST_KALLSYMS; |
708 | else | 786 | else |
@@ -1092,8 +1170,7 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1092 | if (dso->has_build_id) { | 1170 | if (dso->has_build_id) { |
1093 | u8 build_id[BUILD_ID_SIZE]; | 1171 | u8 build_id[BUILD_ID_SIZE]; |
1094 | 1172 | ||
1095 | if (elf_read_build_id(elf, build_id, | 1173 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) |
1096 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | ||
1097 | goto out_elf_end; | 1174 | goto out_elf_end; |
1098 | 1175 | ||
1099 | if (!dso__build_id_equal(dso, build_id)) | 1176 | if (!dso__build_id_equal(dso, build_id)) |
@@ -1111,6 +1188,8 @@ static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | |||
1111 | } | 1188 | } |
1112 | 1189 | ||
1113 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | 1190 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); |
1191 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1192 | opdsec = NULL; | ||
1114 | if (opdsec) | 1193 | if (opdsec) |
1115 | opddata = elf_rawdata(opdsec, NULL); | 1194 | opddata = elf_rawdata(opdsec, NULL); |
1116 | 1195 | ||
@@ -1276,6 +1355,7 @@ new_symbol: | |||
1276 | * For misannotated, zeroed, ASM function sizes. | 1355 | * For misannotated, zeroed, ASM function sizes. |
1277 | */ | 1356 | */ |
1278 | if (nr > 0) { | 1357 | if (nr > 0) { |
1358 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1279 | symbols__fixup_end(&dso->symbols[map->type]); | 1359 | symbols__fixup_end(&dso->symbols[map->type]); |
1280 | if (kmap) { | 1360 | if (kmap) { |
1281 | /* | 1361 | /* |
@@ -1362,8 +1442,8 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1362 | ptr = data->d_buf; | 1442 | ptr = data->d_buf; |
1363 | while (ptr < (data->d_buf + data->d_size)) { | 1443 | while (ptr < (data->d_buf + data->d_size)) { |
1364 | GElf_Nhdr *nhdr = ptr; | 1444 | GElf_Nhdr *nhdr = ptr; |
1365 | int namesz = NOTE_ALIGN(nhdr->n_namesz), | 1445 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), |
1366 | descsz = NOTE_ALIGN(nhdr->n_descsz); | 1446 | descsz = NOTE_ALIGN(nhdr->n_descsz); |
1367 | const char *name; | 1447 | const char *name; |
1368 | 1448 | ||
1369 | ptr += sizeof(*nhdr); | 1449 | ptr += sizeof(*nhdr); |
@@ -1372,8 +1452,10 @@ static int elf_read_build_id(Elf *elf, void *bf, size_t size) | |||
1372 | if (nhdr->n_type == NT_GNU_BUILD_ID && | 1452 | if (nhdr->n_type == NT_GNU_BUILD_ID && |
1373 | nhdr->n_namesz == sizeof("GNU")) { | 1453 | nhdr->n_namesz == sizeof("GNU")) { |
1374 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | 1454 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { |
1375 | memcpy(bf, ptr, BUILD_ID_SIZE); | 1455 | size_t sz = min(size, descsz); |
1376 | err = BUILD_ID_SIZE; | 1456 | memcpy(bf, ptr, sz); |
1457 | memset(bf + sz, 0, size - sz); | ||
1458 | err = descsz; | ||
1377 | break; | 1459 | break; |
1378 | } | 1460 | } |
1379 | } | 1461 | } |
@@ -1425,7 +1507,7 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1425 | while (1) { | 1507 | while (1) { |
1426 | char bf[BUFSIZ]; | 1508 | char bf[BUFSIZ]; |
1427 | GElf_Nhdr nhdr; | 1509 | GElf_Nhdr nhdr; |
1428 | int namesz, descsz; | 1510 | size_t namesz, descsz; |
1429 | 1511 | ||
1430 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | 1512 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) |
1431 | break; | 1513 | break; |
@@ -1434,15 +1516,16 @@ int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | |||
1434 | descsz = NOTE_ALIGN(nhdr.n_descsz); | 1516 | descsz = NOTE_ALIGN(nhdr.n_descsz); |
1435 | if (nhdr.n_type == NT_GNU_BUILD_ID && | 1517 | if (nhdr.n_type == NT_GNU_BUILD_ID && |
1436 | nhdr.n_namesz == sizeof("GNU")) { | 1518 | nhdr.n_namesz == sizeof("GNU")) { |
1437 | if (read(fd, bf, namesz) != namesz) | 1519 | if (read(fd, bf, namesz) != (ssize_t)namesz) |
1438 | break; | 1520 | break; |
1439 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | 1521 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { |
1440 | if (read(fd, build_id, | 1522 | size_t sz = min(descsz, size); |
1441 | BUILD_ID_SIZE) == BUILD_ID_SIZE) { | 1523 | if (read(fd, build_id, sz) == (ssize_t)sz) { |
1524 | memset(build_id + sz, 0, size - sz); | ||
1442 | err = 0; | 1525 | err = 0; |
1443 | break; | 1526 | break; |
1444 | } | 1527 | } |
1445 | } else if (read(fd, bf, descsz) != descsz) | 1528 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) |
1446 | break; | 1529 | break; |
1447 | } else { | 1530 | } else { |
1448 | int n = namesz + descsz; | 1531 | int n = namesz + descsz; |