aboutsummaryrefslogtreecommitdiffstats
path: root/tools/perf/util/symbol.c
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/perf/util/symbol.c
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/perf/util/symbol.c')
-rw-r--r--tools/perf/util/symbol.c153
1 files changed, 118 insertions, 35 deletions
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;