diff options
Diffstat (limited to 'tools/perf/util/symbol.c')
-rw-r--r-- | tools/perf/util/symbol.c | 339 |
1 files changed, 237 insertions, 102 deletions
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index 5b276833e2bf..1a367734e016 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <fcntl.h> | 12 | #include <fcntl.h> |
13 | #include <unistd.h> | 13 | #include <unistd.h> |
14 | #include "build-id.h" | 14 | #include "build-id.h" |
15 | #include "debug.h" | ||
15 | #include "symbol.h" | 16 | #include "symbol.h" |
16 | #include "strlist.h" | 17 | #include "strlist.h" |
17 | 18 | ||
@@ -25,6 +26,8 @@ | |||
25 | #define NT_GNU_BUILD_ID 3 | 26 | #define NT_GNU_BUILD_ID 3 |
26 | #endif | 27 | #endif |
27 | 28 | ||
29 | static bool dso__build_id_equal(const struct dso *self, u8 *build_id); | ||
30 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); | ||
28 | static void dsos__add(struct list_head *head, struct dso *dso); | 31 | static void dsos__add(struct list_head *head, struct dso *dso); |
29 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | 32 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); |
30 | static int dso__load_kernel_sym(struct dso *self, struct map *map, | 33 | static int dso__load_kernel_sym(struct dso *self, struct map *map, |
@@ -40,6 +43,14 @@ struct symbol_conf symbol_conf = { | |||
40 | .try_vmlinux_path = true, | 43 | .try_vmlinux_path = true, |
41 | }; | 44 | }; |
42 | 45 | ||
46 | int dso__name_len(const struct dso *self) | ||
47 | { | ||
48 | if (verbose) | ||
49 | return self->long_name_len; | ||
50 | |||
51 | return self->short_name_len; | ||
52 | } | ||
53 | |||
43 | bool dso__loaded(const struct dso *self, enum map_type type) | 54 | bool dso__loaded(const struct dso *self, enum map_type type) |
44 | { | 55 | { |
45 | return self->loaded & (1 << type); | 56 | return self->loaded & (1 << type); |
@@ -120,7 +131,8 @@ static void map_groups__fixup_end(struct map_groups *self) | |||
120 | __map_groups__fixup_end(self, i); | 131 | __map_groups__fixup_end(self, i); |
121 | } | 132 | } |
122 | 133 | ||
123 | static struct symbol *symbol__new(u64 start, u64 len, const char *name) | 134 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, |
135 | const char *name) | ||
124 | { | 136 | { |
125 | size_t namelen = strlen(name) + 1; | 137 | size_t namelen = strlen(name) + 1; |
126 | struct symbol *self = calloc(1, (symbol_conf.priv_size + | 138 | struct symbol *self = calloc(1, (symbol_conf.priv_size + |
@@ -133,6 +145,7 @@ static struct symbol *symbol__new(u64 start, u64 len, const char *name) | |||
133 | 145 | ||
134 | self->start = start; | 146 | self->start = start; |
135 | self->end = len ? start + len - 1 : start; | 147 | self->end = len ? start + len - 1 : start; |
148 | self->binding = binding; | ||
136 | self->namelen = namelen - 1; | 149 | self->namelen = namelen - 1; |
137 | 150 | ||
138 | pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); | 151 | pr_debug4("%s: %s %#Lx-%#Lx\n", __func__, name, start, self->end); |
@@ -149,8 +162,11 @@ void symbol__delete(struct symbol *self) | |||
149 | 162 | ||
150 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) | 163 | static size_t symbol__fprintf(struct symbol *self, FILE *fp) |
151 | { | 164 | { |
152 | return fprintf(fp, " %llx-%llx %s\n", | 165 | return fprintf(fp, " %llx-%llx %c %s\n", |
153 | self->start, self->end, self->name); | 166 | self->start, self->end, |
167 | self->binding == STB_GLOBAL ? 'g' : | ||
168 | self->binding == STB_LOCAL ? 'l' : 'w', | ||
169 | self->name); | ||
154 | } | 170 | } |
155 | 171 | ||
156 | void dso__set_long_name(struct dso *self, char *name) | 172 | void dso__set_long_name(struct dso *self, char *name) |
@@ -215,7 +231,9 @@ void dso__delete(struct dso *self) | |||
215 | int i; | 231 | int i; |
216 | for (i = 0; i < MAP__NR_TYPES; ++i) | 232 | for (i = 0; i < MAP__NR_TYPES; ++i) |
217 | symbols__delete(&self->symbols[i]); | 233 | symbols__delete(&self->symbols[i]); |
218 | if (self->long_name != self->name) | 234 | if (self->sname_alloc) |
235 | free((char *)self->short_name); | ||
236 | if (self->lname_alloc) | ||
219 | free(self->long_name); | 237 | free(self->long_name); |
220 | free(self); | 238 | free(self); |
221 | } | 239 | } |
@@ -440,6 +458,14 @@ struct process_kallsyms_args { | |||
440 | struct dso *dso; | 458 | struct dso *dso; |
441 | }; | 459 | }; |
442 | 460 | ||
461 | static u8 kallsyms2elf_type(char type) | ||
462 | { | ||
463 | if (type == 'W') | ||
464 | return STB_WEAK; | ||
465 | |||
466 | return isupper(type) ? STB_GLOBAL : STB_LOCAL; | ||
467 | } | ||
468 | |||
443 | static int map__process_kallsym_symbol(void *arg, const char *name, | 469 | static int map__process_kallsym_symbol(void *arg, const char *name, |
444 | char type, u64 start) | 470 | char type, u64 start) |
445 | { | 471 | { |
@@ -453,7 +479,7 @@ static int map__process_kallsym_symbol(void *arg, const char *name, | |||
453 | /* | 479 | /* |
454 | * Will fix up the end later, when we have all symbols sorted. | 480 | * Will fix up the end later, when we have all symbols sorted. |
455 | */ | 481 | */ |
456 | sym = symbol__new(start, 0, name); | 482 | sym = symbol__new(start, 0, kallsyms2elf_type(type), name); |
457 | 483 | ||
458 | if (sym == NULL) | 484 | if (sym == NULL) |
459 | return -ENOMEM; | 485 | return -ENOMEM; |
@@ -648,7 +674,7 @@ static int dso__load_perf_map(struct dso *self, struct map *map, | |||
648 | if (len + 2 >= line_len) | 674 | if (len + 2 >= line_len) |
649 | continue; | 675 | continue; |
650 | 676 | ||
651 | sym = symbol__new(start, size, line + len); | 677 | sym = symbol__new(start, size, STB_GLOBAL, line + len); |
652 | 678 | ||
653 | if (sym == NULL) | 679 | if (sym == NULL) |
654 | goto out_delete_line; | 680 | goto out_delete_line; |
@@ -860,7 +886,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
860 | "%s@plt", elf_sym__name(&sym, symstrs)); | 886 | "%s@plt", elf_sym__name(&sym, symstrs)); |
861 | 887 | ||
862 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 888 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
863 | sympltname); | 889 | STB_GLOBAL, sympltname); |
864 | if (!f) | 890 | if (!f) |
865 | goto out_elf_end; | 891 | goto out_elf_end; |
866 | 892 | ||
@@ -882,7 +908,7 @@ static int dso__synthesize_plt_symbols(struct dso *self, struct map *map, | |||
882 | "%s@plt", elf_sym__name(&sym, symstrs)); | 908 | "%s@plt", elf_sym__name(&sym, symstrs)); |
883 | 909 | ||
884 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | 910 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, |
885 | sympltname); | 911 | STB_GLOBAL, sympltname); |
886 | if (!f) | 912 | if (!f) |
887 | goto out_elf_end; | 913 | goto out_elf_end; |
888 | 914 | ||
@@ -933,8 +959,28 @@ static bool elf_sec__is_a(GElf_Shdr *self, Elf_Data *secstrs, enum map_type type | |||
933 | } | 959 | } |
934 | } | 960 | } |
935 | 961 | ||
962 | static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | ||
963 | { | ||
964 | Elf_Scn *sec = NULL; | ||
965 | GElf_Shdr shdr; | ||
966 | size_t cnt = 1; | ||
967 | |||
968 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
969 | gelf_getshdr(sec, &shdr); | ||
970 | |||
971 | if ((addr >= shdr.sh_addr) && | ||
972 | (addr < (shdr.sh_addr + shdr.sh_size))) | ||
973 | return cnt; | ||
974 | |||
975 | ++cnt; | ||
976 | } | ||
977 | |||
978 | return -1; | ||
979 | } | ||
980 | |||
936 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, | 981 | static int dso__load_sym(struct dso *self, struct map *map, const char *name, |
937 | int fd, symbol_filter_t filter, int kmodule) | 982 | int fd, symbol_filter_t filter, int kmodule, |
983 | int want_symtab) | ||
938 | { | 984 | { |
939 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; | 985 | struct kmap *kmap = self->kernel ? map__kmap(map) : NULL; |
940 | struct map *curr_map = map; | 986 | struct map *curr_map = map; |
@@ -944,31 +990,51 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
944 | int err = -1; | 990 | int err = -1; |
945 | uint32_t idx; | 991 | uint32_t idx; |
946 | GElf_Ehdr ehdr; | 992 | GElf_Ehdr ehdr; |
947 | GElf_Shdr shdr; | 993 | GElf_Shdr shdr, opdshdr; |
948 | Elf_Data *syms; | 994 | Elf_Data *syms, *opddata = NULL; |
949 | GElf_Sym sym; | 995 | GElf_Sym sym; |
950 | Elf_Scn *sec, *sec_strndx; | 996 | Elf_Scn *sec, *sec_strndx, *opdsec; |
951 | Elf *elf; | 997 | Elf *elf; |
952 | int nr = 0; | 998 | int nr = 0; |
999 | size_t opdidx = 0; | ||
953 | 1000 | ||
954 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | 1001 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); |
955 | if (elf == NULL) { | 1002 | if (elf == NULL) { |
956 | pr_err("%s: cannot read %s ELF file.\n", __func__, name); | 1003 | pr_debug("%s: cannot read %s ELF file.\n", __func__, name); |
957 | goto out_close; | 1004 | goto out_close; |
958 | } | 1005 | } |
959 | 1006 | ||
960 | if (gelf_getehdr(elf, &ehdr) == NULL) { | 1007 | if (gelf_getehdr(elf, &ehdr) == NULL) { |
961 | pr_err("%s: cannot get elf header.\n", __func__); | 1008 | pr_debug("%s: cannot get elf header.\n", __func__); |
962 | goto out_elf_end; | 1009 | goto out_elf_end; |
963 | } | 1010 | } |
964 | 1011 | ||
1012 | /* Always reject images with a mismatched build-id: */ | ||
1013 | if (self->has_build_id) { | ||
1014 | u8 build_id[BUILD_ID_SIZE]; | ||
1015 | |||
1016 | if (elf_read_build_id(elf, build_id, | ||
1017 | BUILD_ID_SIZE) != BUILD_ID_SIZE) | ||
1018 | goto out_elf_end; | ||
1019 | |||
1020 | if (!dso__build_id_equal(self, build_id)) | ||
1021 | goto out_elf_end; | ||
1022 | } | ||
1023 | |||
965 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | 1024 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); |
966 | if (sec == NULL) { | 1025 | if (sec == NULL) { |
1026 | if (want_symtab) | ||
1027 | goto out_elf_end; | ||
1028 | |||
967 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); | 1029 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); |
968 | if (sec == NULL) | 1030 | if (sec == NULL) |
969 | goto out_elf_end; | 1031 | goto out_elf_end; |
970 | } | 1032 | } |
971 | 1033 | ||
1034 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | ||
1035 | if (opdsec) | ||
1036 | opddata = elf_rawdata(opdsec, NULL); | ||
1037 | |||
972 | syms = elf_getdata(sec, NULL); | 1038 | syms = elf_getdata(sec, NULL); |
973 | if (syms == NULL) | 1039 | if (syms == NULL) |
974 | goto out_elf_end; | 1040 | goto out_elf_end; |
@@ -1013,6 +1079,23 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1013 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | 1079 | if (!is_label && !elf_sym__is_a(&sym, map->type)) |
1014 | continue; | 1080 | continue; |
1015 | 1081 | ||
1082 | /* Reject ARM ELF "mapping symbols": these aren't unique and | ||
1083 | * don't identify functions, so will confuse the profile | ||
1084 | * output: */ | ||
1085 | if (ehdr.e_machine == EM_ARM) { | ||
1086 | if (!strcmp(elf_name, "$a") || | ||
1087 | !strcmp(elf_name, "$d") || | ||
1088 | !strcmp(elf_name, "$t")) | ||
1089 | continue; | ||
1090 | } | ||
1091 | |||
1092 | if (opdsec && sym.st_shndx == opdidx) { | ||
1093 | u32 offset = sym.st_value - opdshdr.sh_addr; | ||
1094 | u64 *opd = opddata->d_buf + offset; | ||
1095 | sym.st_value = *opd; | ||
1096 | sym.st_shndx = elf_addr_to_index(elf, sym.st_value); | ||
1097 | } | ||
1098 | |||
1016 | sec = elf_getscn(elf, sym.st_shndx); | 1099 | sec = elf_getscn(elf, sym.st_shndx); |
1017 | if (!sec) | 1100 | if (!sec) |
1018 | goto out_elf_end; | 1101 | goto out_elf_end; |
@@ -1086,7 +1169,8 @@ static int dso__load_sym(struct dso *self, struct map *map, const char *name, | |||
1086 | if (demangled != NULL) | 1169 | if (demangled != NULL) |
1087 | elf_name = demangled; | 1170 | elf_name = demangled; |
1088 | new_symbol: | 1171 | new_symbol: |
1089 | f = symbol__new(sym.st_value, sym.st_size, elf_name); | 1172 | f = symbol__new(sym.st_value, sym.st_size, |
1173 | GELF_ST_BIND(sym.st_info), elf_name); | ||
1090 | free(demangled); | 1174 | free(demangled); |
1091 | if (!f) | 1175 | if (!f) |
1092 | goto out_elf_end; | 1176 | goto out_elf_end; |
@@ -1151,37 +1235,26 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
1151 | */ | 1235 | */ |
1152 | #define NOTE_ALIGN(n) (((n) + 3) & -4U) | 1236 | #define NOTE_ALIGN(n) (((n) + 3) & -4U) |
1153 | 1237 | ||
1154 | int filename__read_build_id(const char *filename, void *bf, size_t size) | 1238 | static int elf_read_build_id(Elf *elf, void *bf, size_t size) |
1155 | { | 1239 | { |
1156 | int fd, err = -1; | 1240 | int err = -1; |
1157 | GElf_Ehdr ehdr; | 1241 | GElf_Ehdr ehdr; |
1158 | GElf_Shdr shdr; | 1242 | GElf_Shdr shdr; |
1159 | Elf_Data *data; | 1243 | Elf_Data *data; |
1160 | Elf_Scn *sec; | 1244 | Elf_Scn *sec; |
1161 | Elf_Kind ek; | 1245 | Elf_Kind ek; |
1162 | void *ptr; | 1246 | void *ptr; |
1163 | Elf *elf; | ||
1164 | 1247 | ||
1165 | if (size < BUILD_ID_SIZE) | 1248 | if (size < BUILD_ID_SIZE) |
1166 | goto out; | 1249 | goto out; |
1167 | 1250 | ||
1168 | fd = open(filename, O_RDONLY); | ||
1169 | if (fd < 0) | ||
1170 | goto out; | ||
1171 | |||
1172 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1173 | if (elf == NULL) { | ||
1174 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1175 | goto out_close; | ||
1176 | } | ||
1177 | |||
1178 | ek = elf_kind(elf); | 1251 | ek = elf_kind(elf); |
1179 | if (ek != ELF_K_ELF) | 1252 | if (ek != ELF_K_ELF) |
1180 | goto out_elf_end; | 1253 | goto out; |
1181 | 1254 | ||
1182 | if (gelf_getehdr(elf, &ehdr) == NULL) { | 1255 | if (gelf_getehdr(elf, &ehdr) == NULL) { |
1183 | pr_err("%s: cannot get elf header.\n", __func__); | 1256 | pr_err("%s: cannot get elf header.\n", __func__); |
1184 | goto out_elf_end; | 1257 | goto out; |
1185 | } | 1258 | } |
1186 | 1259 | ||
1187 | sec = elf_section_by_name(elf, &ehdr, &shdr, | 1260 | sec = elf_section_by_name(elf, &ehdr, &shdr, |
@@ -1190,12 +1263,12 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) | |||
1190 | sec = elf_section_by_name(elf, &ehdr, &shdr, | 1263 | sec = elf_section_by_name(elf, &ehdr, &shdr, |
1191 | ".notes", NULL); | 1264 | ".notes", NULL); |
1192 | if (sec == NULL) | 1265 | if (sec == NULL) |
1193 | goto out_elf_end; | 1266 | goto out; |
1194 | } | 1267 | } |
1195 | 1268 | ||
1196 | data = elf_getdata(sec, NULL); | 1269 | data = elf_getdata(sec, NULL); |
1197 | if (data == NULL) | 1270 | if (data == NULL) |
1198 | goto out_elf_end; | 1271 | goto out; |
1199 | 1272 | ||
1200 | ptr = data->d_buf; | 1273 | ptr = data->d_buf; |
1201 | while (ptr < (data->d_buf + data->d_size)) { | 1274 | while (ptr < (data->d_buf + data->d_size)) { |
@@ -1217,7 +1290,31 @@ int filename__read_build_id(const char *filename, void *bf, size_t size) | |||
1217 | } | 1290 | } |
1218 | ptr += descsz; | 1291 | ptr += descsz; |
1219 | } | 1292 | } |
1220 | out_elf_end: | 1293 | |
1294 | out: | ||
1295 | return err; | ||
1296 | } | ||
1297 | |||
1298 | int filename__read_build_id(const char *filename, void *bf, size_t size) | ||
1299 | { | ||
1300 | int fd, err = -1; | ||
1301 | Elf *elf; | ||
1302 | |||
1303 | if (size < BUILD_ID_SIZE) | ||
1304 | goto out; | ||
1305 | |||
1306 | fd = open(filename, O_RDONLY); | ||
1307 | if (fd < 0) | ||
1308 | goto out; | ||
1309 | |||
1310 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1311 | if (elf == NULL) { | ||
1312 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1313 | goto out_close; | ||
1314 | } | ||
1315 | |||
1316 | err = elf_read_build_id(elf, bf, size); | ||
1317 | |||
1221 | elf_end(elf); | 1318 | elf_end(elf); |
1222 | out_close: | 1319 | out_close: |
1223 | close(fd); | 1320 | close(fd); |
@@ -1293,11 +1390,11 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1293 | { | 1390 | { |
1294 | int size = PATH_MAX; | 1391 | int size = PATH_MAX; |
1295 | char *name; | 1392 | char *name; |
1296 | u8 build_id[BUILD_ID_SIZE]; | ||
1297 | int ret = -1; | 1393 | int ret = -1; |
1298 | int fd; | 1394 | int fd; |
1299 | struct machine *machine; | 1395 | struct machine *machine; |
1300 | const char *root_dir; | 1396 | const char *root_dir; |
1397 | int want_symtab; | ||
1301 | 1398 | ||
1302 | dso__set_loaded(self, map->type); | 1399 | dso__set_loaded(self, map->type); |
1303 | 1400 | ||
@@ -1324,13 +1421,18 @@ int dso__load(struct dso *self, struct map *map, symbol_filter_t filter) | |||
1324 | return ret; | 1421 | return ret; |
1325 | } | 1422 | } |
1326 | 1423 | ||
1327 | self->origin = DSO__ORIG_BUILD_ID_CACHE; | 1424 | /* Iterate over candidate debug images. |
1328 | if (dso__build_id_filename(self, name, size) != NULL) | 1425 | * On the first pass, only load images if they have a full symtab. |
1329 | goto open_file; | 1426 | * Failing that, do a second pass where we accept .dynsym also |
1330 | more: | 1427 | */ |
1331 | do { | 1428 | for (self->origin = DSO__ORIG_BUILD_ID_CACHE, want_symtab = 1; |
1332 | self->origin++; | 1429 | self->origin != DSO__ORIG_NOT_FOUND; |
1430 | self->origin++) { | ||
1333 | switch (self->origin) { | 1431 | switch (self->origin) { |
1432 | case DSO__ORIG_BUILD_ID_CACHE: | ||
1433 | if (dso__build_id_filename(self, name, size) == NULL) | ||
1434 | continue; | ||
1435 | break; | ||
1334 | case DSO__ORIG_FEDORA: | 1436 | case DSO__ORIG_FEDORA: |
1335 | snprintf(name, size, "/usr/lib/debug%s.debug", | 1437 | snprintf(name, size, "/usr/lib/debug%s.debug", |
1336 | self->long_name); | 1438 | self->long_name); |
@@ -1339,21 +1441,20 @@ more: | |||
1339 | snprintf(name, size, "/usr/lib/debug%s", | 1441 | snprintf(name, size, "/usr/lib/debug%s", |
1340 | self->long_name); | 1442 | self->long_name); |
1341 | break; | 1443 | break; |
1342 | case DSO__ORIG_BUILDID: | 1444 | case DSO__ORIG_BUILDID: { |
1343 | if (filename__read_build_id(self->long_name, build_id, | 1445 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; |
1344 | sizeof(build_id))) { | 1446 | |
1345 | char build_id_hex[BUILD_ID_SIZE * 2 + 1]; | 1447 | if (!self->has_build_id) |
1346 | build_id__sprintf(build_id, sizeof(build_id), | 1448 | continue; |
1347 | build_id_hex); | 1449 | |
1348 | snprintf(name, size, | 1450 | build_id__sprintf(self->build_id, |
1349 | "/usr/lib/debug/.build-id/%.2s/%s.debug", | 1451 | sizeof(self->build_id), |
1350 | build_id_hex, build_id_hex + 2); | 1452 | build_id_hex); |
1351 | if (self->has_build_id) | 1453 | snprintf(name, size, |
1352 | goto compare_build_id; | 1454 | "/usr/lib/debug/.build-id/%.2s/%s.debug", |
1353 | break; | 1455 | build_id_hex, build_id_hex + 2); |
1354 | } | 1456 | } |
1355 | self->origin++; | 1457 | break; |
1356 | /* Fall thru */ | ||
1357 | case DSO__ORIG_DSO: | 1458 | case DSO__ORIG_DSO: |
1358 | snprintf(name, size, "%s", self->long_name); | 1459 | snprintf(name, size, "%s", self->long_name); |
1359 | break; | 1460 | break; |
@@ -1366,36 +1467,41 @@ more: | |||
1366 | break; | 1467 | break; |
1367 | 1468 | ||
1368 | default: | 1469 | default: |
1369 | goto out; | 1470 | /* |
1471 | * If we wanted a full symtab but no image had one, | ||
1472 | * relax our requirements and repeat the search. | ||
1473 | */ | ||
1474 | if (want_symtab) { | ||
1475 | want_symtab = 0; | ||
1476 | self->origin = DSO__ORIG_BUILD_ID_CACHE; | ||
1477 | } else | ||
1478 | continue; | ||
1370 | } | 1479 | } |
1371 | 1480 | ||
1372 | if (self->has_build_id) { | 1481 | /* Name is now the name of the next image to try */ |
1373 | if (filename__read_build_id(name, build_id, | ||
1374 | sizeof(build_id)) < 0) | ||
1375 | goto more; | ||
1376 | compare_build_id: | ||
1377 | if (!dso__build_id_equal(self, build_id)) | ||
1378 | goto more; | ||
1379 | } | ||
1380 | open_file: | ||
1381 | fd = open(name, O_RDONLY); | 1482 | fd = open(name, O_RDONLY); |
1382 | } while (fd < 0); | 1483 | if (fd < 0) |
1484 | continue; | ||
1383 | 1485 | ||
1384 | ret = dso__load_sym(self, map, name, fd, filter, 0); | 1486 | ret = dso__load_sym(self, map, name, fd, filter, 0, |
1385 | close(fd); | 1487 | want_symtab); |
1488 | close(fd); | ||
1386 | 1489 | ||
1387 | /* | 1490 | /* |
1388 | * Some people seem to have debuginfo files _WITHOUT_ debug info!?!? | 1491 | * Some people seem to have debuginfo files _WITHOUT_ debug |
1389 | */ | 1492 | * info!?!? |
1390 | if (!ret) | 1493 | */ |
1391 | goto more; | 1494 | if (!ret) |
1495 | continue; | ||
1392 | 1496 | ||
1393 | if (ret > 0) { | 1497 | if (ret > 0) { |
1394 | int nr_plt = dso__synthesize_plt_symbols(self, map, filter); | 1498 | int nr_plt = dso__synthesize_plt_symbols(self, map, filter); |
1395 | if (nr_plt > 0) | 1499 | if (nr_plt > 0) |
1396 | ret += nr_plt; | 1500 | ret += nr_plt; |
1501 | break; | ||
1502 | } | ||
1397 | } | 1503 | } |
1398 | out: | 1504 | |
1399 | free(name); | 1505 | free(name); |
1400 | if (ret < 0 && strstr(self->name, " (deleted)") != NULL) | 1506 | if (ret < 0 && strstr(self->name, " (deleted)") != NULL) |
1401 | return 0; | 1507 | return 0; |
@@ -1494,6 +1600,7 @@ static int map_groups__set_modules_path_dir(struct map_groups *self, | |||
1494 | goto out; | 1600 | goto out; |
1495 | } | 1601 | } |
1496 | dso__set_long_name(map->dso, long_name); | 1602 | dso__set_long_name(map->dso, long_name); |
1603 | map->dso->lname_alloc = 1; | ||
1497 | dso__kernel_module_get_build_id(map->dso, ""); | 1604 | dso__kernel_module_get_build_id(map->dso, ""); |
1498 | } | 1605 | } |
1499 | } | 1606 | } |
@@ -1656,36 +1763,12 @@ static int dso__load_vmlinux(struct dso *self, struct map *map, | |||
1656 | { | 1763 | { |
1657 | int err = -1, fd; | 1764 | int err = -1, fd; |
1658 | 1765 | ||
1659 | if (self->has_build_id) { | ||
1660 | u8 build_id[BUILD_ID_SIZE]; | ||
1661 | |||
1662 | if (filename__read_build_id(vmlinux, build_id, | ||
1663 | sizeof(build_id)) < 0) { | ||
1664 | pr_debug("No build_id in %s, ignoring it\n", vmlinux); | ||
1665 | return -1; | ||
1666 | } | ||
1667 | if (!dso__build_id_equal(self, build_id)) { | ||
1668 | char expected_build_id[BUILD_ID_SIZE * 2 + 1], | ||
1669 | vmlinux_build_id[BUILD_ID_SIZE * 2 + 1]; | ||
1670 | |||
1671 | build_id__sprintf(self->build_id, | ||
1672 | sizeof(self->build_id), | ||
1673 | expected_build_id); | ||
1674 | build_id__sprintf(build_id, sizeof(build_id), | ||
1675 | vmlinux_build_id); | ||
1676 | pr_debug("build_id in %s is %s while expected is %s, " | ||
1677 | "ignoring it\n", vmlinux, vmlinux_build_id, | ||
1678 | expected_build_id); | ||
1679 | return -1; | ||
1680 | } | ||
1681 | } | ||
1682 | |||
1683 | fd = open(vmlinux, O_RDONLY); | 1766 | fd = open(vmlinux, O_RDONLY); |
1684 | if (fd < 0) | 1767 | if (fd < 0) |
1685 | return -1; | 1768 | return -1; |
1686 | 1769 | ||
1687 | dso__set_loaded(self, map->type); | 1770 | dso__set_loaded(self, map->type); |
1688 | err = dso__load_sym(self, map, vmlinux, fd, filter, 0); | 1771 | err = dso__load_sym(self, map, vmlinux, fd, filter, 0, 0); |
1689 | close(fd); | 1772 | close(fd); |
1690 | 1773 | ||
1691 | if (err > 0) | 1774 | if (err > 0) |
@@ -2048,6 +2131,36 @@ int __machine__create_kernel_maps(struct machine *self, struct dso *kernel) | |||
2048 | return 0; | 2131 | return 0; |
2049 | } | 2132 | } |
2050 | 2133 | ||
2134 | void machine__destroy_kernel_maps(struct machine *self) | ||
2135 | { | ||
2136 | enum map_type type; | ||
2137 | |||
2138 | for (type = 0; type < MAP__NR_TYPES; ++type) { | ||
2139 | struct kmap *kmap; | ||
2140 | |||
2141 | if (self->vmlinux_maps[type] == NULL) | ||
2142 | continue; | ||
2143 | |||
2144 | kmap = map__kmap(self->vmlinux_maps[type]); | ||
2145 | map_groups__remove(&self->kmaps, self->vmlinux_maps[type]); | ||
2146 | if (kmap->ref_reloc_sym) { | ||
2147 | /* | ||
2148 | * ref_reloc_sym is shared among all maps, so free just | ||
2149 | * on one of them. | ||
2150 | */ | ||
2151 | if (type == MAP__FUNCTION) { | ||
2152 | free((char *)kmap->ref_reloc_sym->name); | ||
2153 | kmap->ref_reloc_sym->name = NULL; | ||
2154 | free(kmap->ref_reloc_sym); | ||
2155 | } | ||
2156 | kmap->ref_reloc_sym = NULL; | ||
2157 | } | ||
2158 | |||
2159 | map__delete(self->vmlinux_maps[type]); | ||
2160 | self->vmlinux_maps[type] = NULL; | ||
2161 | } | ||
2162 | } | ||
2163 | |||
2051 | int machine__create_kernel_maps(struct machine *self) | 2164 | int machine__create_kernel_maps(struct machine *self) |
2052 | { | 2165 | { |
2053 | struct dso *kernel = machine__create_kernel(self); | 2166 | struct dso *kernel = machine__create_kernel(self); |
@@ -2189,6 +2302,15 @@ out_free_comm_list: | |||
2189 | return -1; | 2302 | return -1; |
2190 | } | 2303 | } |
2191 | 2304 | ||
2305 | void symbol__exit(void) | ||
2306 | { | ||
2307 | strlist__delete(symbol_conf.sym_list); | ||
2308 | strlist__delete(symbol_conf.dso_list); | ||
2309 | strlist__delete(symbol_conf.comm_list); | ||
2310 | vmlinux_path__exit(); | ||
2311 | symbol_conf.sym_list = symbol_conf.dso_list = symbol_conf.comm_list = NULL; | ||
2312 | } | ||
2313 | |||
2192 | int machines__create_kernel_maps(struct rb_root *self, pid_t pid) | 2314 | int machines__create_kernel_maps(struct rb_root *self, pid_t pid) |
2193 | { | 2315 | { |
2194 | struct machine *machine = machines__findnew(self, pid); | 2316 | struct machine *machine = machines__findnew(self, pid); |
@@ -2283,6 +2405,19 @@ failure: | |||
2283 | return ret; | 2405 | return ret; |
2284 | } | 2406 | } |
2285 | 2407 | ||
2408 | void machines__destroy_guest_kernel_maps(struct rb_root *self) | ||
2409 | { | ||
2410 | struct rb_node *next = rb_first(self); | ||
2411 | |||
2412 | while (next) { | ||
2413 | struct machine *pos = rb_entry(next, struct machine, rb_node); | ||
2414 | |||
2415 | next = rb_next(&pos->rb_node); | ||
2416 | rb_erase(&pos->rb_node, self); | ||
2417 | machine__delete(pos); | ||
2418 | } | ||
2419 | } | ||
2420 | |||
2286 | int machine__load_kallsyms(struct machine *self, const char *filename, | 2421 | int machine__load_kallsyms(struct machine *self, const char *filename, |
2287 | enum map_type type, symbol_filter_t filter) | 2422 | enum map_type type, symbol_filter_t filter) |
2288 | { | 2423 | { |