]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/perf/util/symbol-minimal.c
Merge drm/drm-next into drm-misc-next
[linux.git] / tools / perf / util / symbol-minimal.c
1 // SPDX-License-Identifier: GPL-2.0
2 #include "symbol.h"
3 #include "util.h"
4
5 #include <errno.h>
6 #include <unistd.h>
7 #include <stdio.h>
8 #include <fcntl.h>
9 #include <string.h>
10 #include <byteswap.h>
11 #include <sys/stat.h>
12
13
14 static bool check_need_swap(int file_endian)
15 {
16         const int data = 1;
17         u8 *check = (u8 *)&data;
18         int host_endian;
19
20         if (check[0] == 1)
21                 host_endian = ELFDATA2LSB;
22         else
23                 host_endian = ELFDATA2MSB;
24
25         return host_endian != file_endian;
26 }
27
28 #define NOTE_ALIGN(sz) (((sz) + 3) & ~3)
29
30 #define NT_GNU_BUILD_ID 3
31
32 static int read_build_id(void *note_data, size_t note_len, void *bf,
33                          size_t size, bool need_swap)
34 {
35         struct {
36                 u32 n_namesz;
37                 u32 n_descsz;
38                 u32 n_type;
39         } *nhdr;
40         void *ptr;
41
42         ptr = note_data;
43         while (ptr < (note_data + note_len)) {
44                 const char *name;
45                 size_t namesz, descsz;
46
47                 nhdr = ptr;
48                 if (need_swap) {
49                         nhdr->n_namesz = bswap_32(nhdr->n_namesz);
50                         nhdr->n_descsz = bswap_32(nhdr->n_descsz);
51                         nhdr->n_type = bswap_32(nhdr->n_type);
52                 }
53
54                 namesz = NOTE_ALIGN(nhdr->n_namesz);
55                 descsz = NOTE_ALIGN(nhdr->n_descsz);
56
57                 ptr += sizeof(*nhdr);
58                 name = ptr;
59                 ptr += namesz;
60                 if (nhdr->n_type == NT_GNU_BUILD_ID &&
61                     nhdr->n_namesz == sizeof("GNU")) {
62                         if (memcmp(name, "GNU", sizeof("GNU")) == 0) {
63                                 size_t sz = min(size, descsz);
64                                 memcpy(bf, ptr, sz);
65                                 memset(bf + sz, 0, size - sz);
66                                 return 0;
67                         }
68                 }
69                 ptr += descsz;
70         }
71
72         return -1;
73 }
74
75 int filename__read_debuglink(const char *filename __maybe_unused,
76                              char *debuglink __maybe_unused,
77                              size_t size __maybe_unused)
78 {
79         return -1;
80 }
81
82 /*
83  * Just try PT_NOTE header otherwise fails
84  */
85 int filename__read_build_id(const char *filename, void *bf, size_t size)
86 {
87         FILE *fp;
88         int ret = -1;
89         bool need_swap = false;
90         u8 e_ident[EI_NIDENT];
91         size_t buf_size;
92         void *buf;
93         int i;
94
95         fp = fopen(filename, "r");
96         if (fp == NULL)
97                 return -1;
98
99         if (fread(e_ident, sizeof(e_ident), 1, fp) != 1)
100                 goto out;
101
102         if (memcmp(e_ident, ELFMAG, SELFMAG) ||
103             e_ident[EI_VERSION] != EV_CURRENT)
104                 goto out;
105
106         need_swap = check_need_swap(e_ident[EI_DATA]);
107
108         /* for simplicity */
109         fseek(fp, 0, SEEK_SET);
110
111         if (e_ident[EI_CLASS] == ELFCLASS32) {
112                 Elf32_Ehdr ehdr;
113                 Elf32_Phdr *phdr;
114
115                 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
116                         goto out;
117
118                 if (need_swap) {
119                         ehdr.e_phoff = bswap_32(ehdr.e_phoff);
120                         ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
121                         ehdr.e_phnum = bswap_16(ehdr.e_phnum);
122                 }
123
124                 buf_size = ehdr.e_phentsize * ehdr.e_phnum;
125                 buf = malloc(buf_size);
126                 if (buf == NULL)
127                         goto out;
128
129                 fseek(fp, ehdr.e_phoff, SEEK_SET);
130                 if (fread(buf, buf_size, 1, fp) != 1)
131                         goto out_free;
132
133                 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
134                         void *tmp;
135                         long offset;
136
137                         if (need_swap) {
138                                 phdr->p_type = bswap_32(phdr->p_type);
139                                 phdr->p_offset = bswap_32(phdr->p_offset);
140                                 phdr->p_filesz = bswap_32(phdr->p_filesz);
141                         }
142
143                         if (phdr->p_type != PT_NOTE)
144                                 continue;
145
146                         buf_size = phdr->p_filesz;
147                         offset = phdr->p_offset;
148                         tmp = realloc(buf, buf_size);
149                         if (tmp == NULL)
150                                 goto out_free;
151
152                         buf = tmp;
153                         fseek(fp, offset, SEEK_SET);
154                         if (fread(buf, buf_size, 1, fp) != 1)
155                                 goto out_free;
156
157                         ret = read_build_id(buf, buf_size, bf, size, need_swap);
158                         if (ret == 0)
159                                 ret = size;
160                         break;
161                 }
162         } else {
163                 Elf64_Ehdr ehdr;
164                 Elf64_Phdr *phdr;
165
166                 if (fread(&ehdr, sizeof(ehdr), 1, fp) != 1)
167                         goto out;
168
169                 if (need_swap) {
170                         ehdr.e_phoff = bswap_64(ehdr.e_phoff);
171                         ehdr.e_phentsize = bswap_16(ehdr.e_phentsize);
172                         ehdr.e_phnum = bswap_16(ehdr.e_phnum);
173                 }
174
175                 buf_size = ehdr.e_phentsize * ehdr.e_phnum;
176                 buf = malloc(buf_size);
177                 if (buf == NULL)
178                         goto out;
179
180                 fseek(fp, ehdr.e_phoff, SEEK_SET);
181                 if (fread(buf, buf_size, 1, fp) != 1)
182                         goto out_free;
183
184                 for (i = 0, phdr = buf; i < ehdr.e_phnum; i++, phdr++) {
185                         void *tmp;
186                         long offset;
187
188                         if (need_swap) {
189                                 phdr->p_type = bswap_32(phdr->p_type);
190                                 phdr->p_offset = bswap_64(phdr->p_offset);
191                                 phdr->p_filesz = bswap_64(phdr->p_filesz);
192                         }
193
194                         if (phdr->p_type != PT_NOTE)
195                                 continue;
196
197                         buf_size = phdr->p_filesz;
198                         offset = phdr->p_offset;
199                         tmp = realloc(buf, buf_size);
200                         if (tmp == NULL)
201                                 goto out_free;
202
203                         buf = tmp;
204                         fseek(fp, offset, SEEK_SET);
205                         if (fread(buf, buf_size, 1, fp) != 1)
206                                 goto out_free;
207
208                         ret = read_build_id(buf, buf_size, bf, size, need_swap);
209                         if (ret == 0)
210                                 ret = size;
211                         break;
212                 }
213         }
214 out_free:
215         free(buf);
216 out:
217         fclose(fp);
218         return ret;
219 }
220
221 int sysfs__read_build_id(const char *filename, void *build_id, size_t size)
222 {
223         int fd;
224         int ret = -1;
225         struct stat stbuf;
226         size_t buf_size;
227         void *buf;
228
229         fd = open(filename, O_RDONLY);
230         if (fd < 0)
231                 return -1;
232
233         if (fstat(fd, &stbuf) < 0)
234                 goto out;
235
236         buf_size = stbuf.st_size;
237         buf = malloc(buf_size);
238         if (buf == NULL)
239                 goto out;
240
241         if (read(fd, buf, buf_size) != (ssize_t) buf_size)
242                 goto out_free;
243
244         ret = read_build_id(buf, buf_size, build_id, size, false);
245 out_free:
246         free(buf);
247 out:
248         close(fd);
249         return ret;
250 }
251
252 int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
253                  enum dso_binary_type type)
254 {
255         int fd = open(name, O_RDONLY);
256         if (fd < 0)
257                 goto out_errno;
258
259         ss->name = strdup(name);
260         if (!ss->name)
261                 goto out_close;
262
263         ss->fd = fd;
264         ss->type = type;
265
266         return 0;
267 out_close:
268         close(fd);
269 out_errno:
270         dso->load_errno = errno;
271         return -1;
272 }
273
274 bool symsrc__possibly_runtime(struct symsrc *ss __maybe_unused)
275 {
276         /* Assume all sym sources could be a runtime image. */
277         return true;
278 }
279
280 bool symsrc__has_symtab(struct symsrc *ss __maybe_unused)
281 {
282         return false;
283 }
284
285 void symsrc__destroy(struct symsrc *ss)
286 {
287         zfree(&ss->name);
288         close(ss->fd);
289 }
290
291 int dso__synthesize_plt_symbols(struct dso *dso __maybe_unused,
292                                 struct symsrc *ss __maybe_unused)
293 {
294         return 0;
295 }
296
297 static int fd__is_64_bit(int fd)
298 {
299         u8 e_ident[EI_NIDENT];
300
301         if (lseek(fd, 0, SEEK_SET))
302                 return -1;
303
304         if (readn(fd, e_ident, sizeof(e_ident)) != sizeof(e_ident))
305                 return -1;
306
307         if (memcmp(e_ident, ELFMAG, SELFMAG) ||
308             e_ident[EI_VERSION] != EV_CURRENT)
309                 return -1;
310
311         return e_ident[EI_CLASS] == ELFCLASS64;
312 }
313
314 enum dso_type dso__type_fd(int fd)
315 {
316         Elf64_Ehdr ehdr;
317         int ret;
318
319         ret = fd__is_64_bit(fd);
320         if (ret < 0)
321                 return DSO__TYPE_UNKNOWN;
322
323         if (ret)
324                 return DSO__TYPE_64BIT;
325
326         if (readn(fd, &ehdr, sizeof(ehdr)) != sizeof(ehdr))
327                 return DSO__TYPE_UNKNOWN;
328
329         if (ehdr.e_machine == EM_X86_64)
330                 return DSO__TYPE_X32BIT;
331
332         return DSO__TYPE_32BIT;
333 }
334
335 int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
336                   struct symsrc *ss,
337                   struct symsrc *runtime_ss __maybe_unused,
338                   int kmodule __maybe_unused)
339 {
340         unsigned char build_id[BUILD_ID_SIZE];
341         int ret;
342
343         ret = fd__is_64_bit(ss->fd);
344         if (ret >= 0)
345                 dso->is_64_bit = ret;
346
347         if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
348                 dso__set_build_id(dso, build_id);
349         }
350         return 0;
351 }
352
353 int file__read_maps(int fd __maybe_unused, bool exe __maybe_unused,
354                     mapfn_t mapfn __maybe_unused, void *data __maybe_unused,
355                     bool *is_64_bit __maybe_unused)
356 {
357         return -1;
358 }
359
360 int kcore_extract__create(struct kcore_extract *kce __maybe_unused)
361 {
362         return -1;
363 }
364
365 void kcore_extract__delete(struct kcore_extract *kce __maybe_unused)
366 {
367 }
368
369 int kcore_copy(const char *from_dir __maybe_unused,
370                const char *to_dir __maybe_unused)
371 {
372         return -1;
373 }
374
375 void symbol__elf_init(void)
376 {
377 }
378
379 char *dso__demangle_sym(struct dso *dso __maybe_unused,
380                         int kmodule __maybe_unused,
381                         const char *elf_name __maybe_unused)
382 {
383         return NULL;
384 }