1/*	$OpenBSD: elf.c,v 1.39 2021/11/07 08:09:04 semarie 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.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_fix_shdrs	elf32_fix_shdrs
55#define	elf_fix_sym	elf32_fix_sym
56#define	elf_size	elf32_size
57#define	elf_symloadx	elf32_symloadx
58#define	elf_symload	elf32_symload
59#define	elf2nlist	elf32_2nlist
60#define	elf_shn2type	elf32_shn2type
61#elif ELFSIZE == 64
62#define	swap_addr	swap64
63#define	swap_off	swap64
64#ifdef __alpha__
65#define	swap_sword	swap64
66#define	swap_word	swap64
67#else
68#define	swap_sword	swap32
69#define	swap_word	swap32
70#endif
71#define	swap_sxword	swap64
72#define	swap_xword	swap64
73#define	swap_half	swap64
74#define	swap_quarter	swap16
75#define	elf_fix_header	elf64_fix_header
76#define	elf_load_shdrs	elf64_load_shdrs
77#define	elf_fix_shdrs	elf64_fix_shdrs
78#define	elf_fix_sym	elf64_fix_sym
79#define	elf_size	elf64_size
80#define	elf_symloadx	elf64_symloadx
81#define	elf_symload	elf64_symload
82#define	elf2nlist	elf64_2nlist
83#define	elf_shn2type	elf64_shn2type
84#else
85#error "Unsupported ELF class"
86#endif
87
88#define	ELF_SDATA	".sdata"
89#define	ELF_TDATA	".tdata"
90#define	ELF_SBSS	".sbss"
91#define	ELF_TBSS	".tbss"
92#define	ELF_PLT		".plt"
93
94#ifndef	SHN_MIPS_ACOMMON
95#define	SHN_MIPS_ACOMMON	SHN_LOPROC + 0
96#endif
97#ifndef	SHN_MIPS_TEXT
98#define	SHN_MIPS_TEXT		SHN_LOPROC + 1
99#endif
100#ifndef	SHN_MIPS_DATA
101#define	SHN_MIPS_DATA		SHN_LOPROC + 2
102#endif
103#ifndef	SHN_MIPS_SUNDEFINED
104#define	SHN_MIPS_SUNDEFINED	SHN_LOPROC + 4
105#endif
106#ifndef	SHN_MIPS_SCOMMON
107#define	SHN_MIPS_SCOMMON	SHN_LOPROC + 3
108#endif
109
110#ifndef	STT_PARISC_MILLI
111#define	STT_PARISC_MILLI	STT_LOPROC + 0
112#endif
113
114
115static int elf_fix_header(Elf_Ehdr *);
116static int elf_fix_shdrs(Elf_Ehdr *, Elf_Shdr *);
117static int elf_fix_sym(Elf_Ehdr *, Elf_Sym *);
118static int elf_shn2type(Elf_Ehdr *, u_int _shn, const char *_sn);
119static int elf2nlist(Elf_Sym *, Elf_Ehdr *, Elf_Shdr *, char *_shstr,
120	    struct xnlist *_np);
121static int elf_symloadx(const char *_name, FILE *, off_t, Elf_Ehdr *,
122	    Elf_Shdr *, char *_shstr, long _shstrsize, struct xnlist **_pnames,
123	    struct xnlist ***_psnames, size_t *_pstabsize, int *_pnrawnames,
124	    const char *_strtab, const char *_symtab);
125
126int
127elf_fix_header(Elf_Ehdr *eh)
128{
129	/* nothing to do */
130	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
131		return (0);
132
133	eh->e_type = swap16(eh->e_type);
134	eh->e_machine = swap16(eh->e_machine);
135	eh->e_version = swap32(eh->e_version);
136	eh->e_entry = swap_addr(eh->e_entry);
137	eh->e_phoff = swap_off(eh->e_phoff);
138	eh->e_shoff = swap_off(eh->e_shoff);
139	eh->e_flags = swap32(eh->e_flags);
140	eh->e_ehsize = swap16(eh->e_ehsize);
141	eh->e_phentsize = swap16(eh->e_phentsize);
142	eh->e_phnum = swap16(eh->e_phnum);
143	eh->e_shentsize = swap16(eh->e_shentsize);
144	eh->e_shnum = swap16(eh->e_shnum);
145	eh->e_shstrndx = swap16(eh->e_shstrndx);
146
147	return (1);
148}
149
150Elf_Shdr *
151elf_load_shdrs(const char *name, FILE *fp, off_t foff, Elf_Ehdr *head)
152{
153	Elf_Shdr *shdr;
154
155	elf_fix_header(head);
156
157	if (head->e_shnum == 0) {
158		warnx("%s: no section header table", name);
159		return (NULL);
160	}
161
162	if (head->e_shstrndx >= head->e_shnum) {
163		warnx("%s: inconsistent section header table", name);
164		return (NULL);
165	}
166
167	if (head->e_shentsize < sizeof(Elf_Shdr)) {
168		warnx("%s: inconsistent section header size", name);
169		return (NULL);
170	}
171
172	if ((shdr = calloc(head->e_shnum, head->e_shentsize)) == NULL) {
173		warn("%s: malloc shdr", name);
174		return (NULL);
175	}
176
177	if (fseeko(fp, foff + head->e_shoff, SEEK_SET)) {
178		warn("%s: fseeko", name);
179		free(shdr);
180		return (NULL);
181	}
182
183	if (fread(shdr, head->e_shentsize, head->e_shnum, fp) != head->e_shnum) {
184		warnx("%s: premature EOF", name);
185		free(shdr);
186		return (NULL);
187	}
188
189	elf_fix_shdrs(head, shdr);
190	return (shdr);
191}
192
193int
194elf_fix_shdrs(Elf_Ehdr *eh, Elf_Shdr *shdr)
195{
196	int i;
197
198	/* nothing to do */
199	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
200		return (0);
201
202	for (i = eh->e_shnum; i--; shdr++) {
203		shdr->sh_name = swap32(shdr->sh_name);
204		shdr->sh_type = swap32(shdr->sh_type);
205		shdr->sh_flags = swap_xword(shdr->sh_flags);
206		shdr->sh_addr = swap_addr(shdr->sh_addr);
207		shdr->sh_offset = swap_off(shdr->sh_offset);
208		shdr->sh_size = swap_xword(shdr->sh_size);
209		shdr->sh_link = swap32(shdr->sh_link);
210		shdr->sh_info = swap32(shdr->sh_info);
211		shdr->sh_addralign = swap_xword(shdr->sh_addralign);
212		shdr->sh_entsize = swap_xword(shdr->sh_entsize);
213	}
214
215	return (1);
216}
217
218int
219elf_fix_sym(Elf_Ehdr *eh, Elf_Sym *sym)
220{
221	/* nothing to do */
222	if (eh->e_ident[EI_DATA] == ELF_TARG_DATA)
223		return (0);
224
225	sym->st_name = swap32(sym->st_name);
226	sym->st_shndx = swap16(sym->st_shndx);
227	sym->st_value = swap_addr(sym->st_value);
228	sym->st_size = swap_xword(sym->st_size);
229
230	return (1);
231}
232
233int
234elf_shn2type(Elf_Ehdr *eh, u_int shn, const char *sn)
235{
236	switch (shn) {
237	case SHN_MIPS_SUNDEFINED:
238		if (eh->e_machine == EM_MIPS)
239			return (N_UNDF | N_EXT);
240		break;
241
242	case SHN_UNDEF:
243		return (N_UNDF | N_EXT);
244
245	case SHN_ABS:
246		return (N_ABS);
247
248	case SHN_MIPS_ACOMMON:
249		if (eh->e_machine == EM_MIPS)
250			return (N_COMM);
251		break;
252
253	case SHN_MIPS_SCOMMON:
254		if (eh->e_machine == EM_MIPS)
255			return (N_COMM);
256		break;
257
258	case SHN_COMMON:
259		return (N_COMM);
260
261	case SHN_MIPS_TEXT:
262		if (eh->e_machine == EM_MIPS)
263			return (N_TEXT);
264		break;
265
266	case SHN_MIPS_DATA:
267		if (eh->e_machine == EM_MIPS)
268			return (N_DATA);
269		break;
270
271	default:
272		/* TODO: beyond 8 a table-driven binsearch should be used */
273		if (sn == NULL)
274			return (-1);
275		else if (!strcmp(sn, ELF_TEXT))
276			return (N_TEXT);
277		else if (!strncmp(sn, ".text.", 6))
278			return (N_TEXT);
279		else if (!strcmp(sn, ELF_RODATA))
280			return (N_SIZE);
281		else if (!strcmp(sn, ELF_OPENBSDRANDOMDATA))
282			return (N_SIZE);
283		else if (!strcmp(sn, ELF_DATA))
284			return (N_DATA);
285		else if (!strcmp(sn, ELF_SDATA))
286			return (N_DATA);
287		else if (!strcmp(sn, ELF_TDATA))
288			return (N_DATA);
289		else if (!strcmp(sn, ELF_BSS))
290			return (N_BSS);
291		else if (!strcmp(sn, ELF_SBSS))
292			return (N_BSS);
293		else if (!strcmp(sn, ELF_TBSS))
294			return (N_BSS);
295		else if (!strncmp(sn, ELF_GOT, sizeof(ELF_GOT) - 1))
296			return (N_DATA);
297		else if (!strncmp(sn, ELF_PLT, sizeof(ELF_PLT) - 1))
298			return (N_DATA);
299	}
300
301	return (-1);
302}
303
304/*
305 * Devise xnlist's type from Elf_Sym.
306 * XXX this task is done as well in libc and kvm_mkdb.
307 */
308int
309elf2nlist(Elf_Sym *sym, Elf_Ehdr *eh, Elf_Shdr *shdr, char *shstr,
310    struct xnlist *np)
311{
312	u_char stt;
313	const char *sn;
314	int type;
315
316	if (sym->st_shndx < eh->e_shnum)
317		sn = shstr + shdr[sym->st_shndx].sh_name;
318	else
319		sn = NULL;
320#if 0
321	{
322		extern char *stab;
323		printf("%d:%s %d %d %s\n", sym->st_shndx, sn? sn : "",
324		    ELF_ST_TYPE(sym->st_info), ELF_ST_BIND(sym->st_info),
325		    stab + sym->st_name);
326	}
327#endif
328
329	switch (stt = ELF_ST_TYPE(sym->st_info)) {
330	case STT_NOTYPE:
331	case STT_OBJECT:
332	case STT_TLS:
333		type = elf_shn2type(eh, sym->st_shndx, sn);
334		if (type < 0) {
335			if (sn == NULL)
336				np->nl.n_other = '?';
337			else
338				np->nl.n_type = stt == STT_NOTYPE ?
339				    N_COMM : N_DATA;
340		} else {
341			/* a hack for .rodata check (; */
342			if (type == N_SIZE) {
343				np->nl.n_type = N_DATA;
344				np->nl.n_other = 'r';
345			} else
346				np->nl.n_type = type;
347		}
348		if (ELF_ST_BIND(sym->st_info) == STB_WEAK)
349			np->nl.n_other = 'W';
350		break;
351
352	case STT_FUNC:
353		type = elf_shn2type(eh, sym->st_shndx, NULL);
354		np->nl.n_type = type < 0? N_TEXT : type;
355		if (ELF_ST_BIND(sym->st_info) == STB_WEAK) {
356			np->nl.n_other = 'W';
357		} else if (sn != NULL && *sn != 0 &&
358		    strcmp(sn, ELF_INIT) &&
359		    strcmp(sn, ELF_TEXT) &&
360		    strncmp(sn, ".text.", 6) &&
361		    strcmp(sn, ELF_FINI))	/* XXX GNU compat */
362			np->nl.n_other = '?';
363		break;
364
365	case STT_SECTION:
366		type = elf_shn2type(eh, sym->st_shndx, NULL);
367		if (type < 0)
368			np->nl.n_other = '?';
369		else
370			np->nl.n_type = type;
371		break;
372
373	case STT_FILE:
374		np->nl.n_type = N_FN | N_EXT;
375		break;
376
377	case STT_PARISC_MILLI:
378		if (eh->e_machine == EM_PARISC)
379			np->nl.n_type = N_TEXT;
380		else
381			np->nl.n_other = '?';
382		break;
383
384	default:
385		np->nl.n_other = '?';
386		break;
387	}
388	if (np->nl.n_type != N_UNDF && ELF_ST_BIND(sym->st_info) != STB_LOCAL) {
389		np->nl.n_type |= N_EXT;
390		if (np->nl.n_other)
391			np->nl.n_other = toupper((unsigned char)np->nl.n_other);
392	}
393
394	return (0);
395}
396
397int
398elf_size(Elf_Ehdr *head, Elf_Shdr *shdr,
399    u_long *ptext, u_long *pdata, u_long *pbss)
400{
401	int i;
402
403	*ptext = *pdata = *pbss = 0;
404
405	for (i = 0; i < head->e_shnum; i++) {
406		if (!(shdr[i].sh_flags & SHF_ALLOC))
407			;
408		else if (shdr[i].sh_flags & SHF_EXECINSTR ||
409		    !(shdr[i].sh_flags & SHF_WRITE))
410			*ptext += shdr[i].sh_size;
411		else if (shdr[i].sh_type == SHT_NOBITS)
412			*pbss += shdr[i].sh_size;
413		else
414			*pdata += shdr[i].sh_size;
415	}
416
417	return (0);
418}
419
420int
421elf_symloadx(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
422    Elf_Shdr *shdr, char *shstr, long shstrsize, struct xnlist **pnames,
423    struct xnlist ***psnames, size_t *pstabsize, int *pnrawnames,
424    const char *strtab, const char *symtab)
425{
426	long symsize;
427	struct xnlist *np;
428	Elf_Sym sbuf;
429	int i;
430
431	for (i = 0; i < eh->e_shnum; i++) {
432		if (shdr[i].sh_name >= shstrsize) {
433			warnx("%s: corrupt file", name);
434			return (1);
435		}
436		if (!strcmp(shstr + shdr[i].sh_name, strtab)) {
437			*pstabsize = shdr[i].sh_size;
438			if (*pstabsize > SIZE_MAX) {
439				warnx("%s: corrupt file", name);
440				return (1);
441			}
442
443			MMAP(stab, *pstabsize, PROT_READ, MAP_PRIVATE|MAP_FILE,
444			    fileno(fp), foff + shdr[i].sh_offset);
445			if (stab == MAP_FAILED)
446				return (1);
447		}
448	}
449	for (i = 0; i < eh->e_shnum; i++) {
450		if (!strcmp(shstr + shdr[i].sh_name, symtab)) {
451			symsize = shdr[i].sh_size;
452			if (fseeko(fp, foff + shdr[i].sh_offset, SEEK_SET)) {
453				warn("%s: fseeko", name);
454				if (stab)
455					MUNMAP(stab, *pstabsize);
456				return (1);
457			}
458
459			*pnrawnames = symsize / sizeof(sbuf);
460			if ((*pnames = calloc(*pnrawnames, sizeof(*np))) == NULL) {
461				warn("%s: malloc names", name);
462				if (stab)
463					MUNMAP(stab, *pstabsize);
464				*pnrawnames = 0;
465				return (1);
466			}
467			if ((*psnames = calloc(*pnrawnames, sizeof(np))) == NULL) {
468				warn("%s: malloc snames", name);
469				if (stab)
470					MUNMAP(stab, *pstabsize);
471				free(*pnames);
472				*pnames = NULL;
473				*pnrawnames = 0;
474				return (1);
475			}
476
477			for (np = *pnames; symsize > 0; symsize -= sizeof(sbuf)) {
478				if (fread(&sbuf, 1, sizeof(sbuf),
479				    fp) != sizeof(sbuf)) {
480					warn("%s: read symbol", name);
481					if (stab)
482						MUNMAP(stab, *pstabsize);
483					free(*pnames);
484					free(*psnames);
485					*pnames = NULL;
486					*psnames = NULL;
487					*pnrawnames = 0;
488					return (1);
489				}
490
491				elf_fix_sym(eh, &sbuf);
492
493				if (!sbuf.st_name ||
494				    sbuf.st_name > *pstabsize)
495					continue;
496
497				elf2nlist(&sbuf, eh, shdr, shstr, np);
498				np->nl.n_value = sbuf.st_value;
499				np->nl.n_un.n_strx = sbuf.st_name;
500				np->n_size = sbuf.st_size;
501				np++;
502			}
503			*pnrawnames = np - *pnames;
504		}
505	}
506	return (0);
507}
508
509int
510elf_symload(const char *name, FILE *fp, off_t foff, Elf_Ehdr *eh,
511    Elf_Shdr *shdr, struct xnlist **pnames, struct xnlist ***psnames,
512    size_t *pstabsize, int *pnrawnames)
513{
514	long shstrsize;
515	char *shstr;
516
517	shstrsize = shdr[eh->e_shstrndx].sh_size;
518	if (shstrsize == 0) {
519		warnx("%s: no name list", name);
520		return (1);
521	}
522
523	if ((shstr = malloc(shstrsize)) == NULL) {
524		warn("%s: malloc shstr", name);
525		return (1);
526	}
527
528	if (fseeko(fp, foff + shdr[eh->e_shstrndx].sh_offset, SEEK_SET)) {
529		warn("%s: fseeko", name);
530		free(shstr);
531		return (1);
532	}
533
534	if (fread(shstr, 1, shstrsize, fp) != shstrsize) {
535		warnx("%s: premature EOF", name);
536		free(shstr);
537		return(1);
538	}
539
540	stab = NULL;
541	*pnames = NULL; *psnames = NULL; *pnrawnames = 0;
542	if (!dynamic_only) {
543		elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames,
544		    psnames, pstabsize, pnrawnames, ELF_STRTAB, ELF_SYMTAB);
545	}
546	if (stab == NULL) {
547		elf_symloadx(name, fp, foff, eh, shdr, shstr, shstrsize, pnames,
548		    psnames, pstabsize, pnrawnames, ELF_DYNSTR, ELF_DYNSYM);
549	}
550
551	free(shstr);
552	if (stab == NULL) {
553		warnx("%s: no name list", name);
554		free(*pnames);
555		free(*psnames);
556		return (1);
557	}
558
559	return (0);
560}
561