diff options
author | Ingo Molnar <mingo@elte.hu> | 2011-10-06 06:48:57 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-10-06 06:49:21 -0400 |
commit | 9d014020234525ae100879d71078a4bcb4849195 (patch) | |
tree | a0d6c0776670cb876e5a8118a4e6ed28d8f51cbc /tools/perf/util/symbol.c | |
parent | 92e51938f5d005026ba4bb5b1fae5a86dc195b86 (diff) | |
parent | 976d167615b64e14bc1491ca51d424e2ba9a5e84 (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.c | 153 |
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 | ||
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; |