aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorIngo Molnar <mingo@elte.hu>2011-10-06 06:48:57 -0400
committerIngo Molnar <mingo@elte.hu>2011-10-06 06:49:21 -0400
commit9d014020234525ae100879d71078a4bcb4849195 (patch)
treea0d6c0776670cb876e5a8118a4e6ed28d8f51cbc /tools
parent92e51938f5d005026ba4bb5b1fae5a86dc195b86 (diff)
parent976d167615b64e14bc1491ca51d424e2ba9a5e84 (diff)
Merge commit 'v3.1-rc9' into perf/core
Merge reason: pick up latest fixes. Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'tools')
-rw-r--r--tools/perf/Makefile9
-rw-r--r--tools/perf/builtin-record.c3
-rw-r--r--tools/perf/builtin-test.c2
-rw-r--r--tools/perf/builtin-top.c9
-rw-r--r--tools/perf/util/event.c5
-rw-r--r--tools/perf/util/event.h2
-rw-r--r--tools/perf/util/evlist.c13
-rw-r--r--tools/perf/util/evlist.h1
-rw-r--r--tools/perf/util/evsel.c57
-rw-r--r--tools/perf/util/probe-finder.c2
-rw-r--r--tools/perf/util/python.c2
-rw-r--r--tools/perf/util/session.h3
-rw-r--r--tools/perf/util/sort.c10
-rw-r--r--tools/perf/util/symbol.c153
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
64endif 66endif
65 67
68# Treat warnings as errors unless directed not to
69ifneq ($(WERROR),0)
70 CFLAGS_WERROR := -Werror
71endif
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
96endif 103endif
97 104
98CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 -Werror $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS) 105CFLAGS = -fno-omit-frame-pointer -ggdb3 -Wall -Wextra -std=gnu99 $(CFLAGS_WERROR) $(CFLAGS_OPTIMIZE) -D_FORTIFY_SOURCE=2 $(EXTRA_WARNINGS) $(EXTRA_CFLAGS)
99EXTLIBS = -lpthread -lrt -lelf -lm 106EXTLIBS = -lpthread -lrt -lelf -lm
100ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64 107ALL_CFLAGS = $(CFLAGS) -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64
101ALL_LDFLAGS = $(LDFLAGS) 108ALL_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
194static void record_precise_ip(struct sym_entry *syme, int counter, u64 ip) 194static 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(&notes->lock)) 206 if (pthread_mutex_trylock(&notes->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(&notes->lock); 212 pthread_mutex_unlock(&notes->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
187int perf_event__parse_sample(const union perf_event *event, u64 type, 187int 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
116void 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
116int perf_evlist__alloc_pollfd(struct perf_evlist *evlist) 129int 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);
54void perf_evlist__munmap(struct perf_evlist *evlist); 54void perf_evlist__munmap(struct perf_evlist *evlist);
55 55
56void perf_evlist__disable(struct perf_evlist *evlist); 56void perf_evlist__disable(struct perf_evlist *evlist);
57void perf_evlist__enable(struct perf_evlist *evlist);
57 58
58static inline void perf_evlist__set_maps(struct perf_evlist *evlist, 59static 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
343int perf_event__parse_sample(const union perf_event *event, u64 type, 345int 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
168struct perf_evsel *perf_session__find_first_evtype(struct perf_session *session, 169struct 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
77bool symbol_type__is_a(char symbol_type, enum map_type map_type) 77bool 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
91static 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
104static 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
148static 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);
157again:
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
89static void symbols__fixup_end(struct rb_root *symbols) 177static 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);
502out_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;