diff options
Diffstat (limited to 'tools/perf')
| -rw-r--r-- | tools/perf/util/symbol.c | 161 | ||||
| -rw-r--r-- | tools/perf/util/symbol.h | 2 |
2 files changed, 122 insertions, 41 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index e88296899470..4dfdefd5ec7e 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
| @@ -27,6 +27,44 @@ enum dso_origin { | |||
| 27 | static void dsos__add(struct dso *dso); | 27 | static void dsos__add(struct dso *dso); |
| 28 | static struct dso *dsos__find(const char *name); | 28 | static struct dso *dsos__find(const char *name); |
| 29 | 29 | ||
| 30 | static struct rb_root kernel_maps; | ||
| 31 | |||
| 32 | static void dso__set_symbols_end(struct dso *self) | ||
| 33 | { | ||
| 34 | struct rb_node *nd, *prevnd = rb_first(&self->syms); | ||
| 35 | |||
| 36 | if (prevnd == NULL) | ||
| 37 | return; | ||
| 38 | |||
| 39 | for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { | ||
| 40 | struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), | ||
| 41 | *curr = rb_entry(nd, struct symbol, rb_node); | ||
| 42 | |||
| 43 | if (prev->end == prev->start) | ||
| 44 | prev->end = curr->start - 1; | ||
| 45 | prevnd = nd; | ||
| 46 | } | ||
| 47 | } | ||
| 48 | |||
| 49 | static void kernel_maps__fixup_sym_end(void) | ||
| 50 | { | ||
| 51 | struct map *prev, *curr; | ||
| 52 | struct rb_node *nd, *prevnd = rb_first(&kernel_maps); | ||
| 53 | |||
| 54 | if (prevnd == NULL) | ||
| 55 | return; | ||
| 56 | |||
| 57 | curr = rb_entry(prevnd, struct map, rb_node); | ||
| 58 | dso__set_symbols_end(curr->dso); | ||
| 59 | |||
| 60 | for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { | ||
| 61 | prev = curr; | ||
| 62 | curr = rb_entry(nd, struct map, rb_node); | ||
| 63 | prev->end = curr->start - 1; | ||
| 64 | dso__set_symbols_end(curr->dso); | ||
| 65 | } | ||
| 66 | } | ||
| 67 | |||
| 30 | static struct symbol *symbol__new(u64 start, u64 len, const char *name, | 68 | static struct symbol *symbol__new(u64 start, u64 len, const char *name, |
| 31 | unsigned int priv_size, int v) | 69 | unsigned int priv_size, int v) |
| 32 | { | 70 | { |
| @@ -162,10 +200,9 @@ size_t dso__fprintf(struct dso *self, FILE *fp) | |||
| 162 | return ret; | 200 | return ret; |
| 163 | } | 201 | } |
| 164 | 202 | ||
| 165 | static int dso__load_kallsyms(struct dso *self, struct map *map, | 203 | static int maps__load_kallsyms(symbol_filter_t filter, int use_modules, int v) |
| 166 | symbol_filter_t filter, int v) | ||
| 167 | { | 204 | { |
| 168 | struct rb_node *nd, *prevnd; | 205 | struct map *map = kernel_map; |
| 169 | char *line = NULL; | 206 | char *line = NULL; |
| 170 | size_t n; | 207 | size_t n; |
| 171 | FILE *file = fopen("/proc/kallsyms", "r"); | 208 | FILE *file = fopen("/proc/kallsyms", "r"); |
| @@ -179,6 +216,7 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, | |||
| 179 | struct symbol *sym; | 216 | struct symbol *sym; |
| 180 | int line_len, len; | 217 | int line_len, len; |
| 181 | char symbol_type; | 218 | char symbol_type; |
| 219 | char *module, *symbol_name; | ||
| 182 | 220 | ||
| 183 | line_len = getline(&line, &n, file); | 221 | line_len = getline(&line, &n, file); |
| 184 | if (line_len < 0) | 222 | if (line_len < 0) |
| @@ -201,40 +239,50 @@ static int dso__load_kallsyms(struct dso *self, struct map *map, | |||
| 201 | */ | 239 | */ |
| 202 | if (symbol_type != 'T' && symbol_type != 'W') | 240 | if (symbol_type != 'T' && symbol_type != 'W') |
| 203 | continue; | 241 | continue; |
| 242 | |||
| 243 | symbol_name = line + len + 2; | ||
| 244 | module = strchr(symbol_name, '\t'); | ||
| 245 | if (module) { | ||
| 246 | char *module_name_end; | ||
| 247 | |||
| 248 | if (!use_modules) | ||
| 249 | continue; | ||
| 250 | *module = '\0'; | ||
| 251 | module = strchr(module + 1, '['); | ||
| 252 | if (!module) | ||
| 253 | continue; | ||
| 254 | module_name_end = strchr(module + 1, ']'); | ||
| 255 | if (!module_name_end) | ||
| 256 | continue; | ||
| 257 | *(module_name_end + 1) = '\0'; | ||
| 258 | if (strcmp(map->dso->name, module)) { | ||
| 259 | map = kernel_maps__find_by_dso_name(module); | ||
| 260 | if (!map) { | ||
| 261 | fputs("/proc/{kallsyms,modules} " | ||
| 262 | "inconsistency!\n", stderr); | ||
| 263 | return -1; | ||
| 264 | } | ||
| 265 | } | ||
| 266 | start = map->map_ip(map, start); | ||
| 267 | } else | ||
| 268 | map = kernel_map; | ||
| 204 | /* | 269 | /* |
| 205 | * Well fix up the end later, when we have all sorted. | 270 | * Well fix up the end later, when we have all sorted. |
| 206 | */ | 271 | */ |
| 207 | sym = symbol__new(start, 0xdead, line + len + 2, | 272 | sym = symbol__new(start, 0, symbol_name, |
| 208 | self->sym_priv_size, v); | 273 | map->dso->sym_priv_size, v); |
| 209 | 274 | ||
| 210 | if (sym == NULL) | 275 | if (sym == NULL) |
| 211 | goto out_delete_line; | 276 | goto out_delete_line; |
| 212 | 277 | ||
| 213 | if (filter && filter(map, sym)) | 278 | if (filter && filter(map, sym)) |
| 214 | symbol__delete(sym, self->sym_priv_size); | 279 | symbol__delete(sym, map->dso->sym_priv_size); |
| 215 | else { | 280 | else { |
| 216 | dso__insert_symbol(self, sym); | 281 | dso__insert_symbol(map->dso, sym); |
| 217 | count++; | 282 | count++; |
| 218 | } | 283 | } |
| 219 | } | 284 | } |
| 220 | 285 | ||
| 221 | /* | ||
| 222 | * Now that we have all sorted out, just set the ->end of all | ||
| 223 | * symbols | ||
| 224 | */ | ||
| 225 | prevnd = rb_first(&self->syms); | ||
| 226 | |||
| 227 | if (prevnd == NULL) | ||
| 228 | goto out_delete_line; | ||
| 229 | |||
| 230 | for (nd = rb_next(prevnd); nd; nd = rb_next(nd)) { | ||
| 231 | struct symbol *prev = rb_entry(prevnd, struct symbol, rb_node), | ||
| 232 | *curr = rb_entry(nd, struct symbol, rb_node); | ||
| 233 | |||
| 234 | prev->end = curr->start - 1; | ||
| 235 | prevnd = nd; | ||
| 236 | } | ||
| 237 | |||
| 238 | free(line); | 286 | free(line); |
| 239 | fclose(file); | 287 | fclose(file); |
| 240 | 288 | ||
| @@ -246,6 +294,24 @@ out_failure: | |||
| 246 | return -1; | 294 | return -1; |
| 247 | } | 295 | } |
| 248 | 296 | ||
| 297 | static size_t kernel_maps__fprintf(FILE *fp) | ||
| 298 | { | ||
| 299 | size_t printed = fprintf(stderr, "Kernel maps:\n"); | ||
| 300 | struct rb_node *nd; | ||
| 301 | |||
| 302 | printed += map__fprintf(kernel_map, fp); | ||
| 303 | printed += dso__fprintf(kernel_map->dso, fp); | ||
| 304 | |||
| 305 | for (nd = rb_first(&kernel_maps); nd; nd = rb_next(nd)) { | ||
| 306 | struct map *pos = rb_entry(nd, struct map, rb_node); | ||
| 307 | |||
| 308 | printed += map__fprintf(pos, fp); | ||
| 309 | printed += dso__fprintf(pos->dso, fp); | ||
| 310 | } | ||
| 311 | |||
| 312 | return printed + fprintf(stderr, "END kernel maps\n"); | ||
| 313 | } | ||
| 314 | |||
| 249 | static int dso__load_perf_map(struct dso *self, struct map *map, | 315 | static int dso__load_perf_map(struct dso *self, struct map *map, |
| 250 | symbol_filter_t filter, int v) | 316 | symbol_filter_t filter, int v) |
| 251 | { | 317 | { |
| @@ -598,6 +664,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 598 | char *demangled; | 664 | char *demangled; |
| 599 | int is_label = elf_sym__is_label(&sym); | 665 | int is_label = elf_sym__is_label(&sym); |
| 600 | const char *section_name; | 666 | const char *section_name; |
| 667 | u64 sh_offset = 0; | ||
| 601 | 668 | ||
| 602 | if (!is_label && !elf_sym__is_function(&sym)) | 669 | if (!is_label && !elf_sym__is_function(&sym)) |
| 603 | continue; | 670 | continue; |
| @@ -613,14 +680,18 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 613 | 680 | ||
| 614 | section_name = elf_sec__name(&shdr, secstrs); | 681 | section_name = elf_sec__name(&shdr, secstrs); |
| 615 | 682 | ||
| 683 | if ((kernel || kmodule)) { | ||
| 684 | if (strstr(section_name, ".init")) | ||
| 685 | sh_offset = shdr.sh_offset; | ||
| 686 | } | ||
| 687 | |||
| 616 | if (self->adjust_symbols) { | 688 | if (self->adjust_symbols) { |
| 617 | if (v >= 2) | 689 | if (v >= 2) |
| 618 | printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", | 690 | printf("adjusting symbol: st_value: %Lx sh_addr: %Lx sh_offset: %Lx\n", |
| 619 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); | 691 | (u64)sym.st_value, (u64)shdr.sh_addr, (u64)shdr.sh_offset); |
| 620 | 692 | ||
| 621 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | 693 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; |
| 622 | } else if (kmodule) | 694 | } |
| 623 | sym.st_value += shdr.sh_offset; | ||
| 624 | /* | 695 | /* |
| 625 | * We need to figure out if the object was created from C++ sources | 696 | * We need to figure out if the object was created from C++ sources |
| 626 | * DWARF DW_compile_unit has this, but we don't always have access | 697 | * DWARF DW_compile_unit has this, but we don't always have access |
| @@ -631,7 +702,7 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
| 631 | if (demangled != NULL) | 702 | if (demangled != NULL) |
| 632 | elf_name = demangled; | 703 | elf_name = demangled; |
| 633 | 704 | ||
| 634 | f = symbol__new(sym.st_value, sym.st_size, elf_name, | 705 | f = symbol__new(sym.st_value + sh_offset, sym.st_size, elf_name, |
| 635 | self->sym_priv_size, v); | 706 | self->sym_priv_size, v); |
| 636 | free(demangled); | 707 | free(demangled); |
| 637 | if (!f) | 708 | if (!f) |
| @@ -804,7 +875,6 @@ out: | |||
| 804 | return ret; | 875 | return ret; |
| 805 | } | 876 | } |
| 806 | 877 | ||
| 807 | static struct rb_root kernel_maps; | ||
| 808 | struct map *kernel_map; | 878 | struct map *kernel_map; |
| 809 | 879 | ||
| 810 | static void kernel_maps__insert(struct map *map) | 880 | static void kernel_maps__insert(struct map *map) |
| @@ -975,8 +1045,7 @@ static struct map *map__new2(u64 start, struct dso *dso) | |||
| 975 | return self; | 1045 | return self; |
| 976 | } | 1046 | } |
| 977 | 1047 | ||
| 978 | int dsos__load_modules(unsigned int sym_priv_size, | 1048 | static int dsos__load_modules(unsigned int sym_priv_size) |
| 979 | symbol_filter_t filter, int v) | ||
| 980 | { | 1049 | { |
| 981 | char *line = NULL; | 1050 | char *line = NULL; |
| 982 | size_t n; | 1051 | size_t n; |
| @@ -1034,8 +1103,7 @@ int dsos__load_modules(unsigned int sym_priv_size, | |||
| 1034 | free(line); | 1103 | free(line); |
| 1035 | fclose(file); | 1104 | fclose(file); |
| 1036 | 1105 | ||
| 1037 | v = 1; | 1106 | return 0; |
| 1038 | return dsos__load_modules_sym(filter, v); | ||
| 1039 | 1107 | ||
| 1040 | out_delete_line: | 1108 | out_delete_line: |
| 1041 | free(line); | 1109 | free(line); |
| @@ -1075,25 +1143,37 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, | |||
| 1075 | 1143 | ||
| 1076 | kernel_map->map_ip = vdso__map_ip; | 1144 | kernel_map->map_ip = vdso__map_ip; |
| 1077 | 1145 | ||
| 1146 | if (use_modules && dsos__load_modules(sym_priv_size) < 0) { | ||
| 1147 | fprintf(stderr, "Failed to load list of modules in use! " | ||
| 1148 | "Continuing...\n"); | ||
| 1149 | use_modules = 0; | ||
| 1150 | } | ||
| 1151 | |||
| 1078 | if (vmlinux) { | 1152 | if (vmlinux) { |
| 1079 | err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); | 1153 | err = dso__load_vmlinux(dso, kernel_map, vmlinux, filter, v); |
| 1080 | if (err > 0 && use_modules) { | 1154 | if (err > 0 && use_modules) { |
| 1081 | int syms = dsos__load_modules(sym_priv_size, filter, v); | 1155 | int syms = dsos__load_modules_sym(filter, v); |
| 1082 | 1156 | ||
| 1083 | if (syms < 0) { | 1157 | if (syms < 0) |
| 1084 | fprintf(stderr, "dsos__load_modules failed!\n"); | 1158 | fprintf(stderr, "Failed to read module symbols!" |
| 1085 | return syms; | 1159 | " Continuing...\n"); |
| 1086 | } | 1160 | else |
| 1087 | err += syms; | 1161 | err += syms; |
| 1088 | } | 1162 | } |
| 1089 | } | 1163 | } |
| 1090 | 1164 | ||
| 1091 | if (err <= 0) | 1165 | if (err <= 0) |
| 1092 | err = dso__load_kallsyms(dso, kernel_map, filter, v); | 1166 | err = maps__load_kallsyms(filter, use_modules, v); |
| 1093 | 1167 | ||
| 1094 | if (err > 0) { | 1168 | if (err > 0) { |
| 1095 | struct rb_node *node = rb_first(&dso->syms); | 1169 | struct rb_node *node = rb_first(&dso->syms); |
| 1096 | struct symbol *sym = rb_entry(node, struct symbol, rb_node); | 1170 | struct symbol *sym = rb_entry(node, struct symbol, rb_node); |
| 1171 | /* | ||
| 1172 | * Now that we have all sorted out, just set the ->end of all | ||
| 1173 | * symbols that still don't have it. | ||
| 1174 | */ | ||
| 1175 | dso__set_symbols_end(dso); | ||
| 1176 | kernel_maps__fixup_sym_end(); | ||
| 1097 | 1177 | ||
| 1098 | kernel_map->start = sym->start; | 1178 | kernel_map->start = sym->start; |
| 1099 | node = rb_last(&dso->syms); | 1179 | node = rb_last(&dso->syms); |
| @@ -1106,6 +1186,9 @@ int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, | |||
| 1106 | * kernel_maps__insert(kernel_map) | 1186 | * kernel_maps__insert(kernel_map) |
| 1107 | */ | 1187 | */ |
| 1108 | dsos__add(dso); | 1188 | dsos__add(dso); |
| 1189 | |||
| 1190 | if (v > 0) | ||
| 1191 | kernel_maps__fprintf(stderr); | ||
| 1109 | } | 1192 | } |
| 1110 | 1193 | ||
| 1111 | return err; | 1194 | return err; |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 5339fd82ec96..2e4522edeb07 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
| @@ -70,8 +70,6 @@ struct symbol *dso__find_symbol(struct dso *self, u64 ip); | |||
| 70 | 70 | ||
| 71 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, | 71 | int dsos__load_kernel(const char *vmlinux, unsigned int sym_priv_size, |
| 72 | symbol_filter_t filter, int verbose, int modules); | 72 | symbol_filter_t filter, int verbose, int modules); |
| 73 | int dsos__load_modules(unsigned int sym_priv_size, symbol_filter_t filter, | ||
| 74 | int verbose); | ||
| 75 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, | 73 | int dso__load(struct dso *self, struct map *map, symbol_filter_t filter, |
| 76 | int verbose); | 74 | int verbose); |
| 77 | struct dso *dsos__findnew(const char *name); | 75 | struct dso *dsos__findnew(const char *name); |
