diff options
-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); |