elfdump.c revision 109313
1/*-
2 * Copyright (c) 2001 Jake Burkholder
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/usr.bin/elfdump/elfdump.c 109313 2003-01-15 18:32:06Z obrien $");
29
30#include <sys/types.h>
31#include <sys/elf32.h>
32#include <sys/elf64.h>
33#include <sys/mman.h>
34#include <sys/stat.h>
35#include <err.h>
36#include <fcntl.h>
37#include <stddef.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43#define	ED_DYN		(1<<0)
44#define	ED_EHDR		(1<<1)
45#define	ED_GOT		(1<<2)
46#define	ED_HASH		(1<<3)
47#define	ED_INTERP	(1<<4)
48#define	ED_NOTE		(1<<5)
49#define	ED_PHDR		(1<<6)
50#define	ED_REL		(1<<7)
51#define	ED_SHDR		(1<<8)
52#define	ED_SYMTAB	(1<<9)
53#define	ED_ALL		((1<<10)-1)
54
55#define	elf_get_addr	elf_get_quad
56#define	elf_get_off	elf_get_quad
57#define	elf_get_size	elf_get_quad
58
59enum elf_member {
60	D_TAG = 1, D_PTR, D_VAL,
61
62	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
63	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
64	E_SHNUM, E_SHSTRNDX,
65
66	N_NAMESZ, N_DESCSZ, N_TYPE,
67
68	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
69	P_ALIGN,
70
71	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
72	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
73
74	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
75
76	R_OFFSET, R_INFO,
77
78	RA_OFFSET, RA_INFO, RA_ADDEND
79};
80
81typedef enum elf_member elf_member_t;
82
83int elf32_offsets[] = {
84	0,
85
86	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
87	offsetof(Elf32_Dyn, d_un.d_val),
88
89	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
90	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
91	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
92	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
93	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
94	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
95	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
96	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
97	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
98	offsetof(Elf32_Ehdr, e_shstrndx),
99
100	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
101	offsetof(Elf_Note, n_type),
102
103	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
104	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
105	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
106	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
107
108	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
109	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
110	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
111	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
112	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
113
114	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
115	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
116	offsetof(Elf32_Sym, st_shndx),
117
118	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
119
120	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
121	offsetof(Elf32_Rela, r_addend)
122};
123
124int elf64_offsets[] = {
125	0,
126
127	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
128	offsetof(Elf64_Dyn, d_un.d_val),
129
130	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
131	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
132	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
133	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
134	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
135	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
136	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
137	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
138	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
139	offsetof(Elf64_Ehdr, e_shstrndx),
140
141	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
142	offsetof(Elf_Note, n_type),
143
144	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
145	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
146	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
147	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
148
149	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
150	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
151	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
152	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
153	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
154
155	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
156	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
157	offsetof(Elf64_Sym, st_shndx),
158
159	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
160
161	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
162	offsetof(Elf64_Rela, r_addend)
163};
164
165char *d_tags[] = {
166	"DT_NULL", "DT_NEEDED", "DT_PLTRELSZ", "DT_PLTGOT", "DT_HASH",
167	"DT_STRTAB", "DT_SYMTAB", "DT_RELA", "DT_RELASZ", "DT_RELAENT",
168	"DT_STRSZ", "DT_SYMENT", "DT_INIT", "DT_FINI", "DT_SONAME",
169	"DT_RPATH", "DT_SYMBOLIC", "DT_REL", "DT_RELSZ", "DT_RELENT",
170	"DT_PLTREL", "DT_DEBUG", "DT_TEXTREL", "DT_JMPREL"
171};
172
173char *e_machines[] = {
174	"EM_NONE", "EM_M32", "EM_SPARC", "EM_386", "EM_68K", "EM_88K",
175	"EM_486", "EM_860", "EM_MIPS"
176};
177
178char *e_types[] = {
179	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
180};
181
182char *ei_versions[] = {
183	"EV_NONE", "EV_CURRENT"
184};
185
186char *ei_classes[] = {
187	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
188};
189
190char *ei_data[] = {
191	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
192};
193
194char *ei_abis[] = {
195	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
196	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS",
197	"ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD",
198	"ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD"
199};
200
201char *p_types[] = {
202	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
203	"PT_SHLIB", "PT_PHDR"
204};
205
206char *p_flags[] = {
207	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
208	"PF_X|PF_W|PF_R"
209};
210
211char *sh_types[] = {
212	"SHT_NULL", "SHT_PROGBITS", "SHT_SYMTAB", "SHT_STRTAB",
213	"SHT_RELA", "SHT_HASH", "SHT_DYNAMIC", "SHT_NOTE", "SHT_NOBITS",
214	"SHT_REL", "SHT_SHLIB", "SHT_DYNSYM"
215};
216
217char *sh_flags[] = {
218	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
219	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
220	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
221};
222
223char *st_types[] = {
224	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
225};
226
227char *st_bindings[] = {
228	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
229};
230
231char *dynstr;
232char *shstrtab;
233char *strtab;
234FILE *out;
235
236u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
237u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member);
238u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
239u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
240u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
241
242void elf_print_ehdr(void *e);
243void elf_print_phdr(void *e, void *p);
244void elf_print_shdr(void *e, void *sh);
245void elf_print_symtab(void *e, void *sh, char *str);
246void elf_print_dynamic(void *e, void *sh);
247void elf_print_rel(void *e, void *r);
248void elf_print_rela(void *e, void *ra);
249void elf_print_interp(void *e, void *p);
250void elf_print_got(void *e, void *sh);
251void elf_print_hash(void *e, void *sh);
252void elf_print_note(void *e, void *sh);
253
254void usage(void);
255
256int
257main(int ac, char **av)
258{
259	u_int64_t phoff;
260	u_int64_t shoff;
261	u_int64_t phentsize;
262	u_int64_t phnum;
263	u_int64_t shentsize;
264	u_int64_t shnum;
265	u_int64_t shstrndx;
266	u_int64_t offset;
267	u_int64_t name;
268	u_int64_t type;
269	struct stat sb;
270	u_int flags;
271	void *e;
272	void *p;
273	void *sh;
274	void *v;
275	int fd;
276	int ch;
277	int i;
278
279	out = stdout;
280	flags = 0;
281	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
282		switch (ch) {
283		case 'a':
284			flags = ED_ALL;
285			break;
286		case 'c':
287			flags |= ED_SHDR;
288			break;
289		case 'd':
290			flags |= ED_DYN;
291			break;
292		case 'e':
293			flags |= ED_EHDR;
294			break;
295		case 'i':
296			flags |= ED_INTERP;
297			break;
298		case 'G':
299			flags |= ED_GOT;
300			break;
301		case 'h':
302			flags |= ED_HASH;
303			break;
304		case 'n':
305			flags |= ED_NOTE;
306			break;
307		case 'p':
308			flags |= ED_PHDR;
309			break;
310		case 'r':
311			flags |= ED_REL;
312			break;
313		case 's':
314			flags |= ED_SYMTAB;
315			break;
316		case 'w':
317			if ((out = fopen(optarg, "w")) == NULL)
318				err(1, "%s", optarg);
319			break;
320		case '?':
321		default:
322			usage();
323		}
324	ac -= optind;
325	av += optind;
326	if (ac == 0 || flags == 0)
327		usage();
328	if ((fd = open(*av, O_RDONLY)) < 0 ||
329	    fstat(fd, &sb) < 0)
330		err(1, NULL);
331	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
332	if (e == MAP_FAILED)
333		err(1, NULL);
334	if (!IS_ELF(*(Elf32_Ehdr *)e))
335		errx(1, "not an elf file");
336	phoff = elf_get_off(e, e, E_PHOFF);
337	shoff = elf_get_off(e, e, E_SHOFF);
338	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
339	phnum = elf_get_quarter(e, e, E_PHNUM);
340	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
341	shnum = elf_get_quarter(e, e, E_SHNUM);
342	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
343	p = e + phoff;
344	sh = e + shoff;
345	offset = elf_get_off(e, sh + shstrndx * shentsize, SH_OFFSET);
346	shstrtab = e + offset;
347	for (i = 0; i < shnum; i++) {
348		name = elf_get_word(e, sh + i * shentsize, SH_NAME);
349		offset = elf_get_off(e, sh + i * shentsize, SH_OFFSET);
350		if (strcmp(shstrtab + name, ".strtab") == 0)
351			strtab = e + offset;
352		if (strcmp(shstrtab + name, ".dynstr") == 0)
353			dynstr = e + offset;
354	}
355	if (flags & ED_EHDR)
356		elf_print_ehdr(e);
357	if (flags & ED_PHDR)
358		elf_print_phdr(e, p);
359	if (flags & ED_SHDR)
360		elf_print_shdr(e, sh);
361	for (i = 0; i < phnum; i++) {
362		v = p + i * phentsize;
363		type = elf_get_word(e, v, P_TYPE);
364		switch (type) {
365		case PT_INTERP:
366			if (flags & ED_INTERP)
367				elf_print_interp(e, v);
368			break;
369		case PT_NULL:
370		case PT_LOAD:
371		case PT_DYNAMIC:
372		case PT_NOTE:
373		case PT_SHLIB:
374		case PT_PHDR:
375			break;
376		}
377	}
378	for (i = 0; i < shnum; i++) {
379		v = sh + i * shentsize;
380		type = elf_get_word(e, v, SH_TYPE);
381		switch (type) {
382		case SHT_SYMTAB:
383			if (flags & ED_SYMTAB)
384				elf_print_symtab(e, v, strtab);
385			break;
386		case SHT_DYNAMIC:
387			if (flags & ED_DYN)
388				elf_print_dynamic(e, v);
389			break;
390		case SHT_RELA:
391			if (flags & ED_REL)
392				elf_print_rela(e, v);
393			break;
394		case SHT_REL:
395			if (flags & ED_REL)
396				elf_print_rel(e, v);
397			break;
398		case SHT_NOTE:
399			name = elf_get_word(e, v, SH_NAME);
400			if (flags & ED_NOTE &&
401			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
402				elf_print_note(e, v);
403			break;
404		case SHT_DYNSYM:
405			if (flags & ED_SYMTAB)
406				elf_print_symtab(e, v, dynstr);
407			break;
408		case SHT_PROGBITS:
409			name = elf_get_word(e, v, SH_NAME);
410			if (flags & ED_GOT &&
411			    strcmp(shstrtab + name, ".got") == 0)
412				elf_print_got(e, v);
413			break;
414		case SHT_HASH:
415			if (flags & ED_HASH)
416				elf_print_hash(e, v);
417			break;
418		case SHT_NULL:
419		case SHT_STRTAB:
420		case SHT_NOBITS:
421		case SHT_SHLIB:
422			break;
423		}
424	}
425
426	return 0;
427}
428
429void
430elf_print_ehdr(void *e)
431{
432	u_int64_t class;
433	u_int64_t data;
434	u_int64_t osabi;
435	u_int64_t type;
436	u_int64_t machine;
437	u_int64_t version;
438	u_int64_t entry;
439	u_int64_t phoff;
440	u_int64_t shoff;
441	u_int64_t flags;
442	u_int64_t ehsize;
443	u_int64_t phentsize;
444	u_int64_t phnum;
445	u_int64_t shentsize;
446	u_int64_t shnum;
447	u_int64_t shstrndx;
448
449	class = elf_get_byte(e, e, E_CLASS);
450	data = elf_get_byte(e, e, E_DATA);
451	osabi = elf_get_byte(e, e, E_OSABI);
452	type = elf_get_quarter(e, e, E_TYPE);
453	machine = elf_get_quarter(e, e, E_MACHINE);
454	version = elf_get_word(e, e, E_VERSION);
455	entry = elf_get_addr(e, e, E_ENTRY);
456	phoff = elf_get_off(e, e, E_PHOFF);
457	shoff = elf_get_off(e, e, E_SHOFF);
458	flags = elf_get_word(e, e, E_FLAGS);
459	ehsize = elf_get_quarter(e, e, E_EHSIZE);
460	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
461	phnum = elf_get_quarter(e, e, E_PHNUM);
462	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
463	shnum = elf_get_quarter(e, e, E_SHNUM);
464	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
465	fprintf(out, "\nelf header:\n");
466	fprintf(out, "\n");
467	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
468	    ei_abis[osabi]);
469	fprintf(out, "\te_type: %s\n", e_types[type]);
470	if (machine < sizeof e_machines / sizeof *e_machines)
471		fprintf(out, "\te_machine: %s\n", e_machines[machine]);
472	else
473		fprintf(out, "\te_machine: %lld\n", machine);
474	fprintf(out, "\te_version: %s\n", ei_versions[version]);
475	fprintf(out, "\te_entry: %#llx\n", entry);
476	fprintf(out, "\te_phoff: %lld\n", phoff);
477	fprintf(out, "\te_shoff: %lld\n", shoff);
478	fprintf(out, "\te_flags: %lld\n", flags);
479	fprintf(out, "\te_ehsize: %lld\n", ehsize);
480	fprintf(out, "\te_phentsize: %lld\n", phentsize);
481	fprintf(out, "\te_phnum: %lld\n", phnum);
482	fprintf(out, "\te_shentsize: %lld\n", shentsize);
483	fprintf(out, "\te_shnum: %lld\n", shnum);
484	fprintf(out, "\te_shstrndx: %lld\n", shstrndx);
485}
486
487void
488elf_print_phdr(void *e, void *p)
489{
490	u_int64_t phentsize;
491	u_int64_t phnum;
492	u_int64_t type;
493	u_int64_t offset;
494	u_int64_t vaddr;
495	u_int64_t paddr;
496	u_int64_t filesz;
497	u_int64_t memsz;
498	u_int64_t flags;
499	u_int64_t align;
500	void *v;
501	int i;
502
503	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
504	phnum = elf_get_quarter(e, e, E_PHNUM);
505	fprintf(out, "\nprogram header:\n");
506	for (i = 0; i < phnum; i++) {
507		v = p + i * phentsize;
508		type = elf_get_word(e, v, P_TYPE);
509		offset = elf_get_off(e, v, P_OFFSET);
510		vaddr = elf_get_addr(e, v, P_VADDR);
511		paddr = elf_get_addr(e, v, P_PADDR);
512		filesz = elf_get_size(e, v, P_FILESZ);
513		memsz = elf_get_size(e, v, P_MEMSZ);
514		flags = elf_get_word(e, v, P_FLAGS);
515		align = elf_get_size(e, v, P_ALIGN);
516		fprintf(out, "\n");
517		fprintf(out, "entry: %d\n", i);
518		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
519		fprintf(out, "\tp_offset: %lld\n", offset);
520		fprintf(out, "\tp_vaddr: %#llx\n", vaddr);
521		fprintf(out, "\tp_paddr: %#llx\n", paddr);
522		fprintf(out, "\tp_filesz: %lld\n", filesz);
523		fprintf(out, "\tp_memsz: %lld\n", memsz);
524		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
525		fprintf(out, "\tp_align: %lld\n", align);
526	}
527}
528
529void
530elf_print_shdr(void *e, void *sh)
531{
532	u_int64_t shentsize;
533	u_int64_t shnum;
534	u_int64_t name;
535	u_int64_t type;
536	u_int64_t flags;
537	u_int64_t addr;
538	u_int64_t offset;
539	u_int64_t size;
540	u_int64_t link;
541	u_int64_t info;
542	u_int64_t addralign;
543	u_int64_t entsize;
544	void *v;
545	int i;
546
547	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
548	shnum = elf_get_quarter(e, e, E_SHNUM);
549	fprintf(out, "\nsection header:\n");
550	for (i = 0; i < shnum; i++) {
551		v = sh + i * shentsize;
552		name = elf_get_word(e, v, SH_NAME);
553		type = elf_get_word(e, v, SH_TYPE);
554		flags = elf_get_word(e, v, SH_FLAGS);
555		addr = elf_get_addr(e, v, SH_ADDR);
556		offset = elf_get_off(e, v, SH_OFFSET);
557		size = elf_get_size(e, v, SH_SIZE);
558		link = elf_get_word(e, v, SH_LINK);
559		info = elf_get_word(e, v, SH_INFO);
560		addralign = elf_get_size(e, v, SH_ADDRALIGN);
561		entsize = elf_get_size(e, v, SH_ENTSIZE);
562		fprintf(out, "\n");
563		fprintf(out, "entry: %d\n", i);
564		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
565		fprintf(out, "\tsh_type: %s\n", sh_types[type]);
566		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
567		fprintf(out, "\tsh_addr: %#llx\n", addr);
568		fprintf(out, "\tsh_offset: %lld\n", offset);
569		fprintf(out, "\tsh_size: %lld\n", size);
570		fprintf(out, "\tsh_link: %lld\n", link);
571		fprintf(out, "\tsh_info: %lld\n", info);
572		fprintf(out, "\tsh_addralign: %lld\n", addralign);
573		fprintf(out, "\tsh_entsize: %lld\n", entsize);
574	}
575}
576
577void
578elf_print_symtab(void *e, void *sh, char *str)
579{
580	u_int64_t offset;
581	u_int64_t entsize;
582	u_int64_t size;
583	u_int64_t name;
584	u_int64_t value;
585	u_int64_t info;
586	u_int64_t shndx;
587	void *st;
588	int len;
589	int i;
590
591	offset = elf_get_off(e, sh, SH_OFFSET);
592	entsize = elf_get_size(e, sh, SH_ENTSIZE);
593	size = elf_get_size(e, sh, SH_SIZE);
594	name = elf_get_word(e, sh, SH_NAME);
595	len = size / entsize;
596	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
597	for (i = 0; i < len; i++) {
598		st = e + offset + i * entsize;
599		name = elf_get_word(e, st, ST_NAME);
600		value = elf_get_addr(e, st, ST_VALUE);
601		size = elf_get_size(e, st, ST_SIZE);
602		info = elf_get_byte(e, st, ST_INFO);
603		shndx = elf_get_quarter(e, st, ST_SHNDX);
604		fprintf(out, "\n");
605		fprintf(out, "entry: %d\n", i);
606		fprintf(out, "\tst_name: %s\n", str + name);
607		fprintf(out, "\tst_value: %#llx\n", value);
608		fprintf(out, "\tst_size: %lld\n", size);
609		fprintf(out, "\tst_info: %s %s\n",
610		    st_types[ELF32_ST_TYPE(info)],
611		    st_bindings[ELF32_ST_BIND(info)]);
612		fprintf(out, "\tst_shndx: %lld\n", shndx);
613	}
614}
615
616void
617elf_print_dynamic(void *e, void *sh)
618{
619	u_int64_t offset;
620	u_int64_t entsize;
621	u_int64_t size;
622	int64_t tag;
623	u_int64_t ptr;
624	u_int64_t val;
625	void *d;
626	int i;
627
628	offset = elf_get_off(e, sh, SH_OFFSET);
629	entsize = elf_get_size(e, sh, SH_ENTSIZE);
630	size = elf_get_size(e, sh, SH_SIZE);
631	fprintf(out, "\ndynamic:\n");
632	for (i = 0; i < size / entsize; i++) {
633		d = e + offset + i * entsize;
634		tag = elf_get_size(e, d, D_TAG);
635		ptr = elf_get_size(e, d, D_PTR);
636		val = elf_get_addr(e, d, D_VAL);
637		fprintf(out, "\n");
638		fprintf(out, "entry: %d\n", i);
639		fprintf(out, "\td_tag: %s\n", d_tags[tag]);
640		switch (tag) {
641		case DT_NEEDED:
642		case DT_SONAME:
643		case DT_RPATH:
644			fprintf(out, "\td_val: %s\n", dynstr + val);
645			break;
646		case DT_PLTRELSZ:
647		case DT_RELA:
648		case DT_RELASZ:
649		case DT_RELAENT:
650		case DT_STRSZ:
651		case DT_SYMENT:
652		case DT_RELSZ:
653		case DT_RELENT:
654		case DT_PLTREL:
655			fprintf(out, "\td_val: %lld\n", val);
656			break;
657		case DT_PLTGOT:
658		case DT_HASH:
659		case DT_STRTAB:
660		case DT_SYMTAB:
661		case DT_INIT:
662		case DT_FINI:
663		case DT_REL:
664		case DT_JMPREL:
665			fprintf(out, "\td_ptr: %#llx\n", ptr);
666			break;
667		case DT_NULL:
668		case DT_SYMBOLIC:
669		case DT_DEBUG:
670		case DT_TEXTREL:
671			break;
672		}
673	}
674}
675
676void
677elf_print_rela(void *e, void *sh)
678{
679	u_int64_t offset;
680	u_int64_t entsize;
681	u_int64_t size;
682	u_int64_t name;
683	u_int64_t info;
684	int64_t addend;
685	void *ra;
686	void *v;
687	int i;
688
689	offset = elf_get_off(e, sh, SH_OFFSET);
690	entsize = elf_get_size(e, sh, SH_ENTSIZE);
691	size = elf_get_size(e, sh, SH_SIZE);
692	name = elf_get_word(e, sh, SH_NAME);
693	v = e + offset;
694	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
695	for (i = 0; i < size / entsize; i++) {
696		ra = v + i * entsize;
697		offset = elf_get_addr(e, ra, RA_OFFSET);
698		info = elf_get_word(e, ra, RA_INFO);
699		addend = elf_get_off(e, ra, RA_ADDEND);
700		fprintf(out, "\n");
701		fprintf(out, "entry: %d\n", i);
702		fprintf(out, "\tr_offset: %#llx\n", offset);
703		fprintf(out, "\tr_info: %lld\n", info);
704		fprintf(out, "\tr_addend: %lld\n", addend);
705	}
706}
707
708void
709elf_print_rel(void *e, void *sh)
710{
711	u_int64_t offset;
712	u_int64_t entsize;
713	u_int64_t size;
714	u_int64_t name;
715	u_int64_t info;
716	void *r;
717	void *v;
718	int i;
719
720	offset = elf_get_off(e, sh, SH_OFFSET);
721	entsize = elf_get_size(e, sh, SH_ENTSIZE);
722	size = elf_get_size(e, sh, SH_SIZE);
723	name = elf_get_word(e, sh, SH_NAME);
724	v = e + offset;
725	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
726	for (i = 0; i < size / entsize; i++) {
727		r = v + i * entsize;
728		offset = elf_get_addr(e, r, R_OFFSET);
729		info = elf_get_word(e, r, R_INFO);
730		fprintf(out, "\n");
731		fprintf(out, "entry: %d\n", i);
732		fprintf(out, "\tr_offset: %#llx\n", offset);
733		fprintf(out, "\tr_info: %lld\n", info);
734	}
735}
736
737void
738elf_print_interp(void *e, void *p)
739{
740	u_int64_t offset;
741	char *s;
742
743	offset = elf_get_off(e, p, P_OFFSET);
744	s = e + offset;
745	fprintf(out, "\ninterp:\n");
746	fprintf(out, "\t%s\n", s);
747}
748
749void
750elf_print_got(void *e, void *sh)
751{
752	u_int64_t offset;
753	u_int64_t addralign;
754	u_int64_t size;
755	u_int64_t addr;
756	void *v;
757	int i;
758
759	offset = elf_get_off(e, sh, SH_OFFSET);
760	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
761	size = elf_get_size(e, sh, SH_SIZE);
762	v = e + offset;
763	fprintf(out, "\nglobal offset table:\n");
764	for (i = 0; i < size / addralign; i++) {
765		addr = elf_get_addr(e, v + i * addralign, 0);
766		fprintf(out, "\n");
767		fprintf(out, "entry: %d\n", i);
768		fprintf(out, "\t%#llx\n", addr);
769	}
770}
771
772void
773elf_print_hash(void *e, void *sh)
774{
775}
776
777void
778elf_print_note(void *e, void *sh)
779{
780	u_int64_t offset;
781	u_int64_t size;
782	u_int64_t name;
783	u_int32_t namesz;
784	u_int32_t descsz;
785	u_int32_t type;
786	u_int32_t desc;
787	char *s;
788	void *n;
789
790	offset = elf_get_off(e, sh, SH_OFFSET);
791	size = elf_get_size(e, sh, SH_SIZE);
792	name = elf_get_word(e, sh, SH_NAME);
793	n = e + offset;
794	fprintf(out, "\nnote (%s):\n", shstrtab + name);
795	while (n < e + offset + size) {
796		namesz = elf_get_word(e, n, N_NAMESZ);
797		descsz = elf_get_word(e, n, N_DESCSZ);
798		type = elf_get_word(e, n, N_TYPE);
799		s = n + sizeof(Elf_Note);
800		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
801		fprintf(out, "\t%s %d\n", s, desc);
802		n += sizeof(Elf_Note) + namesz + descsz;
803	}
804}
805
806u_int64_t
807elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
808{
809	u_int64_t val;
810	u_char *p;
811
812	val = 0;
813	switch (e->e_ident[EI_CLASS]) {
814	case ELFCLASS32:
815		p = base + elf32_offsets[member];
816		val = *p;
817		break;
818	case ELFCLASS64:
819		p = base + elf64_offsets[member];
820		val = *p;
821		break;
822	case ELFCLASSNONE:
823		errx(1, "invalid class");
824	}
825
826	return val;
827}
828
829u_int64_t
830elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
831{
832	u_int64_t val;
833	u_char *p;
834
835	val = 0;
836	switch (e->e_ident[EI_CLASS]) {
837	case ELFCLASS32:
838		p = base + elf32_offsets[member];
839		switch (e->e_ident[EI_DATA]) {
840		case ELFDATA2MSB:
841			val = p[0] << 8 | p[1];
842			break;
843		case ELFDATA2LSB:
844			val = p[1] << 8 | p[0];
845			break;
846		case ELFDATANONE:
847			errx(1, "invalid data format");
848		}
849		break;
850	case ELFCLASS64:
851		p = base + elf64_offsets[member];
852		switch (e->e_ident[EI_DATA]) {
853		case ELFDATA2MSB:
854			val = p[0] << 8 | p[1];
855			break;
856		case ELFDATA2LSB:
857			val = p[1] << 8 | p[0];
858			break;
859		case ELFDATANONE:
860			errx(1, "invalid data format");
861		}
862		break;
863	case ELFCLASSNONE:
864		errx(1, "invalid class");
865	}
866
867	return val;
868}
869
870u_int64_t
871elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
872{
873	u_int64_t val;
874	u_char *p;
875
876	val = 0;
877	switch (e->e_ident[EI_CLASS]) {
878	case ELFCLASS32:
879		p = base + elf32_offsets[member];
880		switch (e->e_ident[EI_DATA]) {
881		case ELFDATA2MSB:
882			val = p[0] << 8 | p[1];
883			break;
884		case ELFDATA2LSB:
885			val = p[1] << 8 | p[0];
886			break;
887		case ELFDATANONE:
888			errx(1, "invalid data format");
889		}
890		break;
891	case ELFCLASS64:
892		p = base + elf64_offsets[member];
893		switch (e->e_ident[EI_DATA]) {
894		case ELFDATA2MSB:
895			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
896			break;
897		case ELFDATA2LSB:
898			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
899			break;
900		case ELFDATANONE:
901			errx(1, "invalid data format");
902		}
903		break;
904	case ELFCLASSNONE:
905		errx(1, "invalid class");
906	}
907
908	return val;
909}
910
911u_int64_t
912elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
913{
914	u_int64_t val;
915	u_char *p;
916
917	val = 0;
918	switch (e->e_ident[EI_CLASS]) {
919	case ELFCLASS32:
920		p = base + elf32_offsets[member];
921		switch (e->e_ident[EI_DATA]) {
922		case ELFDATA2MSB:
923			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
924			break;
925		case ELFDATA2LSB:
926			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
927			break;
928		case ELFDATANONE:
929			errx(1, "invalid data format");
930		}
931		break;
932	case ELFCLASS64:
933		p = base + elf64_offsets[member];
934		switch (e->e_ident[EI_DATA]) {
935		case ELFDATA2MSB:
936			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
937			break;
938		case ELFDATA2LSB:
939			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
940			break;
941		case ELFDATANONE:
942			errx(1, "invalid data format");
943		}
944		break;
945	case ELFCLASSNONE:
946		errx(1, "invalid class");
947	}
948
949	return val;
950}
951
952u_int64_t
953elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
954{
955	u_int64_t high;
956	u_int64_t low;
957	u_int64_t val;
958	u_char *p;
959
960	val = 0;
961	switch (e->e_ident[EI_CLASS]) {
962	case ELFCLASS32:
963		p = base + elf32_offsets[member];
964		switch (e->e_ident[EI_DATA]) {
965		case ELFDATA2MSB:
966			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
967			break;
968		case ELFDATA2LSB:
969			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
970			break;
971		case ELFDATANONE:
972			errx(1, "invalid data format");
973		}
974		break;
975	case ELFCLASS64:
976		p = base + elf64_offsets[member];
977		switch (e->e_ident[EI_DATA]) {
978		case ELFDATA2MSB:
979			high = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
980			low = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
981			val = high << 32 | low;
982			break;
983		case ELFDATA2LSB:
984			high = p[7] << 24 | p[6] << 16 | p[5] << 8 | p[4];
985			low = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
986			val = high << 32 | low;
987			break;
988		case ELFDATANONE:
989			errx(1, "invalid data format");
990		}
991		break;
992	case ELFCLASSNONE:
993		errx(1, "invalid class");
994	}
995
996	return val;
997}
998
999void
1000usage(void)
1001{
1002	fprintf(stderr, "usage: elfdump [-acdeiGhnprs] [-w file] filename\n");
1003	exit(1);
1004}
1005