diff options
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/map.c | 19 | ||||
-rw-r--r-- | tools/perf/util/map.h | 1 | ||||
-rw-r--r-- | tools/perf/util/symbol-elf.c | 774 | ||||
-rw-r--r-- | tools/perf/util/symbol.c | 804 | ||||
-rw-r--r-- | tools/perf/util/symbol.h | 15 |
5 files changed, 816 insertions, 797 deletions
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c index cc33486ad9e2..115654c469c6 100644 --- a/tools/perf/util/map.c +++ b/tools/perf/util/map.c | |||
@@ -86,6 +86,25 @@ out_delete: | |||
86 | return NULL; | 86 | return NULL; |
87 | } | 87 | } |
88 | 88 | ||
89 | /* | ||
90 | * Constructor variant for modules (where we know from /proc/modules where | ||
91 | * they are loaded) and for vmlinux, where only after we load all the | ||
92 | * symbols we'll know where it starts and ends. | ||
93 | */ | ||
94 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | ||
95 | { | ||
96 | struct map *map = calloc(1, (sizeof(*map) + | ||
97 | (dso->kernel ? sizeof(struct kmap) : 0))); | ||
98 | if (map != NULL) { | ||
99 | /* | ||
100 | * ->end will be filled after we load all the symbols | ||
101 | */ | ||
102 | map__init(map, type, start, 0, 0, dso); | ||
103 | } | ||
104 | |||
105 | return map; | ||
106 | } | ||
107 | |||
89 | void map__delete(struct map *self) | 108 | void map__delete(struct map *self) |
90 | { | 109 | { |
91 | free(self); | 110 | free(self); |
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h index 03a1e9b08b21..1e183d1ae581 100644 --- a/tools/perf/util/map.h +++ b/tools/perf/util/map.h | |||
@@ -115,6 +115,7 @@ void map__init(struct map *self, enum map_type type, | |||
115 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, | 115 | struct map *map__new(struct list_head *dsos__list, u64 start, u64 len, |
116 | u64 pgoff, u32 pid, char *filename, | 116 | u64 pgoff, u32 pid, char *filename, |
117 | enum map_type type); | 117 | enum map_type type); |
118 | struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | ||
118 | void map__delete(struct map *self); | 119 | void map__delete(struct map *self); |
119 | struct map *map__clone(struct map *self); | 120 | struct map *map__clone(struct map *self); |
120 | int map__overlap(struct map *l, struct map *r); | 121 | int map__overlap(struct map *l, struct map *r); |
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c new file mode 100644 index 000000000000..9ca89f8f6c97 --- /dev/null +++ b/tools/perf/util/symbol-elf.c | |||
@@ -0,0 +1,774 @@ | |||
1 | #include <libelf.h> | ||
2 | #include <gelf.h> | ||
3 | #include <elf.h> | ||
4 | #include <fcntl.h> | ||
5 | #include <stdio.h> | ||
6 | #include <errno.h> | ||
7 | #include <string.h> | ||
8 | #include <unistd.h> | ||
9 | #include <inttypes.h> | ||
10 | |||
11 | #include "symbol.h" | ||
12 | #include "debug.h" | ||
13 | |||
14 | #ifndef NT_GNU_BUILD_ID | ||
15 | #define NT_GNU_BUILD_ID 3 | ||
16 | #endif | ||
17 | |||
18 | /** | ||
19 | * elf_symtab__for_each_symbol - iterate thru all the symbols | ||
20 | * | ||
21 | * @syms: struct elf_symtab instance to iterate | ||
22 | * @idx: uint32_t idx | ||
23 | * @sym: GElf_Sym iterator | ||
24 | */ | ||
25 | #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ | ||
26 | for (idx = 0, gelf_getsym(syms, idx, &sym);\ | ||
27 | idx < nr_syms; \ | ||
28 | idx++, gelf_getsym(syms, idx, &sym)) | ||
29 | |||
30 | static inline uint8_t elf_sym__type(const GElf_Sym *sym) | ||
31 | { | ||
32 | return GELF_ST_TYPE(sym->st_info); | ||
33 | } | ||
34 | |||
35 | static inline int elf_sym__is_function(const GElf_Sym *sym) | ||
36 | { | ||
37 | return elf_sym__type(sym) == STT_FUNC && | ||
38 | sym->st_name != 0 && | ||
39 | sym->st_shndx != SHN_UNDEF; | ||
40 | } | ||
41 | |||
42 | static inline bool elf_sym__is_object(const GElf_Sym *sym) | ||
43 | { | ||
44 | return elf_sym__type(sym) == STT_OBJECT && | ||
45 | sym->st_name != 0 && | ||
46 | sym->st_shndx != SHN_UNDEF; | ||
47 | } | ||
48 | |||
49 | static inline int elf_sym__is_label(const GElf_Sym *sym) | ||
50 | { | ||
51 | return elf_sym__type(sym) == STT_NOTYPE && | ||
52 | sym->st_name != 0 && | ||
53 | sym->st_shndx != SHN_UNDEF && | ||
54 | sym->st_shndx != SHN_ABS; | ||
55 | } | ||
56 | |||
57 | static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) | ||
58 | { | ||
59 | switch (type) { | ||
60 | case MAP__FUNCTION: | ||
61 | return elf_sym__is_function(sym); | ||
62 | case MAP__VARIABLE: | ||
63 | return elf_sym__is_object(sym); | ||
64 | default: | ||
65 | return false; | ||
66 | } | ||
67 | } | ||
68 | |||
69 | static inline const char *elf_sym__name(const GElf_Sym *sym, | ||
70 | const Elf_Data *symstrs) | ||
71 | { | ||
72 | return symstrs->d_buf + sym->st_name; | ||
73 | } | ||
74 | |||
75 | static inline const char *elf_sec__name(const GElf_Shdr *shdr, | ||
76 | const Elf_Data *secstrs) | ||
77 | { | ||
78 | return secstrs->d_buf + shdr->sh_name; | ||
79 | } | ||
80 | |||
81 | static inline int elf_sec__is_text(const GElf_Shdr *shdr, | ||
82 | const Elf_Data *secstrs) | ||
83 | { | ||
84 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | ||
85 | } | ||
86 | |||
87 | static inline bool elf_sec__is_data(const GElf_Shdr *shdr, | ||
88 | const Elf_Data *secstrs) | ||
89 | { | ||
90 | return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; | ||
91 | } | ||
92 | |||
93 | static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, | ||
94 | enum map_type type) | ||
95 | { | ||
96 | switch (type) { | ||
97 | case MAP__FUNCTION: | ||
98 | return elf_sec__is_text(shdr, secstrs); | ||
99 | case MAP__VARIABLE: | ||
100 | return elf_sec__is_data(shdr, secstrs); | ||
101 | default: | ||
102 | return false; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | ||
107 | { | ||
108 | Elf_Scn *sec = NULL; | ||
109 | GElf_Shdr shdr; | ||
110 | size_t cnt = 1; | ||
111 | |||
112 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
113 | gelf_getshdr(sec, &shdr); | ||
114 | |||
115 | if ((addr >= shdr.sh_addr) && | ||
116 | (addr < (shdr.sh_addr + shdr.sh_size))) | ||
117 | return cnt; | ||
118 | |||
119 | ++cnt; | ||
120 | } | ||
121 | |||
122 | return -1; | ||
123 | } | ||
124 | |||
125 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
126 | GElf_Shdr *shp, const char *name, | ||
127 | size_t *idx) | ||
128 | { | ||
129 | Elf_Scn *sec = NULL; | ||
130 | size_t cnt = 1; | ||
131 | |||
132 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
133 | char *str; | ||
134 | |||
135 | gelf_getshdr(sec, shp); | ||
136 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
137 | if (!strcmp(name, str)) { | ||
138 | if (idx) | ||
139 | *idx = cnt; | ||
140 | break; | ||
141 | } | ||
142 | ++cnt; | ||
143 | } | ||
144 | |||
145 | return sec; | ||
146 | } | ||
147 | |||
148 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ | ||
149 | for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ | ||
150 | idx < nr_entries; \ | ||
151 | ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) | ||
152 | |||
153 | #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ | ||
154 | for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ | ||
155 | idx < nr_entries; \ | ||
156 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | ||
157 | |||
158 | /* | ||
159 | * We need to check if we have a .dynsym, so that we can handle the | ||
160 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it | ||
161 | * .dynsym or .symtab). | ||
162 | * And always look at the original dso, not at debuginfo packages, that | ||
163 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | ||
164 | */ | ||
165 | int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, | ||
166 | symbol_filter_t filter) | ||
167 | { | ||
168 | uint32_t nr_rel_entries, idx; | ||
169 | GElf_Sym sym; | ||
170 | u64 plt_offset; | ||
171 | GElf_Shdr shdr_plt; | ||
172 | struct symbol *f; | ||
173 | GElf_Shdr shdr_rel_plt, shdr_dynsym; | ||
174 | Elf_Data *reldata, *syms, *symstrs; | ||
175 | Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; | ||
176 | size_t dynsym_idx; | ||
177 | GElf_Ehdr ehdr; | ||
178 | char sympltname[1024]; | ||
179 | Elf *elf; | ||
180 | int nr = 0, symidx, fd, err = 0; | ||
181 | |||
182 | fd = open(name, O_RDONLY); | ||
183 | if (fd < 0) | ||
184 | goto out; | ||
185 | |||
186 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
187 | if (elf == NULL) | ||
188 | goto out_close; | ||
189 | |||
190 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
191 | goto out_elf_end; | ||
192 | |||
193 | scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, | ||
194 | ".dynsym", &dynsym_idx); | ||
195 | if (scn_dynsym == NULL) | ||
196 | goto out_elf_end; | ||
197 | |||
198 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
199 | ".rela.plt", NULL); | ||
200 | if (scn_plt_rel == NULL) { | ||
201 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
202 | ".rel.plt", NULL); | ||
203 | if (scn_plt_rel == NULL) | ||
204 | goto out_elf_end; | ||
205 | } | ||
206 | |||
207 | err = -1; | ||
208 | |||
209 | if (shdr_rel_plt.sh_link != dynsym_idx) | ||
210 | goto out_elf_end; | ||
211 | |||
212 | if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) | ||
213 | goto out_elf_end; | ||
214 | |||
215 | /* | ||
216 | * Fetch the relocation section to find the idxes to the GOT | ||
217 | * and the symbols in the .dynsym they refer to. | ||
218 | */ | ||
219 | reldata = elf_getdata(scn_plt_rel, NULL); | ||
220 | if (reldata == NULL) | ||
221 | goto out_elf_end; | ||
222 | |||
223 | syms = elf_getdata(scn_dynsym, NULL); | ||
224 | if (syms == NULL) | ||
225 | goto out_elf_end; | ||
226 | |||
227 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); | ||
228 | if (scn_symstrs == NULL) | ||
229 | goto out_elf_end; | ||
230 | |||
231 | symstrs = elf_getdata(scn_symstrs, NULL); | ||
232 | if (symstrs == NULL) | ||
233 | goto out_elf_end; | ||
234 | |||
235 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; | ||
236 | plt_offset = shdr_plt.sh_offset; | ||
237 | |||
238 | if (shdr_rel_plt.sh_type == SHT_RELA) { | ||
239 | GElf_Rela pos_mem, *pos; | ||
240 | |||
241 | elf_section__for_each_rela(reldata, pos, pos_mem, idx, | ||
242 | nr_rel_entries) { | ||
243 | symidx = GELF_R_SYM(pos->r_info); | ||
244 | plt_offset += shdr_plt.sh_entsize; | ||
245 | gelf_getsym(syms, symidx, &sym); | ||
246 | snprintf(sympltname, sizeof(sympltname), | ||
247 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
248 | |||
249 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
250 | STB_GLOBAL, sympltname); | ||
251 | if (!f) | ||
252 | goto out_elf_end; | ||
253 | |||
254 | if (filter && filter(map, f)) | ||
255 | symbol__delete(f); | ||
256 | else { | ||
257 | symbols__insert(&dso->symbols[map->type], f); | ||
258 | ++nr; | ||
259 | } | ||
260 | } | ||
261 | } else if (shdr_rel_plt.sh_type == SHT_REL) { | ||
262 | GElf_Rel pos_mem, *pos; | ||
263 | elf_section__for_each_rel(reldata, pos, pos_mem, idx, | ||
264 | nr_rel_entries) { | ||
265 | symidx = GELF_R_SYM(pos->r_info); | ||
266 | plt_offset += shdr_plt.sh_entsize; | ||
267 | gelf_getsym(syms, symidx, &sym); | ||
268 | snprintf(sympltname, sizeof(sympltname), | ||
269 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
270 | |||
271 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
272 | STB_GLOBAL, sympltname); | ||
273 | if (!f) | ||
274 | goto out_elf_end; | ||
275 | |||
276 | if (filter && filter(map, f)) | ||
277 | symbol__delete(f); | ||
278 | else { | ||
279 | symbols__insert(&dso->symbols[map->type], f); | ||
280 | ++nr; | ||
281 | } | ||
282 | } | ||
283 | } | ||
284 | |||
285 | err = 0; | ||
286 | out_elf_end: | ||
287 | elf_end(elf); | ||
288 | out_close: | ||
289 | close(fd); | ||
290 | |||
291 | if (err == 0) | ||
292 | return nr; | ||
293 | out: | ||
294 | pr_debug("%s: problems reading %s PLT info.\n", | ||
295 | __func__, dso->long_name); | ||
296 | return 0; | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Align offset to 4 bytes as needed for note name and descriptor data. | ||
301 | */ | ||
302 | #define NOTE_ALIGN(n) (((n) + 3) & -4U) | ||
303 | |||
304 | static int elf_read_build_id(Elf *elf, void *bf, size_t size) | ||
305 | { | ||
306 | int err = -1; | ||
307 | GElf_Ehdr ehdr; | ||
308 | GElf_Shdr shdr; | ||
309 | Elf_Data *data; | ||
310 | Elf_Scn *sec; | ||
311 | Elf_Kind ek; | ||
312 | void *ptr; | ||
313 | |||
314 | if (size < BUILD_ID_SIZE) | ||
315 | goto out; | ||
316 | |||
317 | ek = elf_kind(elf); | ||
318 | if (ek != ELF_K_ELF) | ||
319 | goto out; | ||
320 | |||
321 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
322 | pr_err("%s: cannot get elf header.\n", __func__); | ||
323 | goto out; | ||
324 | } | ||
325 | |||
326 | /* | ||
327 | * Check following sections for notes: | ||
328 | * '.note.gnu.build-id' | ||
329 | * '.notes' | ||
330 | * '.note' (VDSO specific) | ||
331 | */ | ||
332 | do { | ||
333 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
334 | ".note.gnu.build-id", NULL); | ||
335 | if (sec) | ||
336 | break; | ||
337 | |||
338 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
339 | ".notes", NULL); | ||
340 | if (sec) | ||
341 | break; | ||
342 | |||
343 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
344 | ".note", NULL); | ||
345 | if (sec) | ||
346 | break; | ||
347 | |||
348 | return err; | ||
349 | |||
350 | } while (0); | ||
351 | |||
352 | data = elf_getdata(sec, NULL); | ||
353 | if (data == NULL) | ||
354 | goto out; | ||
355 | |||
356 | ptr = data->d_buf; | ||
357 | while (ptr < (data->d_buf + data->d_size)) { | ||
358 | GElf_Nhdr *nhdr = ptr; | ||
359 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), | ||
360 | descsz = NOTE_ALIGN(nhdr->n_descsz); | ||
361 | const char *name; | ||
362 | |||
363 | ptr += sizeof(*nhdr); | ||
364 | name = ptr; | ||
365 | ptr += namesz; | ||
366 | if (nhdr->n_type == NT_GNU_BUILD_ID && | ||
367 | nhdr->n_namesz == sizeof("GNU")) { | ||
368 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | ||
369 | size_t sz = min(size, descsz); | ||
370 | memcpy(bf, ptr, sz); | ||
371 | memset(bf + sz, 0, size - sz); | ||
372 | err = descsz; | ||
373 | break; | ||
374 | } | ||
375 | } | ||
376 | ptr += descsz; | ||
377 | } | ||
378 | |||
379 | out: | ||
380 | return err; | ||
381 | } | ||
382 | |||
383 | int filename__read_build_id(const char *filename, void *bf, size_t size) | ||
384 | { | ||
385 | int fd, err = -1; | ||
386 | Elf *elf; | ||
387 | |||
388 | if (size < BUILD_ID_SIZE) | ||
389 | goto out; | ||
390 | |||
391 | fd = open(filename, O_RDONLY); | ||
392 | if (fd < 0) | ||
393 | goto out; | ||
394 | |||
395 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
396 | if (elf == NULL) { | ||
397 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
398 | goto out_close; | ||
399 | } | ||
400 | |||
401 | err = elf_read_build_id(elf, bf, size); | ||
402 | |||
403 | elf_end(elf); | ||
404 | out_close: | ||
405 | close(fd); | ||
406 | out: | ||
407 | return err; | ||
408 | } | ||
409 | |||
410 | int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | ||
411 | { | ||
412 | int fd, err = -1; | ||
413 | |||
414 | if (size < BUILD_ID_SIZE) | ||
415 | goto out; | ||
416 | |||
417 | fd = open(filename, O_RDONLY); | ||
418 | if (fd < 0) | ||
419 | goto out; | ||
420 | |||
421 | while (1) { | ||
422 | char bf[BUFSIZ]; | ||
423 | GElf_Nhdr nhdr; | ||
424 | size_t namesz, descsz; | ||
425 | |||
426 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | ||
427 | break; | ||
428 | |||
429 | namesz = NOTE_ALIGN(nhdr.n_namesz); | ||
430 | descsz = NOTE_ALIGN(nhdr.n_descsz); | ||
431 | if (nhdr.n_type == NT_GNU_BUILD_ID && | ||
432 | nhdr.n_namesz == sizeof("GNU")) { | ||
433 | if (read(fd, bf, namesz) != (ssize_t)namesz) | ||
434 | break; | ||
435 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | ||
436 | size_t sz = min(descsz, size); | ||
437 | if (read(fd, build_id, sz) == (ssize_t)sz) { | ||
438 | memset(build_id + sz, 0, size - sz); | ||
439 | err = 0; | ||
440 | break; | ||
441 | } | ||
442 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) | ||
443 | break; | ||
444 | } else { | ||
445 | int n = namesz + descsz; | ||
446 | if (read(fd, bf, n) != n) | ||
447 | break; | ||
448 | } | ||
449 | } | ||
450 | close(fd); | ||
451 | out: | ||
452 | return err; | ||
453 | } | ||
454 | |||
455 | int filename__read_debuglink(const char *filename, char *debuglink, | ||
456 | size_t size) | ||
457 | { | ||
458 | int fd, err = -1; | ||
459 | Elf *elf; | ||
460 | GElf_Ehdr ehdr; | ||
461 | GElf_Shdr shdr; | ||
462 | Elf_Data *data; | ||
463 | Elf_Scn *sec; | ||
464 | Elf_Kind ek; | ||
465 | |||
466 | fd = open(filename, O_RDONLY); | ||
467 | if (fd < 0) | ||
468 | goto out; | ||
469 | |||
470 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
471 | if (elf == NULL) { | ||
472 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
473 | goto out_close; | ||
474 | } | ||
475 | |||
476 | ek = elf_kind(elf); | ||
477 | if (ek != ELF_K_ELF) | ||
478 | goto out_close; | ||
479 | |||
480 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
481 | pr_err("%s: cannot get elf header.\n", __func__); | ||
482 | goto out_close; | ||
483 | } | ||
484 | |||
485 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
486 | ".gnu_debuglink", NULL); | ||
487 | if (sec == NULL) | ||
488 | goto out_close; | ||
489 | |||
490 | data = elf_getdata(sec, NULL); | ||
491 | if (data == NULL) | ||
492 | goto out_close; | ||
493 | |||
494 | /* the start of this section is a zero-terminated string */ | ||
495 | strncpy(debuglink, data->d_buf, size); | ||
496 | |||
497 | elf_end(elf); | ||
498 | |||
499 | out_close: | ||
500 | close(fd); | ||
501 | out: | ||
502 | return err; | ||
503 | } | ||
504 | |||
505 | static int dso__swap_init(struct dso *dso, unsigned char eidata) | ||
506 | { | ||
507 | static unsigned int const endian = 1; | ||
508 | |||
509 | dso->needs_swap = DSO_SWAP__NO; | ||
510 | |||
511 | switch (eidata) { | ||
512 | case ELFDATA2LSB: | ||
513 | /* We are big endian, DSO is little endian. */ | ||
514 | if (*(unsigned char const *)&endian != 1) | ||
515 | dso->needs_swap = DSO_SWAP__YES; | ||
516 | break; | ||
517 | |||
518 | case ELFDATA2MSB: | ||
519 | /* We are little endian, DSO is big endian. */ | ||
520 | if (*(unsigned char const *)&endian != 0) | ||
521 | dso->needs_swap = DSO_SWAP__YES; | ||
522 | break; | ||
523 | |||
524 | default: | ||
525 | pr_err("unrecognized DSO data encoding %d\n", eidata); | ||
526 | return -EINVAL; | ||
527 | } | ||
528 | |||
529 | return 0; | ||
530 | } | ||
531 | |||
532 | int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, | ||
533 | symbol_filter_t filter, int kmodule, int want_symtab) | ||
534 | { | ||
535 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; | ||
536 | struct map *curr_map = map; | ||
537 | struct dso *curr_dso = dso; | ||
538 | Elf_Data *symstrs, *secstrs; | ||
539 | uint32_t nr_syms; | ||
540 | int err = -1; | ||
541 | uint32_t idx; | ||
542 | GElf_Ehdr ehdr; | ||
543 | GElf_Shdr shdr, opdshdr; | ||
544 | Elf_Data *syms, *opddata = NULL; | ||
545 | GElf_Sym sym; | ||
546 | Elf_Scn *sec, *sec_strndx, *opdsec; | ||
547 | Elf *elf; | ||
548 | int nr = 0; | ||
549 | size_t opdidx = 0; | ||
550 | |||
551 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
552 | if (elf == NULL) { | ||
553 | pr_debug("%s: cannot read %s ELF file.\n", __func__, name); | ||
554 | goto out_close; | ||
555 | } | ||
556 | |||
557 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
558 | pr_debug("%s: cannot get elf header.\n", __func__); | ||
559 | goto out_elf_end; | ||
560 | } | ||
561 | |||
562 | if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) | ||
563 | goto out_elf_end; | ||
564 | |||
565 | /* Always reject images with a mismatched build-id: */ | ||
566 | if (dso->has_build_id) { | ||
567 | u8 build_id[BUILD_ID_SIZE]; | ||
568 | |||
569 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) | ||
570 | goto out_elf_end; | ||
571 | |||
572 | if (!dso__build_id_equal(dso, build_id)) | ||
573 | goto out_elf_end; | ||
574 | } | ||
575 | |||
576 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | ||
577 | if (sec == NULL) { | ||
578 | if (want_symtab) | ||
579 | goto out_elf_end; | ||
580 | |||
581 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); | ||
582 | if (sec == NULL) | ||
583 | goto out_elf_end; | ||
584 | } | ||
585 | |||
586 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | ||
587 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
588 | opdsec = NULL; | ||
589 | if (opdsec) | ||
590 | opddata = elf_rawdata(opdsec, NULL); | ||
591 | |||
592 | syms = elf_getdata(sec, NULL); | ||
593 | if (syms == NULL) | ||
594 | goto out_elf_end; | ||
595 | |||
596 | sec = elf_getscn(elf, shdr.sh_link); | ||
597 | if (sec == NULL) | ||
598 | goto out_elf_end; | ||
599 | |||
600 | symstrs = elf_getdata(sec, NULL); | ||
601 | if (symstrs == NULL) | ||
602 | goto out_elf_end; | ||
603 | |||
604 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | ||
605 | if (sec_strndx == NULL) | ||
606 | goto out_elf_end; | ||
607 | |||
608 | secstrs = elf_getdata(sec_strndx, NULL); | ||
609 | if (secstrs == NULL) | ||
610 | goto out_elf_end; | ||
611 | |||
612 | nr_syms = shdr.sh_size / shdr.sh_entsize; | ||
613 | |||
614 | memset(&sym, 0, sizeof(sym)); | ||
615 | if (dso->kernel == DSO_TYPE_USER) { | ||
616 | dso->adjust_symbols = (ehdr.e_type == ET_EXEC || | ||
617 | elf_section_by_name(elf, &ehdr, &shdr, | ||
618 | ".gnu.prelink_undo", | ||
619 | NULL) != NULL); | ||
620 | } else { | ||
621 | dso->adjust_symbols = 0; | ||
622 | } | ||
623 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { | ||
624 | struct symbol *f; | ||
625 | const char *elf_name = elf_sym__name(&sym, symstrs); | ||
626 | char *demangled = NULL; | ||
627 | int is_label = elf_sym__is_label(&sym); | ||
628 | const char *section_name; | ||
629 | |||
630 | if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && | ||
631 | strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) | ||
632 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | ||
633 | |||
634 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | ||
635 | continue; | ||
636 | |||
637 | /* Reject ARM ELF "mapping symbols": these aren't unique and | ||
638 | * don't identify functions, so will confuse the profile | ||
639 | * output: */ | ||
640 | if (ehdr.e_machine == EM_ARM) { | ||
641 | if (!strcmp(elf_name, "$a") || | ||
642 | !strcmp(elf_name, "$d") || | ||
643 | !strcmp(elf_name, "$t")) | ||
644 | continue; | ||
645 | } | ||
646 | |||
647 | if (opdsec && sym.st_shndx == opdidx) { | ||
648 | u32 offset = sym.st_value - opdshdr.sh_addr; | ||
649 | u64 *opd = opddata->d_buf + offset; | ||
650 | sym.st_value = DSO__SWAP(dso, u64, *opd); | ||
651 | sym.st_shndx = elf_addr_to_index(elf, sym.st_value); | ||
652 | } | ||
653 | |||
654 | sec = elf_getscn(elf, sym.st_shndx); | ||
655 | if (!sec) | ||
656 | goto out_elf_end; | ||
657 | |||
658 | gelf_getshdr(sec, &shdr); | ||
659 | |||
660 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) | ||
661 | continue; | ||
662 | |||
663 | section_name = elf_sec__name(&shdr, secstrs); | ||
664 | |||
665 | /* On ARM, symbols for thumb functions have 1 added to | ||
666 | * the symbol address as a flag - remove it */ | ||
667 | if ((ehdr.e_machine == EM_ARM) && | ||
668 | (map->type == MAP__FUNCTION) && | ||
669 | (sym.st_value & 1)) | ||
670 | --sym.st_value; | ||
671 | |||
672 | if (dso->kernel != DSO_TYPE_USER || kmodule) { | ||
673 | char dso_name[PATH_MAX]; | ||
674 | |||
675 | if (strcmp(section_name, | ||
676 | (curr_dso->short_name + | ||
677 | dso->short_name_len)) == 0) | ||
678 | goto new_symbol; | ||
679 | |||
680 | if (strcmp(section_name, ".text") == 0) { | ||
681 | curr_map = map; | ||
682 | curr_dso = dso; | ||
683 | goto new_symbol; | ||
684 | } | ||
685 | |||
686 | snprintf(dso_name, sizeof(dso_name), | ||
687 | "%s%s", dso->short_name, section_name); | ||
688 | |||
689 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); | ||
690 | if (curr_map == NULL) { | ||
691 | u64 start = sym.st_value; | ||
692 | |||
693 | if (kmodule) | ||
694 | start += map->start + shdr.sh_offset; | ||
695 | |||
696 | curr_dso = dso__new(dso_name); | ||
697 | if (curr_dso == NULL) | ||
698 | goto out_elf_end; | ||
699 | curr_dso->kernel = dso->kernel; | ||
700 | curr_dso->long_name = dso->long_name; | ||
701 | curr_dso->long_name_len = dso->long_name_len; | ||
702 | curr_map = map__new2(start, curr_dso, | ||
703 | map->type); | ||
704 | if (curr_map == NULL) { | ||
705 | dso__delete(curr_dso); | ||
706 | goto out_elf_end; | ||
707 | } | ||
708 | curr_map->map_ip = identity__map_ip; | ||
709 | curr_map->unmap_ip = identity__map_ip; | ||
710 | curr_dso->symtab_type = dso->symtab_type; | ||
711 | map_groups__insert(kmap->kmaps, curr_map); | ||
712 | dsos__add(&dso->node, curr_dso); | ||
713 | dso__set_loaded(curr_dso, map->type); | ||
714 | } else | ||
715 | curr_dso = curr_map->dso; | ||
716 | |||
717 | goto new_symbol; | ||
718 | } | ||
719 | |||
720 | if (curr_dso->adjust_symbols) { | ||
721 | pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " | ||
722 | "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, | ||
723 | (u64)sym.st_value, (u64)shdr.sh_addr, | ||
724 | (u64)shdr.sh_offset); | ||
725 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | ||
726 | } | ||
727 | /* | ||
728 | * We need to figure out if the object was created from C++ sources | ||
729 | * DWARF DW_compile_unit has this, but we don't always have access | ||
730 | * to it... | ||
731 | */ | ||
732 | demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); | ||
733 | if (demangled != NULL) | ||
734 | elf_name = demangled; | ||
735 | new_symbol: | ||
736 | f = symbol__new(sym.st_value, sym.st_size, | ||
737 | GELF_ST_BIND(sym.st_info), elf_name); | ||
738 | free(demangled); | ||
739 | if (!f) | ||
740 | goto out_elf_end; | ||
741 | |||
742 | if (filter && filter(curr_map, f)) | ||
743 | symbol__delete(f); | ||
744 | else { | ||
745 | symbols__insert(&curr_dso->symbols[curr_map->type], f); | ||
746 | nr++; | ||
747 | } | ||
748 | } | ||
749 | |||
750 | /* | ||
751 | * For misannotated, zeroed, ASM function sizes. | ||
752 | */ | ||
753 | if (nr > 0) { | ||
754 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
755 | symbols__fixup_end(&dso->symbols[map->type]); | ||
756 | if (kmap) { | ||
757 | /* | ||
758 | * We need to fixup this here too because we create new | ||
759 | * maps here, for things like vsyscall sections. | ||
760 | */ | ||
761 | __map_groups__fixup_end(kmap->kmaps, map->type); | ||
762 | } | ||
763 | } | ||
764 | err = nr; | ||
765 | out_elf_end: | ||
766 | elf_end(elf); | ||
767 | out_close: | ||
768 | return err; | ||
769 | } | ||
770 | |||
771 | void symbol__elf_init(void) | ||
772 | { | ||
773 | elf_version(EV_CURRENT); | ||
774 | } | ||
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c index a61fec4518da..f02de8ac842d 100644 --- a/tools/perf/util/symbol.c +++ b/tools/perf/util/symbol.c | |||
@@ -15,8 +15,6 @@ | |||
15 | #include "symbol.h" | 15 | #include "symbol.h" |
16 | #include "strlist.h" | 16 | #include "strlist.h" |
17 | 17 | ||
18 | #include <libelf.h> | ||
19 | #include <gelf.h> | ||
20 | #include <elf.h> | 18 | #include <elf.h> |
21 | #include <limits.h> | 19 | #include <limits.h> |
22 | #include <sys/utsname.h> | 20 | #include <sys/utsname.h> |
@@ -25,15 +23,7 @@ | |||
25 | #define KSYM_NAME_LEN 256 | 23 | #define KSYM_NAME_LEN 256 |
26 | #endif | 24 | #endif |
27 | 25 | ||
28 | #ifndef NT_GNU_BUILD_ID | ||
29 | #define NT_GNU_BUILD_ID 3 | ||
30 | #endif | ||
31 | |||
32 | static void dso_cache__free(struct rb_root *root); | 26 | static void dso_cache__free(struct rb_root *root); |
33 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | ||
34 | static int elf_read_build_id(Elf *elf, void *bf, size_t size); | ||
35 | static void dsos__add(struct list_head *head, struct dso *dso); | ||
36 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type); | ||
37 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, | 27 | static int dso__load_kernel_sym(struct dso *dso, struct map *map, |
38 | symbol_filter_t filter); | 28 | symbol_filter_t filter); |
39 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, | 29 | static int dso__load_guest_kernel_sym(struct dso *dso, struct map *map, |
@@ -170,7 +160,7 @@ static int choose_best_symbol(struct symbol *syma, struct symbol *symb) | |||
170 | return SYMBOL_B; | 160 | return SYMBOL_B; |
171 | } | 161 | } |
172 | 162 | ||
173 | static void symbols__fixup_duplicate(struct rb_root *symbols) | 163 | void symbols__fixup_duplicate(struct rb_root *symbols) |
174 | { | 164 | { |
175 | struct rb_node *nd; | 165 | struct rb_node *nd; |
176 | struct symbol *curr, *next; | 166 | struct symbol *curr, *next; |
@@ -199,7 +189,7 @@ again: | |||
199 | } | 189 | } |
200 | } | 190 | } |
201 | 191 | ||
202 | static void symbols__fixup_end(struct rb_root *symbols) | 192 | void symbols__fixup_end(struct rb_root *symbols) |
203 | { | 193 | { |
204 | struct rb_node *nd, *prevnd = rb_first(symbols); | 194 | struct rb_node *nd, *prevnd = rb_first(symbols); |
205 | struct symbol *curr, *prev; | 195 | struct symbol *curr, *prev; |
@@ -222,7 +212,7 @@ static void symbols__fixup_end(struct rb_root *symbols) | |||
222 | curr->end = roundup(curr->start, 4096); | 212 | curr->end = roundup(curr->start, 4096); |
223 | } | 213 | } |
224 | 214 | ||
225 | static void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) | 215 | void __map_groups__fixup_end(struct map_groups *mg, enum map_type type) |
226 | { | 216 | { |
227 | struct map *prev, *curr; | 217 | struct map *prev, *curr; |
228 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); | 218 | struct rb_node *nd, *prevnd = rb_first(&mg->maps[type]); |
@@ -252,8 +242,7 @@ static void map_groups__fixup_end(struct map_groups *mg) | |||
252 | __map_groups__fixup_end(mg, i); | 242 | __map_groups__fixup_end(mg, i); |
253 | } | 243 | } |
254 | 244 | ||
255 | static struct symbol *symbol__new(u64 start, u64 len, u8 binding, | 245 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name) |
256 | const char *name) | ||
257 | { | 246 | { |
258 | size_t namelen = strlen(name) + 1; | 247 | size_t namelen = strlen(name) + 1; |
259 | struct symbol *sym = calloc(1, (symbol_conf.priv_size + | 248 | struct symbol *sym = calloc(1, (symbol_conf.priv_size + |
@@ -390,7 +379,7 @@ void dso__set_build_id(struct dso *dso, void *build_id) | |||
390 | dso->has_build_id = 1; | 379 | dso->has_build_id = 1; |
391 | } | 380 | } |
392 | 381 | ||
393 | static void symbols__insert(struct rb_root *symbols, struct symbol *sym) | 382 | void symbols__insert(struct rb_root *symbols, struct symbol *sym) |
394 | { | 383 | { |
395 | struct rb_node **p = &symbols->rb_node; | 384 | struct rb_node **p = &symbols->rb_node; |
396 | struct rb_node *parent = NULL; | 385 | struct rb_node *parent = NULL; |
@@ -904,561 +893,7 @@ out_failure: | |||
904 | return -1; | 893 | return -1; |
905 | } | 894 | } |
906 | 895 | ||
907 | /** | 896 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id) |
908 | * elf_symtab__for_each_symbol - iterate thru all the symbols | ||
909 | * | ||
910 | * @syms: struct elf_symtab instance to iterate | ||
911 | * @idx: uint32_t idx | ||
912 | * @sym: GElf_Sym iterator | ||
913 | */ | ||
914 | #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \ | ||
915 | for (idx = 0, gelf_getsym(syms, idx, &sym);\ | ||
916 | idx < nr_syms; \ | ||
917 | idx++, gelf_getsym(syms, idx, &sym)) | ||
918 | |||
919 | static inline uint8_t elf_sym__type(const GElf_Sym *sym) | ||
920 | { | ||
921 | return GELF_ST_TYPE(sym->st_info); | ||
922 | } | ||
923 | |||
924 | static inline int elf_sym__is_function(const GElf_Sym *sym) | ||
925 | { | ||
926 | return elf_sym__type(sym) == STT_FUNC && | ||
927 | sym->st_name != 0 && | ||
928 | sym->st_shndx != SHN_UNDEF; | ||
929 | } | ||
930 | |||
931 | static inline bool elf_sym__is_object(const GElf_Sym *sym) | ||
932 | { | ||
933 | return elf_sym__type(sym) == STT_OBJECT && | ||
934 | sym->st_name != 0 && | ||
935 | sym->st_shndx != SHN_UNDEF; | ||
936 | } | ||
937 | |||
938 | static inline int elf_sym__is_label(const GElf_Sym *sym) | ||
939 | { | ||
940 | return elf_sym__type(sym) == STT_NOTYPE && | ||
941 | sym->st_name != 0 && | ||
942 | sym->st_shndx != SHN_UNDEF && | ||
943 | sym->st_shndx != SHN_ABS; | ||
944 | } | ||
945 | |||
946 | static inline const char *elf_sec__name(const GElf_Shdr *shdr, | ||
947 | const Elf_Data *secstrs) | ||
948 | { | ||
949 | return secstrs->d_buf + shdr->sh_name; | ||
950 | } | ||
951 | |||
952 | static inline int elf_sec__is_text(const GElf_Shdr *shdr, | ||
953 | const Elf_Data *secstrs) | ||
954 | { | ||
955 | return strstr(elf_sec__name(shdr, secstrs), "text") != NULL; | ||
956 | } | ||
957 | |||
958 | static inline bool elf_sec__is_data(const GElf_Shdr *shdr, | ||
959 | const Elf_Data *secstrs) | ||
960 | { | ||
961 | return strstr(elf_sec__name(shdr, secstrs), "data") != NULL; | ||
962 | } | ||
963 | |||
964 | static inline const char *elf_sym__name(const GElf_Sym *sym, | ||
965 | const Elf_Data *symstrs) | ||
966 | { | ||
967 | return symstrs->d_buf + sym->st_name; | ||
968 | } | ||
969 | |||
970 | static Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep, | ||
971 | GElf_Shdr *shp, const char *name, | ||
972 | size_t *idx) | ||
973 | { | ||
974 | Elf_Scn *sec = NULL; | ||
975 | size_t cnt = 1; | ||
976 | |||
977 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
978 | char *str; | ||
979 | |||
980 | gelf_getshdr(sec, shp); | ||
981 | str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name); | ||
982 | if (!strcmp(name, str)) { | ||
983 | if (idx) | ||
984 | *idx = cnt; | ||
985 | break; | ||
986 | } | ||
987 | ++cnt; | ||
988 | } | ||
989 | |||
990 | return sec; | ||
991 | } | ||
992 | |||
993 | #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \ | ||
994 | for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \ | ||
995 | idx < nr_entries; \ | ||
996 | ++idx, pos = gelf_getrel(reldata, idx, &pos_mem)) | ||
997 | |||
998 | #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \ | ||
999 | for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \ | ||
1000 | idx < nr_entries; \ | ||
1001 | ++idx, pos = gelf_getrela(reldata, idx, &pos_mem)) | ||
1002 | |||
1003 | /* | ||
1004 | * We need to check if we have a .dynsym, so that we can handle the | ||
1005 | * .plt, synthesizing its symbols, that aren't on the symtabs (be it | ||
1006 | * .dynsym or .symtab). | ||
1007 | * And always look at the original dso, not at debuginfo packages, that | ||
1008 | * have the PLT data stripped out (shdr_rel_plt.sh_type == SHT_NOBITS). | ||
1009 | */ | ||
1010 | static int | ||
1011 | dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, | ||
1012 | symbol_filter_t filter) | ||
1013 | { | ||
1014 | uint32_t nr_rel_entries, idx; | ||
1015 | GElf_Sym sym; | ||
1016 | u64 plt_offset; | ||
1017 | GElf_Shdr shdr_plt; | ||
1018 | struct symbol *f; | ||
1019 | GElf_Shdr shdr_rel_plt, shdr_dynsym; | ||
1020 | Elf_Data *reldata, *syms, *symstrs; | ||
1021 | Elf_Scn *scn_plt_rel, *scn_symstrs, *scn_dynsym; | ||
1022 | size_t dynsym_idx; | ||
1023 | GElf_Ehdr ehdr; | ||
1024 | char sympltname[1024]; | ||
1025 | Elf *elf; | ||
1026 | int nr = 0, symidx, fd, err = 0; | ||
1027 | |||
1028 | fd = open(name, O_RDONLY); | ||
1029 | if (fd < 0) | ||
1030 | goto out; | ||
1031 | |||
1032 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1033 | if (elf == NULL) | ||
1034 | goto out_close; | ||
1035 | |||
1036 | if (gelf_getehdr(elf, &ehdr) == NULL) | ||
1037 | goto out_elf_end; | ||
1038 | |||
1039 | scn_dynsym = elf_section_by_name(elf, &ehdr, &shdr_dynsym, | ||
1040 | ".dynsym", &dynsym_idx); | ||
1041 | if (scn_dynsym == NULL) | ||
1042 | goto out_elf_end; | ||
1043 | |||
1044 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
1045 | ".rela.plt", NULL); | ||
1046 | if (scn_plt_rel == NULL) { | ||
1047 | scn_plt_rel = elf_section_by_name(elf, &ehdr, &shdr_rel_plt, | ||
1048 | ".rel.plt", NULL); | ||
1049 | if (scn_plt_rel == NULL) | ||
1050 | goto out_elf_end; | ||
1051 | } | ||
1052 | |||
1053 | err = -1; | ||
1054 | |||
1055 | if (shdr_rel_plt.sh_link != dynsym_idx) | ||
1056 | goto out_elf_end; | ||
1057 | |||
1058 | if (elf_section_by_name(elf, &ehdr, &shdr_plt, ".plt", NULL) == NULL) | ||
1059 | goto out_elf_end; | ||
1060 | |||
1061 | /* | ||
1062 | * Fetch the relocation section to find the idxes to the GOT | ||
1063 | * and the symbols in the .dynsym they refer to. | ||
1064 | */ | ||
1065 | reldata = elf_getdata(scn_plt_rel, NULL); | ||
1066 | if (reldata == NULL) | ||
1067 | goto out_elf_end; | ||
1068 | |||
1069 | syms = elf_getdata(scn_dynsym, NULL); | ||
1070 | if (syms == NULL) | ||
1071 | goto out_elf_end; | ||
1072 | |||
1073 | scn_symstrs = elf_getscn(elf, shdr_dynsym.sh_link); | ||
1074 | if (scn_symstrs == NULL) | ||
1075 | goto out_elf_end; | ||
1076 | |||
1077 | symstrs = elf_getdata(scn_symstrs, NULL); | ||
1078 | if (symstrs == NULL) | ||
1079 | goto out_elf_end; | ||
1080 | |||
1081 | nr_rel_entries = shdr_rel_plt.sh_size / shdr_rel_plt.sh_entsize; | ||
1082 | plt_offset = shdr_plt.sh_offset; | ||
1083 | |||
1084 | if (shdr_rel_plt.sh_type == SHT_RELA) { | ||
1085 | GElf_Rela pos_mem, *pos; | ||
1086 | |||
1087 | elf_section__for_each_rela(reldata, pos, pos_mem, idx, | ||
1088 | nr_rel_entries) { | ||
1089 | symidx = GELF_R_SYM(pos->r_info); | ||
1090 | plt_offset += shdr_plt.sh_entsize; | ||
1091 | gelf_getsym(syms, symidx, &sym); | ||
1092 | snprintf(sympltname, sizeof(sympltname), | ||
1093 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
1094 | |||
1095 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
1096 | STB_GLOBAL, sympltname); | ||
1097 | if (!f) | ||
1098 | goto out_elf_end; | ||
1099 | |||
1100 | if (filter && filter(map, f)) | ||
1101 | symbol__delete(f); | ||
1102 | else { | ||
1103 | symbols__insert(&dso->symbols[map->type], f); | ||
1104 | ++nr; | ||
1105 | } | ||
1106 | } | ||
1107 | } else if (shdr_rel_plt.sh_type == SHT_REL) { | ||
1108 | GElf_Rel pos_mem, *pos; | ||
1109 | elf_section__for_each_rel(reldata, pos, pos_mem, idx, | ||
1110 | nr_rel_entries) { | ||
1111 | symidx = GELF_R_SYM(pos->r_info); | ||
1112 | plt_offset += shdr_plt.sh_entsize; | ||
1113 | gelf_getsym(syms, symidx, &sym); | ||
1114 | snprintf(sympltname, sizeof(sympltname), | ||
1115 | "%s@plt", elf_sym__name(&sym, symstrs)); | ||
1116 | |||
1117 | f = symbol__new(plt_offset, shdr_plt.sh_entsize, | ||
1118 | STB_GLOBAL, sympltname); | ||
1119 | if (!f) | ||
1120 | goto out_elf_end; | ||
1121 | |||
1122 | if (filter && filter(map, f)) | ||
1123 | symbol__delete(f); | ||
1124 | else { | ||
1125 | symbols__insert(&dso->symbols[map->type], f); | ||
1126 | ++nr; | ||
1127 | } | ||
1128 | } | ||
1129 | } | ||
1130 | |||
1131 | err = 0; | ||
1132 | out_elf_end: | ||
1133 | elf_end(elf); | ||
1134 | out_close: | ||
1135 | close(fd); | ||
1136 | |||
1137 | if (err == 0) | ||
1138 | return nr; | ||
1139 | out: | ||
1140 | pr_debug("%s: problems reading %s PLT info.\n", | ||
1141 | __func__, dso->long_name); | ||
1142 | return 0; | ||
1143 | } | ||
1144 | |||
1145 | static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type) | ||
1146 | { | ||
1147 | switch (type) { | ||
1148 | case MAP__FUNCTION: | ||
1149 | return elf_sym__is_function(sym); | ||
1150 | case MAP__VARIABLE: | ||
1151 | return elf_sym__is_object(sym); | ||
1152 | default: | ||
1153 | return false; | ||
1154 | } | ||
1155 | } | ||
1156 | |||
1157 | static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs, | ||
1158 | enum map_type type) | ||
1159 | { | ||
1160 | switch (type) { | ||
1161 | case MAP__FUNCTION: | ||
1162 | return elf_sec__is_text(shdr, secstrs); | ||
1163 | case MAP__VARIABLE: | ||
1164 | return elf_sec__is_data(shdr, secstrs); | ||
1165 | default: | ||
1166 | return false; | ||
1167 | } | ||
1168 | } | ||
1169 | |||
1170 | static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr) | ||
1171 | { | ||
1172 | Elf_Scn *sec = NULL; | ||
1173 | GElf_Shdr shdr; | ||
1174 | size_t cnt = 1; | ||
1175 | |||
1176 | while ((sec = elf_nextscn(elf, sec)) != NULL) { | ||
1177 | gelf_getshdr(sec, &shdr); | ||
1178 | |||
1179 | if ((addr >= shdr.sh_addr) && | ||
1180 | (addr < (shdr.sh_addr + shdr.sh_size))) | ||
1181 | return cnt; | ||
1182 | |||
1183 | ++cnt; | ||
1184 | } | ||
1185 | |||
1186 | return -1; | ||
1187 | } | ||
1188 | |||
1189 | static int dso__swap_init(struct dso *dso, unsigned char eidata) | ||
1190 | { | ||
1191 | static unsigned int const endian = 1; | ||
1192 | |||
1193 | dso->needs_swap = DSO_SWAP__NO; | ||
1194 | |||
1195 | switch (eidata) { | ||
1196 | case ELFDATA2LSB: | ||
1197 | /* We are big endian, DSO is little endian. */ | ||
1198 | if (*(unsigned char const *)&endian != 1) | ||
1199 | dso->needs_swap = DSO_SWAP__YES; | ||
1200 | break; | ||
1201 | |||
1202 | case ELFDATA2MSB: | ||
1203 | /* We are little endian, DSO is big endian. */ | ||
1204 | if (*(unsigned char const *)&endian != 0) | ||
1205 | dso->needs_swap = DSO_SWAP__YES; | ||
1206 | break; | ||
1207 | |||
1208 | default: | ||
1209 | pr_err("unrecognized DSO data encoding %d\n", eidata); | ||
1210 | return -EINVAL; | ||
1211 | } | ||
1212 | |||
1213 | return 0; | ||
1214 | } | ||
1215 | |||
1216 | static int dso__load_sym(struct dso *dso, struct map *map, const char *name, | ||
1217 | int fd, symbol_filter_t filter, int kmodule, | ||
1218 | int want_symtab) | ||
1219 | { | ||
1220 | struct kmap *kmap = dso->kernel ? map__kmap(map) : NULL; | ||
1221 | struct map *curr_map = map; | ||
1222 | struct dso *curr_dso = dso; | ||
1223 | Elf_Data *symstrs, *secstrs; | ||
1224 | uint32_t nr_syms; | ||
1225 | int err = -1; | ||
1226 | uint32_t idx; | ||
1227 | GElf_Ehdr ehdr; | ||
1228 | GElf_Shdr shdr, opdshdr; | ||
1229 | Elf_Data *syms, *opddata = NULL; | ||
1230 | GElf_Sym sym; | ||
1231 | Elf_Scn *sec, *sec_strndx, *opdsec; | ||
1232 | Elf *elf; | ||
1233 | int nr = 0; | ||
1234 | size_t opdidx = 0; | ||
1235 | |||
1236 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1237 | if (elf == NULL) { | ||
1238 | pr_debug("%s: cannot read %s ELF file.\n", __func__, name); | ||
1239 | goto out_close; | ||
1240 | } | ||
1241 | |||
1242 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1243 | pr_debug("%s: cannot get elf header.\n", __func__); | ||
1244 | goto out_elf_end; | ||
1245 | } | ||
1246 | |||
1247 | if (dso__swap_init(dso, ehdr.e_ident[EI_DATA])) | ||
1248 | goto out_elf_end; | ||
1249 | |||
1250 | /* Always reject images with a mismatched build-id: */ | ||
1251 | if (dso->has_build_id) { | ||
1252 | u8 build_id[BUILD_ID_SIZE]; | ||
1253 | |||
1254 | if (elf_read_build_id(elf, build_id, BUILD_ID_SIZE) < 0) | ||
1255 | goto out_elf_end; | ||
1256 | |||
1257 | if (!dso__build_id_equal(dso, build_id)) | ||
1258 | goto out_elf_end; | ||
1259 | } | ||
1260 | |||
1261 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".symtab", NULL); | ||
1262 | if (sec == NULL) { | ||
1263 | if (want_symtab) | ||
1264 | goto out_elf_end; | ||
1265 | |||
1266 | sec = elf_section_by_name(elf, &ehdr, &shdr, ".dynsym", NULL); | ||
1267 | if (sec == NULL) | ||
1268 | goto out_elf_end; | ||
1269 | } | ||
1270 | |||
1271 | opdsec = elf_section_by_name(elf, &ehdr, &opdshdr, ".opd", &opdidx); | ||
1272 | if (opdshdr.sh_type != SHT_PROGBITS) | ||
1273 | opdsec = NULL; | ||
1274 | if (opdsec) | ||
1275 | opddata = elf_rawdata(opdsec, NULL); | ||
1276 | |||
1277 | syms = elf_getdata(sec, NULL); | ||
1278 | if (syms == NULL) | ||
1279 | goto out_elf_end; | ||
1280 | |||
1281 | sec = elf_getscn(elf, shdr.sh_link); | ||
1282 | if (sec == NULL) | ||
1283 | goto out_elf_end; | ||
1284 | |||
1285 | symstrs = elf_getdata(sec, NULL); | ||
1286 | if (symstrs == NULL) | ||
1287 | goto out_elf_end; | ||
1288 | |||
1289 | sec_strndx = elf_getscn(elf, ehdr.e_shstrndx); | ||
1290 | if (sec_strndx == NULL) | ||
1291 | goto out_elf_end; | ||
1292 | |||
1293 | secstrs = elf_getdata(sec_strndx, NULL); | ||
1294 | if (secstrs == NULL) | ||
1295 | goto out_elf_end; | ||
1296 | |||
1297 | nr_syms = shdr.sh_size / shdr.sh_entsize; | ||
1298 | |||
1299 | memset(&sym, 0, sizeof(sym)); | ||
1300 | if (dso->kernel == DSO_TYPE_USER) { | ||
1301 | dso->adjust_symbols = (ehdr.e_type == ET_EXEC || | ||
1302 | elf_section_by_name(elf, &ehdr, &shdr, | ||
1303 | ".gnu.prelink_undo", | ||
1304 | NULL) != NULL); | ||
1305 | } else { | ||
1306 | dso->adjust_symbols = 0; | ||
1307 | } | ||
1308 | elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) { | ||
1309 | struct symbol *f; | ||
1310 | const char *elf_name = elf_sym__name(&sym, symstrs); | ||
1311 | char *demangled = NULL; | ||
1312 | int is_label = elf_sym__is_label(&sym); | ||
1313 | const char *section_name; | ||
1314 | |||
1315 | if (kmap && kmap->ref_reloc_sym && kmap->ref_reloc_sym->name && | ||
1316 | strcmp(elf_name, kmap->ref_reloc_sym->name) == 0) | ||
1317 | kmap->ref_reloc_sym->unrelocated_addr = sym.st_value; | ||
1318 | |||
1319 | if (!is_label && !elf_sym__is_a(&sym, map->type)) | ||
1320 | continue; | ||
1321 | |||
1322 | /* Reject ARM ELF "mapping symbols": these aren't unique and | ||
1323 | * don't identify functions, so will confuse the profile | ||
1324 | * output: */ | ||
1325 | if (ehdr.e_machine == EM_ARM) { | ||
1326 | if (!strcmp(elf_name, "$a") || | ||
1327 | !strcmp(elf_name, "$d") || | ||
1328 | !strcmp(elf_name, "$t")) | ||
1329 | continue; | ||
1330 | } | ||
1331 | |||
1332 | if (opdsec && sym.st_shndx == opdidx) { | ||
1333 | u32 offset = sym.st_value - opdshdr.sh_addr; | ||
1334 | u64 *opd = opddata->d_buf + offset; | ||
1335 | sym.st_value = DSO__SWAP(dso, u64, *opd); | ||
1336 | sym.st_shndx = elf_addr_to_index(elf, sym.st_value); | ||
1337 | } | ||
1338 | |||
1339 | sec = elf_getscn(elf, sym.st_shndx); | ||
1340 | if (!sec) | ||
1341 | goto out_elf_end; | ||
1342 | |||
1343 | gelf_getshdr(sec, &shdr); | ||
1344 | |||
1345 | if (is_label && !elf_sec__is_a(&shdr, secstrs, map->type)) | ||
1346 | continue; | ||
1347 | |||
1348 | section_name = elf_sec__name(&shdr, secstrs); | ||
1349 | |||
1350 | /* On ARM, symbols for thumb functions have 1 added to | ||
1351 | * the symbol address as a flag - remove it */ | ||
1352 | if ((ehdr.e_machine == EM_ARM) && | ||
1353 | (map->type == MAP__FUNCTION) && | ||
1354 | (sym.st_value & 1)) | ||
1355 | --sym.st_value; | ||
1356 | |||
1357 | if (dso->kernel != DSO_TYPE_USER || kmodule) { | ||
1358 | char dso_name[PATH_MAX]; | ||
1359 | |||
1360 | if (strcmp(section_name, | ||
1361 | (curr_dso->short_name + | ||
1362 | dso->short_name_len)) == 0) | ||
1363 | goto new_symbol; | ||
1364 | |||
1365 | if (strcmp(section_name, ".text") == 0) { | ||
1366 | curr_map = map; | ||
1367 | curr_dso = dso; | ||
1368 | goto new_symbol; | ||
1369 | } | ||
1370 | |||
1371 | snprintf(dso_name, sizeof(dso_name), | ||
1372 | "%s%s", dso->short_name, section_name); | ||
1373 | |||
1374 | curr_map = map_groups__find_by_name(kmap->kmaps, map->type, dso_name); | ||
1375 | if (curr_map == NULL) { | ||
1376 | u64 start = sym.st_value; | ||
1377 | |||
1378 | if (kmodule) | ||
1379 | start += map->start + shdr.sh_offset; | ||
1380 | |||
1381 | curr_dso = dso__new(dso_name); | ||
1382 | if (curr_dso == NULL) | ||
1383 | goto out_elf_end; | ||
1384 | curr_dso->kernel = dso->kernel; | ||
1385 | curr_dso->long_name = dso->long_name; | ||
1386 | curr_dso->long_name_len = dso->long_name_len; | ||
1387 | curr_map = map__new2(start, curr_dso, | ||
1388 | map->type); | ||
1389 | if (curr_map == NULL) { | ||
1390 | dso__delete(curr_dso); | ||
1391 | goto out_elf_end; | ||
1392 | } | ||
1393 | curr_map->map_ip = identity__map_ip; | ||
1394 | curr_map->unmap_ip = identity__map_ip; | ||
1395 | curr_dso->symtab_type = dso->symtab_type; | ||
1396 | map_groups__insert(kmap->kmaps, curr_map); | ||
1397 | dsos__add(&dso->node, curr_dso); | ||
1398 | dso__set_loaded(curr_dso, map->type); | ||
1399 | } else | ||
1400 | curr_dso = curr_map->dso; | ||
1401 | |||
1402 | goto new_symbol; | ||
1403 | } | ||
1404 | |||
1405 | if (curr_dso->adjust_symbols) { | ||
1406 | pr_debug4("%s: adjusting symbol: st_value: %#" PRIx64 " " | ||
1407 | "sh_addr: %#" PRIx64 " sh_offset: %#" PRIx64 "\n", __func__, | ||
1408 | (u64)sym.st_value, (u64)shdr.sh_addr, | ||
1409 | (u64)shdr.sh_offset); | ||
1410 | sym.st_value -= shdr.sh_addr - shdr.sh_offset; | ||
1411 | } | ||
1412 | /* | ||
1413 | * We need to figure out if the object was created from C++ sources | ||
1414 | * DWARF DW_compile_unit has this, but we don't always have access | ||
1415 | * to it... | ||
1416 | */ | ||
1417 | demangled = bfd_demangle(NULL, elf_name, DMGL_PARAMS | DMGL_ANSI); | ||
1418 | if (demangled != NULL) | ||
1419 | elf_name = demangled; | ||
1420 | new_symbol: | ||
1421 | f = symbol__new(sym.st_value, sym.st_size, | ||
1422 | GELF_ST_BIND(sym.st_info), elf_name); | ||
1423 | free(demangled); | ||
1424 | if (!f) | ||
1425 | goto out_elf_end; | ||
1426 | |||
1427 | if (filter && filter(curr_map, f)) | ||
1428 | symbol__delete(f); | ||
1429 | else { | ||
1430 | symbols__insert(&curr_dso->symbols[curr_map->type], f); | ||
1431 | nr++; | ||
1432 | } | ||
1433 | } | ||
1434 | |||
1435 | /* | ||
1436 | * For misannotated, zeroed, ASM function sizes. | ||
1437 | */ | ||
1438 | if (nr > 0) { | ||
1439 | symbols__fixup_duplicate(&dso->symbols[map->type]); | ||
1440 | symbols__fixup_end(&dso->symbols[map->type]); | ||
1441 | if (kmap) { | ||
1442 | /* | ||
1443 | * We need to fixup this here too because we create new | ||
1444 | * maps here, for things like vsyscall sections. | ||
1445 | */ | ||
1446 | __map_groups__fixup_end(kmap->kmaps, map->type); | ||
1447 | } | ||
1448 | } | ||
1449 | err = nr; | ||
1450 | out_elf_end: | ||
1451 | elf_end(elf); | ||
1452 | out_close: | ||
1453 | return err; | ||
1454 | } | ||
1455 | |||
1456 | void symbol__elf_init(void) | ||
1457 | { | ||
1458 | elf_version(EV_CURRENT); | ||
1459 | } | ||
1460 | |||
1461 | static bool dso__build_id_equal(const struct dso *dso, u8 *build_id) | ||
1462 | { | 897 | { |
1463 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; | 898 | return memcmp(dso->build_id, build_id, sizeof(dso->build_id)) == 0; |
1464 | } | 899 | } |
@@ -1485,212 +920,6 @@ bool __dsos__read_build_ids(struct list_head *head, bool with_hits) | |||
1485 | return have_build_id; | 920 | return have_build_id; |
1486 | } | 921 | } |
1487 | 922 | ||
1488 | /* | ||
1489 | * Align offset to 4 bytes as needed for note name and descriptor data. | ||
1490 | */ | ||
1491 | #define NOTE_ALIGN(n) (((n) + 3) & -4U) | ||
1492 | |||
1493 | static int elf_read_build_id(Elf *elf, void *bf, size_t size) | ||
1494 | { | ||
1495 | int err = -1; | ||
1496 | GElf_Ehdr ehdr; | ||
1497 | GElf_Shdr shdr; | ||
1498 | Elf_Data *data; | ||
1499 | Elf_Scn *sec; | ||
1500 | Elf_Kind ek; | ||
1501 | void *ptr; | ||
1502 | |||
1503 | if (size < BUILD_ID_SIZE) | ||
1504 | goto out; | ||
1505 | |||
1506 | ek = elf_kind(elf); | ||
1507 | if (ek != ELF_K_ELF) | ||
1508 | goto out; | ||
1509 | |||
1510 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1511 | pr_err("%s: cannot get elf header.\n", __func__); | ||
1512 | goto out; | ||
1513 | } | ||
1514 | |||
1515 | /* | ||
1516 | * Check following sections for notes: | ||
1517 | * '.note.gnu.build-id' | ||
1518 | * '.notes' | ||
1519 | * '.note' (VDSO specific) | ||
1520 | */ | ||
1521 | do { | ||
1522 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1523 | ".note.gnu.build-id", NULL); | ||
1524 | if (sec) | ||
1525 | break; | ||
1526 | |||
1527 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1528 | ".notes", NULL); | ||
1529 | if (sec) | ||
1530 | break; | ||
1531 | |||
1532 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1533 | ".note", NULL); | ||
1534 | if (sec) | ||
1535 | break; | ||
1536 | |||
1537 | return err; | ||
1538 | |||
1539 | } while (0); | ||
1540 | |||
1541 | data = elf_getdata(sec, NULL); | ||
1542 | if (data == NULL) | ||
1543 | goto out; | ||
1544 | |||
1545 | ptr = data->d_buf; | ||
1546 | while (ptr < (data->d_buf + data->d_size)) { | ||
1547 | GElf_Nhdr *nhdr = ptr; | ||
1548 | size_t namesz = NOTE_ALIGN(nhdr->n_namesz), | ||
1549 | descsz = NOTE_ALIGN(nhdr->n_descsz); | ||
1550 | const char *name; | ||
1551 | |||
1552 | ptr += sizeof(*nhdr); | ||
1553 | name = ptr; | ||
1554 | ptr += namesz; | ||
1555 | if (nhdr->n_type == NT_GNU_BUILD_ID && | ||
1556 | nhdr->n_namesz == sizeof("GNU")) { | ||
1557 | if (memcmp(name, "GNU", sizeof("GNU")) == 0) { | ||
1558 | size_t sz = min(size, descsz); | ||
1559 | memcpy(bf, ptr, sz); | ||
1560 | memset(bf + sz, 0, size - sz); | ||
1561 | err = descsz; | ||
1562 | break; | ||
1563 | } | ||
1564 | } | ||
1565 | ptr += descsz; | ||
1566 | } | ||
1567 | |||
1568 | out: | ||
1569 | return err; | ||
1570 | } | ||
1571 | |||
1572 | int filename__read_build_id(const char *filename, void *bf, size_t size) | ||
1573 | { | ||
1574 | int fd, err = -1; | ||
1575 | Elf *elf; | ||
1576 | |||
1577 | if (size < BUILD_ID_SIZE) | ||
1578 | goto out; | ||
1579 | |||
1580 | fd = open(filename, O_RDONLY); | ||
1581 | if (fd < 0) | ||
1582 | goto out; | ||
1583 | |||
1584 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1585 | if (elf == NULL) { | ||
1586 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1587 | goto out_close; | ||
1588 | } | ||
1589 | |||
1590 | err = elf_read_build_id(elf, bf, size); | ||
1591 | |||
1592 | elf_end(elf); | ||
1593 | out_close: | ||
1594 | close(fd); | ||
1595 | out: | ||
1596 | return err; | ||
1597 | } | ||
1598 | |||
1599 | int sysfs__read_build_id(const char *filename, void *build_id, size_t size) | ||
1600 | { | ||
1601 | int fd, err = -1; | ||
1602 | |||
1603 | if (size < BUILD_ID_SIZE) | ||
1604 | goto out; | ||
1605 | |||
1606 | fd = open(filename, O_RDONLY); | ||
1607 | if (fd < 0) | ||
1608 | goto out; | ||
1609 | |||
1610 | while (1) { | ||
1611 | char bf[BUFSIZ]; | ||
1612 | GElf_Nhdr nhdr; | ||
1613 | size_t namesz, descsz; | ||
1614 | |||
1615 | if (read(fd, &nhdr, sizeof(nhdr)) != sizeof(nhdr)) | ||
1616 | break; | ||
1617 | |||
1618 | namesz = NOTE_ALIGN(nhdr.n_namesz); | ||
1619 | descsz = NOTE_ALIGN(nhdr.n_descsz); | ||
1620 | if (nhdr.n_type == NT_GNU_BUILD_ID && | ||
1621 | nhdr.n_namesz == sizeof("GNU")) { | ||
1622 | if (read(fd, bf, namesz) != (ssize_t)namesz) | ||
1623 | break; | ||
1624 | if (memcmp(bf, "GNU", sizeof("GNU")) == 0) { | ||
1625 | size_t sz = min(descsz, size); | ||
1626 | if (read(fd, build_id, sz) == (ssize_t)sz) { | ||
1627 | memset(build_id + sz, 0, size - sz); | ||
1628 | err = 0; | ||
1629 | break; | ||
1630 | } | ||
1631 | } else if (read(fd, bf, descsz) != (ssize_t)descsz) | ||
1632 | break; | ||
1633 | } else { | ||
1634 | int n = namesz + descsz; | ||
1635 | if (read(fd, bf, n) != n) | ||
1636 | break; | ||
1637 | } | ||
1638 | } | ||
1639 | close(fd); | ||
1640 | out: | ||
1641 | return err; | ||
1642 | } | ||
1643 | |||
1644 | static int filename__read_debuglink(const char *filename, | ||
1645 | char *debuglink, size_t size) | ||
1646 | { | ||
1647 | int fd, err = -1; | ||
1648 | Elf *elf; | ||
1649 | GElf_Ehdr ehdr; | ||
1650 | GElf_Shdr shdr; | ||
1651 | Elf_Data *data; | ||
1652 | Elf_Scn *sec; | ||
1653 | Elf_Kind ek; | ||
1654 | |||
1655 | fd = open(filename, O_RDONLY); | ||
1656 | if (fd < 0) | ||
1657 | goto out; | ||
1658 | |||
1659 | elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL); | ||
1660 | if (elf == NULL) { | ||
1661 | pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename); | ||
1662 | goto out_close; | ||
1663 | } | ||
1664 | |||
1665 | ek = elf_kind(elf); | ||
1666 | if (ek != ELF_K_ELF) | ||
1667 | goto out_close; | ||
1668 | |||
1669 | if (gelf_getehdr(elf, &ehdr) == NULL) { | ||
1670 | pr_err("%s: cannot get elf header.\n", __func__); | ||
1671 | goto out_close; | ||
1672 | } | ||
1673 | |||
1674 | sec = elf_section_by_name(elf, &ehdr, &shdr, | ||
1675 | ".gnu_debuglink", NULL); | ||
1676 | if (sec == NULL) | ||
1677 | goto out_close; | ||
1678 | |||
1679 | data = elf_getdata(sec, NULL); | ||
1680 | if (data == NULL) | ||
1681 | goto out_close; | ||
1682 | |||
1683 | /* the start of this section is a zero-terminated string */ | ||
1684 | strncpy(debuglink, data->d_buf, size); | ||
1685 | |||
1686 | elf_end(elf); | ||
1687 | |||
1688 | out_close: | ||
1689 | close(fd); | ||
1690 | out: | ||
1691 | return err; | ||
1692 | } | ||
1693 | |||
1694 | char dso__symtab_origin(const struct dso *dso) | 923 | char dso__symtab_origin(const struct dso *dso) |
1695 | { | 924 | { |
1696 | static const char origin[] = { | 925 | static const char origin[] = { |
@@ -2035,25 +1264,6 @@ static int machine__set_modules_path(struct machine *machine) | |||
2035 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); | 1264 | return map_groups__set_modules_path_dir(&machine->kmaps, modules_path); |
2036 | } | 1265 | } |
2037 | 1266 | ||
2038 | /* | ||
2039 | * Constructor variant for modules (where we know from /proc/modules where | ||
2040 | * they are loaded) and for vmlinux, where only after we load all the | ||
2041 | * symbols we'll know where it starts and ends. | ||
2042 | */ | ||
2043 | static struct map *map__new2(u64 start, struct dso *dso, enum map_type type) | ||
2044 | { | ||
2045 | struct map *map = calloc(1, (sizeof(*map) + | ||
2046 | (dso->kernel ? sizeof(struct kmap) : 0))); | ||
2047 | if (map != NULL) { | ||
2048 | /* | ||
2049 | * ->end will be filled after we load all the symbols | ||
2050 | */ | ||
2051 | map__init(map, type, start, 0, 0, dso); | ||
2052 | } | ||
2053 | |||
2054 | return map; | ||
2055 | } | ||
2056 | |||
2057 | struct map *machine__new_module(struct machine *machine, u64 start, | 1267 | struct map *machine__new_module(struct machine *machine, u64 start, |
2058 | const char *filename) | 1268 | const char *filename) |
2059 | { | 1269 | { |
@@ -2357,7 +1567,7 @@ out_try_fixup: | |||
2357 | return err; | 1567 | return err; |
2358 | } | 1568 | } |
2359 | 1569 | ||
2360 | static void dsos__add(struct list_head *head, struct dso *dso) | 1570 | void dsos__add(struct list_head *head, struct dso *dso) |
2361 | { | 1571 | { |
2362 | list_add_tail(&dso->node, head); | 1572 | list_add_tail(&dso->node, head); |
2363 | } | 1573 | } |
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h index 355993d3abbf..38ccbbb39faa 100644 --- a/tools/perf/util/symbol.h +++ b/tools/perf/util/symbol.h | |||
@@ -254,6 +254,7 @@ static inline void dso__set_loaded(struct dso *dso, enum map_type type) | |||
254 | 254 | ||
255 | void dso__sort_by_name(struct dso *dso, enum map_type type); | 255 | void dso__sort_by_name(struct dso *dso, enum map_type type); |
256 | 256 | ||
257 | void dsos__add(struct list_head *head, struct dso *dso); | ||
257 | struct dso *__dsos__findnew(struct list_head *head, const char *name); | 258 | struct dso *__dsos__findnew(struct list_head *head, const char *name); |
258 | 259 | ||
259 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); | 260 | int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter); |
@@ -283,6 +284,7 @@ size_t dso__fprintf(struct dso *dso, enum map_type type, FILE *fp); | |||
283 | char dso__symtab_origin(const struct dso *dso); | 284 | char dso__symtab_origin(const struct dso *dso); |
284 | void dso__set_long_name(struct dso *dso, char *name); | 285 | void dso__set_long_name(struct dso *dso, char *name); |
285 | void dso__set_build_id(struct dso *dso, void *build_id); | 286 | void dso__set_build_id(struct dso *dso, void *build_id); |
287 | bool dso__build_id_equal(const struct dso *dso, u8 *build_id); | ||
286 | void dso__read_running_kernel_build_id(struct dso *dso, | 288 | void dso__read_running_kernel_build_id(struct dso *dso, |
287 | struct machine *machine); | 289 | struct machine *machine); |
288 | struct map *dso__new_map(const char *name); | 290 | struct map *dso__new_map(const char *name); |
@@ -298,6 +300,8 @@ int build_id__sprintf(const u8 *build_id, int len, char *bf); | |||
298 | int kallsyms__parse(const char *filename, void *arg, | 300 | int kallsyms__parse(const char *filename, void *arg, |
299 | int (*process_symbol)(void *arg, const char *name, | 301 | int (*process_symbol)(void *arg, const char *name, |
300 | char type, u64 start, u64 end)); | 302 | char type, u64 start, u64 end)); |
303 | int filename__read_debuglink(const char *filename, char *debuglink, | ||
304 | size_t size); | ||
301 | 305 | ||
302 | void machine__destroy_kernel_maps(struct machine *machine); | 306 | void machine__destroy_kernel_maps(struct machine *machine); |
303 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); | 307 | int __machine__create_kernel_maps(struct machine *machine, struct dso *kernel); |
@@ -310,6 +314,7 @@ void machines__destroy_guest_kernel_maps(struct rb_root *machines); | |||
310 | int symbol__init(void); | 314 | int symbol__init(void); |
311 | void symbol__exit(void); | 315 | void symbol__exit(void); |
312 | void symbol__elf_init(void); | 316 | void symbol__elf_init(void); |
317 | struct symbol *symbol__new(u64 start, u64 len, u8 binding, const char *name); | ||
313 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, | 318 | size_t symbol__fprintf_symname_offs(const struct symbol *sym, |
314 | const struct addr_location *al, FILE *fp); | 319 | const struct addr_location *al, FILE *fp); |
315 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); | 320 | size_t symbol__fprintf_symname(const struct symbol *sym, FILE *fp); |
@@ -327,4 +332,14 @@ ssize_t dso__data_read_addr(struct dso *dso, struct map *map, | |||
327 | struct machine *machine, u64 addr, | 332 | struct machine *machine, u64 addr, |
328 | u8 *data, ssize_t size); | 333 | u8 *data, ssize_t size); |
329 | int dso__test_data(void); | 334 | int dso__test_data(void); |
335 | int dso__load_sym(struct dso *dso, struct map *map, const char *name, int fd, | ||
336 | symbol_filter_t filter, int kmodule, int want_symtab); | ||
337 | int dso__synthesize_plt_symbols(struct dso *dso, char *name, struct map *map, | ||
338 | symbol_filter_t filter); | ||
339 | |||
340 | void symbols__insert(struct rb_root *symbols, struct symbol *sym); | ||
341 | void symbols__fixup_duplicate(struct rb_root *symbols); | ||
342 | void symbols__fixup_end(struct rb_root *symbols); | ||
343 | void __map_groups__fixup_end(struct map_groups *mg, enum map_type type); | ||
344 | |||
330 | #endif /* __PERF_SYMBOL */ | 345 | #endif /* __PERF_SYMBOL */ |