xref: /openbsd-src/usr.bin/nm/elf.c (revision f2da64fbbbf1b03f09f390ab01267c93dfd77c4c)
1 /*	$OpenBSD: elf.c,v 1.34 2015/12/09 19:28:34 mmcc Exp $	*/
2 
3 /*
4  * Copyright (c) 2003 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/mman.h>
30 #include <unistd.h>
31 #include <a.out.h>
32 #include <elf_abi.h>
33 #include <errno.h>
34 #include <err.h>
35 #include <stdint.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <ctype.h>
40 #include "util.h"
41 #include "elfuncs.h"
42 
43 #if ELFSIZE == 32
44 #define	swap_addr	swap32
45 #define	swap_off	swap32
46 #define	swap_sword	swap32
47 #define	swap_word	swap32
48 #define	swap_sxword	swap32
49 #define	swap_xword	swap32
50 #define	swap_half	swap16
51 #define	swap_quarter	swap16
52 #define	elf_fix_header	elf32_fix_header
53 #define	elf_load_shdrs	elf32_load_shdrs
54 #define	elf_load_phdrs	elf32_load_phdrs
55 #define	elf_fix_shdrs	elf32_fix_shdrs
56 #define	elf_fix_phdrs	elf32_fix_phdrs
57 #define	elf_fix_sym	elf32_fix_sym
58 #define	elf_size	elf32_size
59 #define	elf_symloadx	elf32_symloadx
60 #define	elf_symload	elf32_symload
61 #define	elf2nlist	elf32_2nlist
62 #define	elf_shn2type	elf32_shn2type
63 #elif ELFSIZE == 64
64 #define	swap_addr	swap64
65 #define	swap_off	swap64
66 #ifdef __alpha__
67 #define	swap_sword	swap64
68 #define	swap_word	swap64
69 #else
70 #define	swap_sword	swap32
71 #define	swap_word	swap32
72 #endif
73 #define	swap_sxword	swap64
74 #define	swap_xword	swap64
75 #define	swap_half	swap64
76 #define	swap_quarter	swap16
77 #define	elf_fix_header	elf64_fix_header
78 #define	elf_load_shdrs	elf64_load_shdrs
79 #define	elf_load_phdrs	elf64_load_phdrs
80 #define	elf_fix_shdrs	elf64_fix_shdrs
81 #define	elf_fix_phdrs	elf64_fix_phdrs
82 #define	elf_fix_sym	elf64_fix_sym
83 #define	elf_size	elf64_size
84 #define	elf_symloadx	elf64_symloadx
85 #define	elf_symload	elf64_symload
86 #define	elf2nlist	elf64_2nlist
87 #define	elf_shn2type	elf64_shn2type
88 #else
89 #error "Unsupported ELF class"
90 #endif
91 
92 #define	ELF_SDATA	".sdata"
93 #define	ELF_TDATA	".tdata"
94 #define	ELF_SBSS	".sbss"
95 #define	ELF_TBSS	".tbss"
96 #define	ELF_PLT		".plt"
97 
98 #ifndef	SHN_MIPS_ACOMMON
99 #define	SHN_MIPS_ACOMMON	SHN_LOPROC + 0
100 #endif
101 #ifndef	SHN_MIPS_TEXT
102 #define	SHN_MIPS_TEXT		SHN_LOPROC + 1
103 #endif
104 #ifndef	SHN_MIPS_DATA
105 #define	SHN_MIPS_DATA		SHN_LOPROC + 2
106 #endif
107 #ifndef	SHN_MIPS_SUNDEFINED
108 #define	SHN_MIPS_SUNDEFINED	SHN_LOPROC + 4
109 #endif
110 #ifndef	SHN_MIPS_SCOMMON
111 #define	SHN_MIPS_SCOMMON	SHN_LOPROC + 3
112 #endif
113 
114 #ifndef	STT_PARISC_MILLI
115 #define	STT_PARISC_MILLI	STT_LOPROC + 0
116 #endif
117 
118 int elf_shn2type(Elf_Ehdr *, u_int, const char *);
119 int elf2nlist(Elf_Sym *, Elf_Ehdr *, Elf_Shdr *, char *, struct xnlist *);
120 
121 int
122 elf_fix_header(Elf_Ehdr *eh)
123 {
124 	/* nothing to do */
125 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
126 		return (0);
127 
128 	eh->e_type = swap16(eh->e_type);
129 	eh->e_machine = swap16(eh->e_machine);
130 	eh->e_version = swap32(eh->e_version);
131 	eh->e_entry = swap_addr(eh->e_entry);
132 	eh->e_phoff = swap_off(eh->e_phoff);
133 	eh->e_shoff = swap_off(eh->e_shoff);
134 	eh->e_flags = swap32(eh->e_flags);
135 	eh->e_ehsize = swap16(eh->e_ehsize);
136 	eh->e_phentsize = swap16(eh->e_phentsize);
137 	eh->e_phnum = swap16(eh->e_phnum);
138 	eh->e_shentsize = swap16(eh->e_shentsize);
139 	eh->e_shnum = swap16(eh->e_shnum);
140 	eh->e_shstrndx = swap16(eh->e_shstrndx);
141 
142 	return (1);
143 }
144 
145 Elf_Shdr *
146 elf_load_shdrs(const char *name, FILE *fp, off_t foff, Elf_Ehdr *head)
147 {
148 	Elf_Shdr *shdr;
149 
150 	elf_fix_header(head);
151 
152 	if (head->e_shnum == 0) {
153 		warnx("%s: no section header table", name);
154 		return (NULL);
155 	}
156 
157 	if (head->e_shstrndx >= head->e_shnum) {
158 		warnx("%s: inconsistent section header table", name);
159 		return (NULL);
160 	}
161 
162 	if (head->e_shentsize < sizeof(Elf_Shdr)) {
163 		warnx("%s: inconsistent section header size", name);
164 		return (NULL);
165 	}
166 
167 	if ((shdr = calloc(head->e_shnum, head->e_shentsize)) == NULL) {
168 		warn("%s: malloc shdr", name);
169 		return (NULL);
170 	}
171 
172 	if (fseeko(fp, foff + head->e_shoff, SEEK_SET)) {
173 		warn("%s: fseeko", name);
174 		free(shdr);
175 		return (NULL);
176 	}
177 
178 	if (fread(shdr, head->e_shentsize, head->e_shnum, fp) != head->e_shnum) {
179 		warnx("%s: premature EOF", name);
180 		free(shdr);
181 		return (NULL);
182 	}
183 
184 	elf_fix_shdrs(head, shdr);
185 	return (shdr);
186 }
187 
188 Elf_Phdr *
189 elf_load_phdrs(const char *name, FILE *fp, off_t foff, Elf_Ehdr *head)
190 {
191 	Elf_Phdr *phdr;
192 
193 	if ((phdr = calloc(head->e_phentsize, head->e_phnum)) == NULL) {
194 		warn("%s: malloc phdr", name);
195 		return (NULL);
196 	}
197 
198 	if (fseeko(fp, foff + head->e_phoff, SEEK_SET)) {
199 		warn("%s: fseeko", name);
200 		free(phdr);
201 		return (NULL);
202 	}
203 
204 	if (fread(phdr, head->e_phentsize, head->e_phnum, fp) != head->e_phnum) {
205 		warnx("%s: premature EOF", name);
206 		free(phdr);
207 		return (NULL);
208 	}
209 
210 	elf_fix_phdrs(head, phdr);
211 	return (phdr);
212 }
213 
214 int
215 elf_fix_shdrs(Elf_Ehdr *eh, Elf_Shdr *shdr)
216 {
217 	int i;
218 
219 	/* nothing to do */
220 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
221 		return (0);
222 
223 	for (i = eh->e_shnum; i--; shdr++) {
224 		shdr->sh_name = swap32(shdr->sh_name);
225 		shdr->sh_type = swap32(shdr->sh_type);
226 		shdr->sh_flags = swap_xword(shdr->sh_flags);
227 		shdr->sh_addr = swap_addr(shdr->sh_addr);
228 		shdr->sh_offset = swap_off(shdr->sh_offset);
229 		shdr->sh_size = swap_xword(shdr->sh_size);
230 		shdr->sh_link = swap32(shdr->sh_link);
231 		shdr->sh_info = swap32(shdr->sh_info);
232 		shdr->sh_addralign = swap_xword(shdr->sh_addralign);
233 		shdr->sh_entsize = swap_xword(shdr->sh_entsize);
234 	}
235 
236 	return (1);
237 }
238 
239 int
240 elf_fix_phdrs(Elf_Ehdr *eh, Elf_Phdr *phdr)
241 {
242 	int i;
243 
244 	/* nothing to do */
245 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
246 		return (0);
247 
248 	for (i = eh->e_phnum; i--; phdr++) {
249 		phdr->p_type = swap32(phdr->p_type);
250 		phdr->p_flags = swap32(phdr->p_flags);
251 		phdr->p_offset = swap_off(phdr->p_offset);
252 		phdr->p_vaddr = swap_addr(phdr->p_vaddr);
253 		phdr->p_paddr = swap_addr(phdr->p_paddr);
254 		phdr->p_filesz = swap_xword(phdr->p_filesz);
255 		phdr->p_memsz = swap_xword(phdr->p_memsz);
256 		phdr->p_align = swap_xword(phdr->p_align);
257 	}
258 
259 	return (1);
260 }
261 
262 int
263 elf_fix_sym(Elf_Ehdr *eh, Elf_Sym *sym)
264 {
265 	/* nothing to do */
266 	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
267 		return (0);
268 
269 	sym->st_name = swap32(sym->st_name);
270 	sym->st_shndx = swap16(sym->st_shndx);
271 	sym->st_value = swap_addr(sym->st_value);
272 	sym->st_size = swap_xword(sym->st_size);
273 
274 	return (1);
275 }
276 
277 int
278 elf_shn2type(Elf_Ehdr *eh, u_int shn, const char *sn)
279 {
280 	switch (shn) {
281 	case SHN_MIPS_SUNDEFINED:
282 		if (eh->e_machine == EM_MIPS)
283 			return (N_UNDF | N_EXT);
284 		break;
285 
286 	case SHN_UNDEF:
287 		return (N_UNDF | N_EXT);
288 
289 	case SHN_ABS:
290 		return (N_ABS);
291 
292 	case SHN_MIPS_ACOMMON:
293 		if (eh->e_machine == EM_MIPS)
294 			return (N_COMM);
295 		break;
296 
297 	case SHN_MIPS_SCOMMON:
298 		if (eh->e_machine == EM_MIPS)
299 			return (N_COMM);
300 		break;
301 
302 	case SHN_COMMON:
303 		return (N_COMM);
304 
305 	case SHN_MIPS_TEXT:
306 		if (eh->e_machine == EM_MIPS)
307 			return (N_TEXT);
308 		break;
309 
310 	case SHN_MIPS_DATA:
311 		if (eh->e_machine == EM_MIPS)
312 			return (N_DATA);
313 		break;
314 
315 	default:
316 		/* TODO: beyond 8 a table-driven binsearch should be used */
317 		if (sn == NULL)
318 			return (-1);
319 		else if (!strcmp(sn, ELF_TEXT))
320 			return (N_TEXT);
321 		else if (!strcmp(sn, ELF_RODATA))
322 			return (N_SIZE);
323 		else if (!strcmp(sn, ELF_DATA))
324 			return (N_DATA);
325 		else if (!strcmp(sn, ELF_SDATA))
326 			return (N_DATA);
327 		else if (!strcmp(sn, ELF_TDATA))
328 			return (N_DATA);
329 		else if (!strcmp(sn, ELF_BSS))
330 			return (N_BSS);
331 		else if (!strcmp(sn, ELF_SBSS))
332 			return (N_BSS);
333 		else if (!strcmp(sn, ELF_TBSS))
334 			return (N_BSS);
335 		else if (!strncmp(sn, ELF_GOT, sizeof(ELF_GOT) - 1))
336 			return (N_DATA);
337 		else if (!strncmp(sn, ELF_PLT, sizeof(ELF_PLT) - 1))
338 			return (N_DATA);
339 	}
340 
341 	return (-1);
342 }
343 
344 /*
345  * Devise xnlist's type from Elf_Sym.
346  * XXX this task is done as well in libc and kvm_mkdb.
347  */
348 int
349 elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr,
350     struct xnlist *np)
351 {
352 	u_char stt;
353 	const char *sn;
354 	int type;
355 
356 	if (sym->st_shndx < eh->e_shnum)
357 		sn = shstr + shdr[sym->st_shndx].sh_name;
358 	else
359 		sn = NULL;
360 #if 0
361 	{
362 		extern char *stab;
363 		printf("%d:%s %d %d %s\n", sym->st_shndx, sn? sn : "",
364 		    ELF_ST_TYPE(sym->st_info), ELF_ST_BIND(sym->st_info),
365 		    stab + sym->st_name);
366 	}
367 #endif
368 
369 	switch (stt = ELF_ST_TYPE(sym->st_info)) {
370 	case STT_NOTYPE:
371 	case STT_OBJECT:
372 	case STT_TLS:
373 		type = elf_shn2type(eh, sym->st_shndx, sn);
374 		if (type < 0) {
375 			if (sn == NULL)
376 				np->nl.n_other = '?';
377 			else
378 				np->nl.n_type = stt == STT_NOTYPE ?
379 				    N_COMM : N_DATA;
380 		} else {
381 			/* a hack for .rodata check (; */
382 			if (type == N_SIZE) {
383 				np->nl.n_type = N_DATA;
384 				np->nl.n_other = 'r';
385 			} else
386 				np->nl.n_type = type;
387 		}
388 		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
389 			np->nl.n_other = 'W';
390 		break;
391 
392 	case STT_FUNC:
393 		type = elf_shn2type(eh, sym->st_shndx, NULL);
394 		np->nl.n_type = type < 0? N_TEXT : type;
395 		if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
396 			np->nl.n_other = 'W';
397 		} else if (sn != NULL && *sn != 0 &&
398 		    strcmp(sn, ELF_INIT) &&
399 		    strcmp(sn, ELF_TEXT) &&
400 		    strcmp(sn, ELF_FINI))	/* XXX GNU compat */
401 			np->nl.n_other = '?';
402 		break;
403 
404 	case STT_SECTION:
405 		type = elf_shn2type(eh, sym->st_shndx, NULL);
406 		if (type < 0)
407 			np->nl.n_other = '?';
408 		else
409 			np->nl.n_type = type;
410 		break;
411 
412 	case STT_FILE:
413 		np->nl.n_type = N_FN | N_EXT;
414 		break;
415 
416 	case STT_PARISC_MILLI:
417 		if (eh->e_machine == EM_PARISC)
418 			np->nl.n_type = N_TEXT;
419 		else
420 			np->nl.n_other = '?';
421 		break;
422 
423 	default:
424 		np->nl.n_other = '?';
425 		break;
426 	}
427 	if (np->nl.n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
428 		np->nl.n_type |= N_EXT;
429 		if (np->nl.n_other)
430 			np->nl.n_other = toupper((unsigned char)np->nl.n_other);
431 	}
432 
433 	return (0);
434 }
435 
436 int
437 elf_size(Elf_Ehdr *head, Elf_Shdr *shdr,
438     u_long *ptext, u_long *pdata, u_long *pbss)
439 {
440 	int i;
441 
442 	*ptext = *pdata = *pbss = 0;
443 
444 	for (i = 0; i < head->e_shnum; i++) {
445 		if (!(shdr[i].sh_flags & SHF_ALLOC))
446 			;
447 		else if (shdr[i].sh_flags & SHF_EXECINSTR ||
448 		    !(shdr[i].sh_flags & SHF_WRITE))
449 			*ptext += shdr[i].sh_size;
450 		else if (shdr[i].sh_type == SHT_NOBITS)
451 			*pbss += shdr[i].sh_size;
452 		else
453 			*pdata += shdr[i].sh_size;
454 	}
455 
456 	return (0);
457 }
458 
459 int
460 elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
461     Elf_Shdr *shdr, char *shstr, long shstrsize, struct xnlist **pnames,
462     struct xnlist ***psnames, size_t *pstabsize, int *pnrawnames,
463     const char *strtab, const char *symtab)
464 {
465 	long symsize;
466 	struct xnlist *np;
467 	Elf_Sym sbuf;
468 	int i;
469 
470 	for (i = 0; i < eh->e_shnum; i++) {
471 		if (shdr[i].sh_name >= shstrsize) {
472 			warnx("%s: corrupt file", name);
473 			return (1);
474 		}
475 		if (!strcmp(shstr + shdr[i].sh_name, strtab)) {
476 			*pstabsize = shdr[i].sh_size;
477 			if (*pstabsize > SIZE_MAX) {
478 				warnx("%s: corrupt file", name);
479 				return (1);
480 			}
481 
482 			MMAP(stab, *pstabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
483 			    fileno(fp), foff + shdr[i].sh_offset);
484 			if (stab == MAP_FAILED)
485 				return (1);
486 		}
487 	}
488 	for (i = 0; i < eh->e_shnum; i++) {
489 		if (!strcmp(shstr + shdr[i].sh_name, symtab)) {
490 			symsize = shdr[i].sh_size;
491 			if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) {
492 				warn("%s: fseeko", name);
493 				if (stab)
494 					MUNMAP(stab, *pstabsize);
495 				return (1);
496 			}
497 
498 			*pnrawnames = symsize / sizeof(sbuf);
499 			if ((*pnames = calloc(*pnrawnames, sizeof(*np))) == NULL) {
500 				warn("%s: malloc names", name);
501 				if (stab)
502 					MUNMAP(stab, *pstabsize);
503 				*pnrawnames = 0;
504 				return (1);
505 			}
506 			if ((*psnames = calloc(*pnrawnames, sizeof(np))) == NULL) {
507 				warn("%s: malloc snames", name);
508 				if (stab)
509 					MUNMAP(stab, *pstabsize);
510 				free(*pnames);
511 				*pnames = NULL;
512 				*pnrawnames = 0;
513 				return (1);
514 			}
515 
516 			for (np = *pnames; symsize > 0; symsize -= sizeof(sbuf)) {
517 				if (fread(&sbuf, 1, sizeof(sbuf),
518 				    fp) != sizeof(sbuf)) {
519 					warn("%s: read symbol", name);
520 					if (stab)
521 						MUNMAP(stab, *pstabsize);
522 					free(*pnames);
523 					free(*psnames);
524 					*pnames = NULL;
525 					*psnames = NULL;
526 					*pnrawnames = 0;
527 					return (1);
528 				}
529 
530 				elf_fix_sym(eh, &sbuf);
531 
532 				if (!sbuf.st_name ||
533 				    sbuf.st_name > *pstabsize)
534 					continue;
535 
536 				elf2nlist(&sbuf, eh, shdr, shstr, np);
537 				np->nl.n_value = sbuf.st_value;
538 				np->nl.n_un.n_strx = sbuf.st_name;
539 				np->n_size = sbuf.st_size;
540 				np++;
541 			}
542 			*pnrawnames = np - *pnames;
543 		}
544 	}
545 	return (0);
546 }
547 
548 int
549 elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
550     Elf_Shdr *shdr, struct xnlist **pnames, struct xnlist ***psnames,
551     size_t *pstabsize, int *pnrawnames)
552 {
553 	long shstrsize;
554 	char *shstr;
555 
556 	shstrsize = shdr[eh->e_shstrndx].sh_size;
557 	if (shstrsize == 0) {
558 		warnx("%s: no name list", name);
559 		return (1);
560 	}
561 
562 	if ((shstr = malloc(shstrsize)) == NULL) {
563 		warn("%s: malloc shsrt", name);
564 		return (1);
565 	}
566 
567 	if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) {
568 		warn("%s: fseeko", name);
569 		free(shstr);
570 		return (1);
571 	}
572 
573 	if (fread(shstr, 1, shstrsize, fp) != shstrsize) {
574 		warnx("%s: premature EOF", name);
575 		free(shstr);
576 		return(1);
577 	}
578 
579 	stab = NULL;
580 	*pnames = NULL; *psnames = NULL; *pnrawnames = 0;
581 	if (!dynamic_only) {
582 		elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames,
583 		    psnames, pstabsize, pnrawnames, ELF_STRTAB, ELF_SYMTAB);
584 	}
585 	if (stab == NULL) {
586 		elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames,
587 		    psnames, pstabsize, pnrawnames, ELF_DYNSTR, ELF_DYNSYM);
588 	}
589 
590 	free(shstr);
591 	if (stab == NULL) {
592 		warnx("%s: no name list", name);
593 		free(*pnames);
594 		free(*psnames);
595 		return (1);
596 	}
597 
598 	return (0);
599 }
600