xref: /openbmc/linux/tools/perf/util/symbol-minimal.c (revision 9b93eb47)
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 }
385