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