perf: Remove unused parts of symbol-elf.c
[akaros.git] / tools / profile / perf / symbol-elf.c
1 /* Copyright (c) 2011-2015 Linux Perf Authors
2  *
3  * This source code is licensed under the GNU General Public License Version 2.
4  * See the file LICENSE-gpl-2.0.txt for more details. */
5
6 #include <fcntl.h>
7 #include <stdio.h>
8 #include <errno.h>
9 #include <string.h>
10 #include <unistd.h>
11 #include <inttypes.h>
12
13 #include "symbol.h"
14 #include "machine.h"
15 #include "vdso.h"
16 #include <symbol/kallsyms.h>
17 #include "debug.h"
18
19 #ifndef EM_AARCH64
20 #define EM_AARCH64      183  /* ARM 64 bit */
21 #endif
22
23
24 #ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
25 extern char *cplus_demangle(const char *, int);
26
27 static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
28 {
29         return cplus_demangle(c, i);
30 }
31 #else
32 #ifdef NO_DEMANGLE
33 static inline char *bfd_demangle(void __maybe_unused *v,
34                                  const char __maybe_unused *c,
35                                  int __maybe_unused i)
36 {
37         return NULL;
38 }
39 #else
40 #define PACKAGE 'perf'
41 #include <bfd.h>
42 #endif
43 #endif
44
45 #ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
46 static int elf_getphdrnum(Elf *elf, size_t *dst)
47 {
48         GElf_Ehdr gehdr;
49         GElf_Ehdr *ehdr;
50
51         ehdr = gelf_getehdr(elf, &gehdr);
52         if (!ehdr)
53                 return -1;
54
55         *dst = ehdr->e_phnum;
56
57         return 0;
58 }
59 #endif
60
61 #ifndef NT_GNU_BUILD_ID
62 #define NT_GNU_BUILD_ID 3
63 #endif
64
65 /**
66  * elf_symtab__for_each_symbol - iterate thru all the symbols
67  *
68  * @syms: struct elf_symtab instance to iterate
69  * @idx: uint32_t idx
70  * @sym: GElf_Sym iterator
71  */
72 #define elf_symtab__for_each_symbol(syms, nr_syms, idx, sym) \
73         for (idx = 0, gelf_getsym(syms, idx, &sym);\
74              idx < nr_syms; \
75              idx++, gelf_getsym(syms, idx, &sym))
76
77 static inline uint8_t elf_sym__type(const GElf_Sym *sym)
78 {
79         return GELF_ST_TYPE(sym->st_info);
80 }
81
82 #ifndef STT_GNU_IFUNC
83 #define STT_GNU_IFUNC 10
84 #endif
85
86 static inline int elf_sym__is_function(const GElf_Sym *sym)
87 {
88         return (elf_sym__type(sym) == STT_FUNC ||
89                 elf_sym__type(sym) == STT_GNU_IFUNC) &&
90                sym->st_name != 0 &&
91                sym->st_shndx != SHN_UNDEF;
92 }
93
94 static inline bool elf_sym__is_object(const GElf_Sym *sym)
95 {
96         return elf_sym__type(sym) == STT_OBJECT &&
97                 sym->st_name != 0 &&
98                 sym->st_shndx != SHN_UNDEF;
99 }
100
101 static inline int elf_sym__is_label(const GElf_Sym *sym)
102 {
103         return elf_sym__type(sym) == STT_NOTYPE &&
104                 sym->st_name != 0 &&
105                 sym->st_shndx != SHN_UNDEF &&
106                 sym->st_shndx != SHN_ABS;
107 }
108
109 static bool elf_sym__is_a(GElf_Sym *sym, enum map_type type)
110 {
111         switch (type) {
112         case MAP__FUNCTION:
113                 return elf_sym__is_function(sym);
114         case MAP__VARIABLE:
115                 return elf_sym__is_object(sym);
116         default:
117                 return false;
118         }
119 }
120
121 static inline const char *elf_sym__name(const GElf_Sym *sym,
122                                         const Elf_Data *symstrs)
123 {
124         return symstrs->d_buf + sym->st_name;
125 }
126
127 static inline const char *elf_sec__name(const GElf_Shdr *shdr,
128                                         const Elf_Data *secstrs)
129 {
130         return secstrs->d_buf + shdr->sh_name;
131 }
132
133 static inline int elf_sec__is_text(const GElf_Shdr *shdr,
134                                         const Elf_Data *secstrs)
135 {
136         return strstr(elf_sec__name(shdr, secstrs), "text") != NULL;
137 }
138
139 static inline bool elf_sec__is_data(const GElf_Shdr *shdr,
140                                     const Elf_Data *secstrs)
141 {
142         return strstr(elf_sec__name(shdr, secstrs), "data") != NULL;
143 }
144
145 static bool elf_sec__is_a(GElf_Shdr *shdr, Elf_Data *secstrs,
146                           enum map_type type)
147 {
148         switch (type) {
149         case MAP__FUNCTION:
150                 return elf_sec__is_text(shdr, secstrs);
151         case MAP__VARIABLE:
152                 return elf_sec__is_data(shdr, secstrs);
153         default:
154                 return false;
155         }
156 }
157
158 static size_t elf_addr_to_index(Elf *elf, GElf_Addr addr)
159 {
160         Elf_Scn *sec = NULL;
161         GElf_Shdr shdr;
162         size_t cnt = 1;
163
164         while ((sec = elf_nextscn(elf, sec)) != NULL) {
165                 gelf_getshdr(sec, &shdr);
166
167                 if ((addr >= shdr.sh_addr) &&
168                     (addr < (shdr.sh_addr + shdr.sh_size)))
169                         return cnt;
170
171                 ++cnt;
172         }
173
174         return -1;
175 }
176
177 Elf_Scn *elf_section_by_name(Elf *elf, GElf_Ehdr *ep,
178                              GElf_Shdr *shp, const char *name, size_t *idx)
179 {
180         Elf_Scn *sec = NULL;
181         size_t cnt = 1;
182
183         /* Elf is corrupted/truncated, avoid calling elf_strptr. */
184         if (!elf_rawdata(elf_getscn(elf, ep->e_shstrndx), NULL))
185                 return NULL;
186
187         while ((sec = elf_nextscn(elf, sec)) != NULL) {
188                 char *str;
189
190                 gelf_getshdr(sec, shp);
191                 str = elf_strptr(elf, ep->e_shstrndx, shp->sh_name);
192                 if (str && !strcmp(name, str)) {
193                         if (idx)
194                                 *idx = cnt;
195                         return sec;
196                 }
197                 ++cnt;
198         }
199
200         return NULL;
201 }
202
203 #define elf_section__for_each_rel(reldata, pos, pos_mem, idx, nr_entries) \
204         for (idx = 0, pos = gelf_getrel(reldata, 0, &pos_mem); \
205              idx < nr_entries; \
206              ++idx, pos = gelf_getrel(reldata, idx, &pos_mem))
207
208 #define elf_section__for_each_rela(reldata, pos, pos_mem, idx, nr_entries) \
209         for (idx = 0, pos = gelf_getrela(reldata, 0, &pos_mem); \
210              idx < nr_entries; \
211              ++idx, pos = gelf_getrela(reldata, idx, &pos_mem))
212
213
214 /*
215  * Align offset to 4 bytes as needed for note name and descriptor data.
216  */
217 #define NOTE_ALIGN(n) (((n) + 3) & -4U)
218
219 static int elf_read_build_id(Elf *elf, void *bf, size_t size)
220 {
221         int err = -1;
222         GElf_Ehdr ehdr;
223         GElf_Shdr shdr;
224         Elf_Data *data;
225         Elf_Scn *sec;
226         Elf_Kind ek;
227         void *ptr;
228
229         if (size < BUILD_ID_SIZE)
230                 goto out;
231
232         ek = elf_kind(elf);
233         if (ek != ELF_K_ELF)
234                 goto out;
235
236         if (gelf_getehdr(elf, &ehdr) == NULL) {
237                 pr_err("%s: cannot get elf header.\n", __func__);
238                 goto out;
239         }
240
241         /*
242          * Check following sections for notes:
243          *   '.note.gnu.build-id'
244          *   '.notes'
245          *   '.note' (VDSO specific)
246          */
247         do {
248                 sec = elf_section_by_name(elf, &ehdr, &shdr,
249                                           ".note.gnu.build-id", NULL);
250                 if (sec)
251                         break;
252
253                 sec = elf_section_by_name(elf, &ehdr, &shdr,
254                                           ".notes", NULL);
255                 if (sec)
256                         break;
257
258                 sec = elf_section_by_name(elf, &ehdr, &shdr,
259                                           ".note", NULL);
260                 if (sec)
261                         break;
262
263                 return err;
264
265         } while (0);
266
267         data = elf_getdata(sec, NULL);
268         if (data == NULL)
269                 goto out;
270
271         ptr = data->d_buf;
272         while (ptr < (data->d_buf + data->d_size)) {
273                 GElf_Nhdr *nhdr = ptr;
274                 size_t namesz = NOTE_ALIGN(nhdr->n_namesz),
275                        descsz = NOTE_ALIGN(nhdr->n_descsz);
276                 const char *name;
277
278                 ptr += sizeof(*nhdr);
279                 name = ptr;
280                 ptr += namesz;
281                 if (nhdr->n_type == NT_GNU_BUILD_ID &&
282                     nhdr->n_namesz == sizeof("GNU")) {
283                         if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
284                                 size_t sz = min(size, descsz);
285                                 memcpy(bf, ptr, sz);
286                                 memset(bf + sz, 0, size - sz);
287                                 err = descsz;
288                                 break;
289                         }
290                 }
291                 ptr += descsz;
292         }
293
294 out:
295         return err;
296 }
297
298 int filename__read_build_id(const char *filename, void *bf, size_t size)
299 {
300         int fd, err = -1;
301         Elf *elf;
302
303         if (size < BUILD_ID_SIZE)
304                 goto out;
305
306         fd = open(filename, O_RDONLY);
307         if (fd < 0)
308                 goto out;
309
310         elf = elf_begin(fd, PERF_ELF_C_READ_MMAP, NULL);
311         if (elf == NULL) {
312                 pr_debug2("%s: cannot read %s ELF file.\n", __func__, filename);
313                 goto out_close;
314         }
315
316         err = elf_read_build_id(elf, bf, size);
317
318         elf_end(elf);
319 out_close:
320         close(fd);
321 out:
322         return err;
323 }
324
325 void symbol__elf_init(void)
326 {
327         elf_version(EV_CURRENT);
328 }