1/*-
2 * Copyright (c) 2003 David O'Brien.  All rights reserved.
3 * Copyright (c) 2001 Jake Burkholder
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 *    notice, this list of conditions and the following disclaimer in the
13 *    documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28#include <sys/cdefs.h>
29__FBSDID("$FreeBSD: stable/10/usr.bin/elfdump/elfdump.c 307834 2016-10-24 00:46:38Z emaste $");
30
31#include <sys/types.h>
32
33#include <sys/capability.h>
34#include <sys/elf32.h>
35#include <sys/elf64.h>
36#include <sys/endian.h>
37#include <sys/mman.h>
38#include <sys/stat.h>
39#include <err.h>
40#include <errno.h>
41#include <fcntl.h>
42#include <inttypes.h>
43#include <stddef.h>
44#include <stdio.h>
45#include <stdlib.h>
46#include <string.h>
47#include <unistd.h>
48
49#define	ED_DYN		(1<<0)
50#define	ED_EHDR		(1<<1)
51#define	ED_GOT		(1<<2)
52#define	ED_HASH		(1<<3)
53#define	ED_INTERP	(1<<4)
54#define	ED_NOTE		(1<<5)
55#define	ED_PHDR		(1<<6)
56#define	ED_REL		(1<<7)
57#define	ED_SHDR		(1<<8)
58#define	ED_SYMTAB	(1<<9)
59#define	ED_ALL		((1<<10)-1)
60
61#define	elf_get_addr	elf_get_quad
62#define	elf_get_off	elf_get_quad
63#define	elf_get_size	elf_get_quad
64
65enum elf_member {
66	D_TAG = 1, D_PTR, D_VAL,
67
68	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
69	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
70	E_SHNUM, E_SHSTRNDX,
71
72	N_NAMESZ, N_DESCSZ, N_TYPE,
73
74	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
75	P_ALIGN,
76
77	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
78	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
79
80	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
81
82	R_OFFSET, R_INFO,
83
84	RA_OFFSET, RA_INFO, RA_ADDEND
85};
86
87typedef enum elf_member elf_member_t;
88
89static int elf32_offsets[] = {
90	0,
91
92	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
93	offsetof(Elf32_Dyn, d_un.d_val),
94
95	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
96	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
97	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
98	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
99	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
100	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
101	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
102	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
103	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
104	offsetof(Elf32_Ehdr, e_shstrndx),
105
106	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
107	offsetof(Elf_Note, n_type),
108
109	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
110	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
111	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
112	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
113
114	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
115	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
116	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
117	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
118	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
119
120	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
121	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
122	offsetof(Elf32_Sym, st_shndx),
123
124	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
125
126	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
127	offsetof(Elf32_Rela, r_addend)
128};
129
130static int elf64_offsets[] = {
131	0,
132
133	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
134	offsetof(Elf64_Dyn, d_un.d_val),
135
136	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
137	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
138	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
139	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
140	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
141	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
142	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
143	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
144	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
145	offsetof(Elf64_Ehdr, e_shstrndx),
146
147	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
148	offsetof(Elf_Note, n_type),
149
150	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
151	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
152	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
153	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
154
155	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
156	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
157	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
158	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
159	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
160
161	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
162	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
163	offsetof(Elf64_Sym, st_shndx),
164
165	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
166
167	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
168	offsetof(Elf64_Rela, r_addend)
169};
170
171/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
172static const char *
173d_tags(u_int64_t tag)
174{
175	static char unknown_tag[48];
176
177	switch (tag) {
178	case DT_NULL:		return "DT_NULL";
179	case DT_NEEDED:		return "DT_NEEDED";
180	case DT_PLTRELSZ:	return "DT_PLTRELSZ";
181	case DT_PLTGOT:		return "DT_PLTGOT";
182	case DT_HASH:		return "DT_HASH";
183	case DT_STRTAB:		return "DT_STRTAB";
184	case DT_SYMTAB:		return "DT_SYMTAB";
185	case DT_RELA:		return "DT_RELA";
186	case DT_RELASZ:		return "DT_RELASZ";
187	case DT_RELAENT:	return "DT_RELAENT";
188	case DT_STRSZ:		return "DT_STRSZ";
189	case DT_SYMENT:		return "DT_SYMENT";
190	case DT_INIT:		return "DT_INIT";
191	case DT_FINI:		return "DT_FINI";
192	case DT_SONAME:		return "DT_SONAME";
193	case DT_RPATH:		return "DT_RPATH";
194	case DT_SYMBOLIC:	return "DT_SYMBOLIC";
195	case DT_REL:		return "DT_REL";
196	case DT_RELSZ:		return "DT_RELSZ";
197	case DT_RELENT:		return "DT_RELENT";
198	case DT_PLTREL:		return "DT_PLTREL";
199	case DT_DEBUG:		return "DT_DEBUG";
200	case DT_TEXTREL:	return "DT_TEXTREL";
201	case DT_JMPREL:		return "DT_JMPREL";
202	case DT_BIND_NOW:	return "DT_BIND_NOW";
203	case DT_INIT_ARRAY:	return "DT_INIT_ARRAY";
204	case DT_FINI_ARRAY:	return "DT_FINI_ARRAY";
205	case DT_INIT_ARRAYSZ:	return "DT_INIT_ARRAYSZ";
206	case DT_FINI_ARRAYSZ:	return "DT_FINI_ARRAYSZ";
207	case DT_RUNPATH:	return "DT_RUNPATH";
208	case DT_FLAGS:		return "DT_FLAGS";
209	case DT_PREINIT_ARRAY:	return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */
210	case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ";
211	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
212	case 0x6ffffdf5:	return "DT_GNU_PRELINKED";
213	case 0x6ffffdf6:	return "DT_GNU_CONFLICTSZ";
214	case 0x6ffffdf7:	return "DT_GNU_LIBLISTSZ";
215	case 0x6ffffdf8:	return "DT_SUNW_CHECKSUM";
216	case DT_PLTPADSZ:	return "DT_PLTPADSZ";
217	case DT_MOVEENT:	return "DT_MOVEENT";
218	case DT_MOVESZ:		return "DT_MOVESZ";
219	case DT_FEATURE:	return "DT_FEATURE";
220	case DT_POSFLAG_1:	return "DT_POSFLAG_1";
221	case DT_SYMINSZ:	return "DT_SYMINSZ";
222	case DT_SYMINENT :	return "DT_SYMINENT (DT_VALRNGHI)";
223	case DT_ADDRRNGLO:	return "DT_ADDRRNGLO";
224	case DT_GNU_HASH:	return "DT_GNU_HASH";
225	case 0x6ffffef8:	return "DT_GNU_CONFLICT";
226	case 0x6ffffef9:	return "DT_GNU_LIBLIST";
227	case DT_CONFIG:		return "DT_CONFIG";
228	case DT_DEPAUDIT:	return "DT_DEPAUDIT";
229	case DT_AUDIT:		return "DT_AUDIT";
230	case DT_PLTPAD:		return "DT_PLTPAD";
231	case DT_MOVETAB:	return "DT_MOVETAB";
232	case DT_SYMINFO :	return "DT_SYMINFO (DT_ADDRRNGHI)";
233	case DT_RELACOUNT:	return "DT_RELACOUNT";
234	case DT_RELCOUNT:	return "DT_RELCOUNT";
235	case DT_FLAGS_1:	return "DT_FLAGS_1";
236	case DT_VERDEF:		return "DT_VERDEF";
237	case DT_VERDEFNUM:	return "DT_VERDEFNUM";
238	case DT_VERNEED:	return "DT_VERNEED";
239	case DT_VERNEEDNUM:	return "DT_VERNEEDNUM";
240	case 0x6ffffff0:	return "DT_GNU_VERSYM";
241	/* 0x70000000 - 0x7fffffff processor-specific semantics */
242	case 0x70000000:	return "DT_IA_64_PLT_RESERVE";
243	case DT_AUXILIARY:	return "DT_AUXILIARY";
244	case DT_USED:		return "DT_USED";
245	case DT_FILTER:		return "DT_FILTER";
246	}
247	snprintf(unknown_tag, sizeof(unknown_tag),
248		"ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag);
249	return (unknown_tag);
250}
251
252static const char *
253e_machines(u_int mach)
254{
255	static char machdesc[64];
256
257	switch (mach) {
258	case EM_NONE:	return "EM_NONE";
259	case EM_M32:	return "EM_M32";
260	case EM_SPARC:	return "EM_SPARC";
261	case EM_386:	return "EM_386";
262	case EM_68K:	return "EM_68K";
263	case EM_88K:	return "EM_88K";
264	case EM_IAMCU:	return "EM_IAMCU";
265	case EM_860:	return "EM_860";
266	case EM_MIPS:	return "EM_MIPS";
267	case EM_PPC:	return "EM_PPC";
268	case EM_PPC64:	return "EM_PPC64";
269	case EM_ARM:	return "EM_ARM";
270	case EM_ALPHA:	return "EM_ALPHA (legacy)";
271	case EM_SPARCV9:return "EM_SPARCV9";
272	case EM_IA_64:	return "EM_IA_64";
273	case EM_X86_64:	return "EM_X86_64";
274	case EM_AARCH64:return "EM_AARCH64";
275	case EM_RISCV:	return "EM_RISCV";
276	}
277	snprintf(machdesc, sizeof(machdesc),
278	    "(unknown machine) -- type 0x%x", mach);
279	return (machdesc);
280}
281
282static const char *e_types[] = {
283	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
284};
285
286static const char *ei_versions[] = {
287	"EV_NONE", "EV_CURRENT"
288};
289
290static const char *ei_classes[] = {
291	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
292};
293
294static const char *ei_data[] = {
295	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
296};
297
298static const char *ei_abis[256] = {
299	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
300	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX",
301	"ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64",
302	"ELFOSABI_MODESTO", "ELFOSABI_OPENBSD",
303	[255] = "ELFOSABI_STANDALONE"
304};
305
306static const char *p_types[] = {
307	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
308	"PT_SHLIB", "PT_PHDR", "PT_TLS"
309};
310
311static const char *p_flags[] = {
312	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
313	"PF_X|PF_W|PF_R"
314};
315
316/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
317static const char *
318sh_types(uint64_t machine, uint64_t sht) {
319	static char unknown_buf[64];
320
321	if (sht < 0x60000000) {
322		switch (sht) {
323		case SHT_NULL:		return "SHT_NULL";
324		case SHT_PROGBITS:	return "SHT_PROGBITS";
325		case SHT_SYMTAB:	return "SHT_SYMTAB";
326		case SHT_STRTAB:	return "SHT_STRTAB";
327		case SHT_RELA:		return "SHT_RELA";
328		case SHT_HASH:		return "SHT_HASH";
329		case SHT_DYNAMIC:	return "SHT_DYNAMIC";
330		case SHT_NOTE:		return "SHT_NOTE";
331		case SHT_NOBITS:	return "SHT_NOBITS";
332		case SHT_REL:		return "SHT_REL";
333		case SHT_SHLIB:		return "SHT_SHLIB";
334		case SHT_DYNSYM:	return "SHT_DYNSYM";
335		case SHT_INIT_ARRAY:	return "SHT_INIT_ARRAY";
336		case SHT_FINI_ARRAY:	return "SHT_FINI_ARRAY";
337		case SHT_PREINIT_ARRAY:	return "SHT_PREINIT_ARRAY";
338		case SHT_GROUP:		return "SHT_GROUP";
339		case SHT_SYMTAB_SHNDX:	return "SHT_SYMTAB_SHNDX";
340		}
341		snprintf(unknown_buf, sizeof(unknown_buf),
342		    "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht);
343		return (unknown_buf);
344	} else if (sht < 0x70000000) {
345		/* 0x60000000-0x6fffffff operating system-specific semantics */
346		switch (sht) {
347		case 0x6ffffff0:	return "XXX:VERSYM";
348		case SHT_SUNW_dof:	return "SHT_SUNW_dof";
349		case SHT_GNU_HASH:	return "SHT_GNU_HASH";
350		case 0x6ffffff7:	return "SHT_GNU_LIBLIST";
351		case 0x6ffffffc:	return "XXX:VERDEF";
352		case SHT_SUNW_verdef:	return "SHT_SUNW(GNU)_verdef";
353		case SHT_SUNW_verneed:	return "SHT_SUNW(GNU)_verneed";
354		case SHT_SUNW_versym:	return "SHT_SUNW(GNU)_versym";
355		}
356		snprintf(unknown_buf, sizeof(unknown_buf),
357		    "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED",
358		     (uintmax_t)sht);
359		return (unknown_buf);
360	} else if (sht < 0x80000000) {
361		/* 0x70000000-0x7fffffff processor-specific semantics */
362		switch (machine) {
363		case EM_ARM:
364			switch (sht) {
365			case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX";
366			case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP";
367			case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES";
368			case SHT_ARM_DEBUGOVERLAY:
369			    return "SHT_ARM_DEBUGOVERLAY";
370			case SHT_ARM_OVERLAYSECTION:
371			    return "SHT_ARM_OVERLAYSECTION";
372			}
373			break;
374		case EM_IA_64:
375			switch (sht) {
376			case 0x70000000: return "SHT_IA_64_EXT";
377			case 0x70000001: return "SHT_IA_64_UNWIND";
378			}
379			break;
380		case EM_MIPS:
381			switch (sht) {
382			case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO";
383			case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS";
384			case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS";
385			}
386			break;
387		}
388		switch (sht) {
389		case 0x7ffffffd: return "XXX:AUXILIARY";
390		case 0x7fffffff: return "XXX:FILTER";
391		}
392		snprintf(unknown_buf, sizeof(unknown_buf),
393		    "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED",
394		     (uintmax_t)sht);
395		return (unknown_buf);
396	} else {
397		/* 0x80000000-0xffffffff application programs */
398		snprintf(unknown_buf, sizeof(unknown_buf),
399		    "ERROR: SHT 0x%jx NOT DEFINED",
400		     (uintmax_t)sht);
401		return (unknown_buf);
402	}
403}
404
405static const char *sh_flags[] = {
406	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
407	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
408	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
409};
410
411static const char *st_types[] = {
412	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
413};
414
415static const char *st_bindings[] = {
416	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
417};
418
419static char *dynstr;
420static char *shstrtab;
421static char *strtab;
422static FILE *out;
423
424static u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
425static u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base,
426    elf_member_t member);
427#if 0
428static u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
429#endif
430static u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
431static u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
432
433static void elf_print_ehdr(Elf32_Ehdr *e, void *sh);
434static void elf_print_phdr(Elf32_Ehdr *e, void *p);
435static void elf_print_shdr(Elf32_Ehdr *e, void *sh);
436static void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
437static void elf_print_dynamic(Elf32_Ehdr *e, void *sh);
438static void elf_print_rel(Elf32_Ehdr *e, void *r);
439static void elf_print_rela(Elf32_Ehdr *e, void *ra);
440static void elf_print_interp(Elf32_Ehdr *e, void *p);
441static void elf_print_got(Elf32_Ehdr *e, void *sh);
442static void elf_print_hash(Elf32_Ehdr *e, void *sh);
443static void elf_print_note(Elf32_Ehdr *e, void *sh);
444
445static void usage(void);
446
447/*
448 * Helpers for ELF files with shnum or shstrndx values that don't fit in the
449 * ELF header.  If the values are too large then an escape value is used to
450 * indicate that the actual value is found in one of section 0's fields.
451 */
452static uint64_t
453elf_get_shnum(Elf32_Ehdr *e, void *sh)
454{
455	uint64_t shnum;
456
457	shnum = elf_get_quarter(e, e, E_SHNUM);
458	if (shnum == 0)
459		shnum = elf_get_word(e, (char *)sh, SH_SIZE);
460	return shnum;
461}
462
463static uint64_t
464elf_get_shstrndx(Elf32_Ehdr *e, void *sh)
465{
466	uint64_t shstrndx;
467
468	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
469	if (shstrndx == SHN_XINDEX)
470		shstrndx = elf_get_word(e, (char *)sh, SH_LINK);
471	return shstrndx;
472}
473
474int
475main(int ac, char **av)
476{
477	cap_rights_t rights;
478	u_int64_t phoff;
479	u_int64_t shoff;
480	u_int64_t phentsize;
481	u_int64_t phnum;
482	u_int64_t shentsize;
483	u_int64_t shnum;
484	u_int64_t shstrndx;
485	u_int64_t offset;
486	u_int64_t name;
487	u_int64_t type;
488	struct stat sb;
489	u_int flags;
490	Elf32_Ehdr *e;
491	void *p;
492	void *sh;
493	void *v;
494	int fd;
495	int ch;
496	int i;
497
498	out = stdout;
499	flags = 0;
500	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
501		switch (ch) {
502		case 'a':
503			flags = ED_ALL;
504			break;
505		case 'c':
506			flags |= ED_SHDR;
507			break;
508		case 'd':
509			flags |= ED_DYN;
510			break;
511		case 'e':
512			flags |= ED_EHDR;
513			break;
514		case 'i':
515			flags |= ED_INTERP;
516			break;
517		case 'G':
518			flags |= ED_GOT;
519			break;
520		case 'h':
521			flags |= ED_HASH;
522			break;
523		case 'n':
524			flags |= ED_NOTE;
525			break;
526		case 'p':
527			flags |= ED_PHDR;
528			break;
529		case 'r':
530			flags |= ED_REL;
531			break;
532		case 's':
533			flags |= ED_SYMTAB;
534			break;
535		case 'w':
536			if ((out = fopen(optarg, "w")) == NULL)
537				err(1, "%s", optarg);
538			cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE);
539			if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS)
540				err(1, "unable to limit rights for %s", optarg);
541			break;
542		case '?':
543		default:
544			usage();
545		}
546	ac -= optind;
547	av += optind;
548	if (ac == 0 || flags == 0)
549		usage();
550	if ((fd = open(*av, O_RDONLY)) < 0 ||
551	    fstat(fd, &sb) < 0)
552		err(1, "%s", *av);
553	cap_rights_init(&rights, CAP_MMAP_R);
554	if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS)
555		err(1, "unable to limit rights for %s", *av);
556	close(STDIN_FILENO);
557	cap_rights_init(&rights, CAP_WRITE);
558	if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
559		err(1, "unable to limit rights for stdout");
560	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
561		err(1, "unable to limit rights for stderr");
562	if (cap_enter() < 0 && errno != ENOSYS)
563		err(1, "unable to enter capability mode");
564	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
565	if (e == MAP_FAILED)
566		err(1, NULL);
567	if (!IS_ELF(*(Elf32_Ehdr *)e))
568		errx(1, "not an elf file");
569	phoff = elf_get_off(e, e, E_PHOFF);
570	shoff = elf_get_off(e, e, E_SHOFF);
571	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
572	phnum = elf_get_quarter(e, e, E_PHNUM);
573	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
574	p = (char *)e + phoff;
575	if (shoff > 0) {
576		sh = (char *)e + shoff;
577		shnum = elf_get_shnum(e, sh);
578		shstrndx = elf_get_shstrndx(e, sh);
579		offset = elf_get_off(e, (char *)sh + shstrndx * shentsize,
580		    SH_OFFSET);
581		shstrtab = (char *)e + offset;
582	} else {
583		sh = NULL;
584		shnum = 0;
585		shstrndx = 0;
586		shstrtab = NULL;
587	}
588	for (i = 0; (u_int64_t)i < shnum; i++) {
589		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
590		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
591		if (strcmp(shstrtab + name, ".strtab") == 0)
592			strtab = (char *)e + offset;
593		if (strcmp(shstrtab + name, ".dynstr") == 0)
594			dynstr = (char *)e + offset;
595	}
596	if (flags & ED_EHDR)
597		elf_print_ehdr(e, sh);
598	if (flags & ED_PHDR)
599		elf_print_phdr(e, p);
600	if (flags & ED_SHDR)
601		elf_print_shdr(e, sh);
602	for (i = 0; (u_int64_t)i < phnum; i++) {
603		v = (char *)p + i * phentsize;
604		type = elf_get_word(e, v, P_TYPE);
605		switch (type) {
606		case PT_INTERP:
607			if (flags & ED_INTERP)
608				elf_print_interp(e, v);
609			break;
610		case PT_NULL:
611		case PT_LOAD:
612		case PT_DYNAMIC:
613		case PT_NOTE:
614		case PT_SHLIB:
615		case PT_PHDR:
616			break;
617		}
618	}
619	for (i = 0; (u_int64_t)i < shnum; i++) {
620		v = (char *)sh + i * shentsize;
621		type = elf_get_word(e, v, SH_TYPE);
622		switch (type) {
623		case SHT_SYMTAB:
624			if (flags & ED_SYMTAB)
625				elf_print_symtab(e, v, strtab);
626			break;
627		case SHT_DYNAMIC:
628			if (flags & ED_DYN)
629				elf_print_dynamic(e, v);
630			break;
631		case SHT_RELA:
632			if (flags & ED_REL)
633				elf_print_rela(e, v);
634			break;
635		case SHT_REL:
636			if (flags & ED_REL)
637				elf_print_rel(e, v);
638			break;
639		case SHT_NOTE:
640			name = elf_get_word(e, v, SH_NAME);
641			if (flags & ED_NOTE &&
642			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
643				elf_print_note(e, v);
644			break;
645		case SHT_DYNSYM:
646			if (flags & ED_SYMTAB)
647				elf_print_symtab(e, v, dynstr);
648			break;
649		case SHT_PROGBITS:
650			name = elf_get_word(e, v, SH_NAME);
651			if (flags & ED_GOT &&
652			    strcmp(shstrtab + name, ".got") == 0)
653				elf_print_got(e, v);
654			break;
655		case SHT_HASH:
656			if (flags & ED_HASH)
657				elf_print_hash(e, v);
658			break;
659		case SHT_NULL:
660		case SHT_STRTAB:
661		case SHT_NOBITS:
662		case SHT_SHLIB:
663			break;
664		}
665	}
666
667	return 0;
668}
669
670static void
671elf_print_ehdr(Elf32_Ehdr *e, void *sh)
672{
673	u_int64_t class;
674	u_int64_t data;
675	u_int64_t osabi;
676	u_int64_t type;
677	u_int64_t machine;
678	u_int64_t version;
679	u_int64_t entry;
680	u_int64_t phoff;
681	u_int64_t shoff;
682	u_int64_t flags;
683	u_int64_t ehsize;
684	u_int64_t phentsize;
685	u_int64_t phnum;
686	u_int64_t shentsize;
687	u_int64_t shnum;
688	u_int64_t shstrndx;
689
690	class = elf_get_byte(e, e, E_CLASS);
691	data = elf_get_byte(e, e, E_DATA);
692	osabi = elf_get_byte(e, e, E_OSABI);
693	type = elf_get_quarter(e, e, E_TYPE);
694	machine = elf_get_quarter(e, e, E_MACHINE);
695	version = elf_get_word(e, e, E_VERSION);
696	entry = elf_get_addr(e, e, E_ENTRY);
697	phoff = elf_get_off(e, e, E_PHOFF);
698	shoff = elf_get_off(e, e, E_SHOFF);
699	flags = elf_get_word(e, e, E_FLAGS);
700	ehsize = elf_get_quarter(e, e, E_EHSIZE);
701	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
702	phnum = elf_get_quarter(e, e, E_PHNUM);
703	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
704	fprintf(out, "\nelf header:\n");
705	fprintf(out, "\n");
706	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
707	    ei_abis[osabi]);
708	fprintf(out, "\te_type: %s\n", e_types[type]);
709	fprintf(out, "\te_machine: %s\n", e_machines(machine));
710	fprintf(out, "\te_version: %s\n", ei_versions[version]);
711	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
712	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
713	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
714	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
715	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
716	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
717	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
718	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
719	if (sh != NULL) {
720		shnum = elf_get_shnum(e, sh);
721		shstrndx = elf_get_shstrndx(e, sh);
722		fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
723		fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
724	}
725}
726
727static void
728elf_print_phdr(Elf32_Ehdr *e, void *p)
729{
730	u_int64_t phentsize;
731	u_int64_t phnum;
732	u_int64_t type;
733	u_int64_t offset;
734	u_int64_t vaddr;
735	u_int64_t paddr;
736	u_int64_t filesz;
737	u_int64_t memsz;
738	u_int64_t flags;
739	u_int64_t align;
740	void *v;
741	int i;
742
743	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
744	phnum = elf_get_quarter(e, e, E_PHNUM);
745	fprintf(out, "\nprogram header:\n");
746	for (i = 0; (u_int64_t)i < phnum; i++) {
747		v = (char *)p + i * phentsize;
748		type = elf_get_word(e, v, P_TYPE);
749		offset = elf_get_off(e, v, P_OFFSET);
750		vaddr = elf_get_addr(e, v, P_VADDR);
751		paddr = elf_get_addr(e, v, P_PADDR);
752		filesz = elf_get_size(e, v, P_FILESZ);
753		memsz = elf_get_size(e, v, P_MEMSZ);
754		flags = elf_get_word(e, v, P_FLAGS);
755		align = elf_get_size(e, v, P_ALIGN);
756		fprintf(out, "\n");
757		fprintf(out, "entry: %d\n", i);
758		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
759		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
760		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
761		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
762		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
763		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
764		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
765		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
766	}
767}
768
769static void
770elf_print_shdr(Elf32_Ehdr *e, void *sh)
771{
772	u_int64_t shentsize;
773	u_int64_t shnum;
774	u_int64_t name;
775	u_int64_t type;
776	u_int64_t flags;
777	u_int64_t addr;
778	u_int64_t offset;
779	u_int64_t size;
780	u_int64_t shlink;
781	u_int64_t info;
782	u_int64_t addralign;
783	u_int64_t entsize;
784	u_int64_t machine;
785	void *v;
786	int i;
787
788	if (sh == NULL) {
789		fprintf(out, "\nNo section headers\n");
790		return;
791	}
792
793	machine = elf_get_quarter(e, e, E_MACHINE);
794	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
795	shnum = elf_get_shnum(e, sh);
796	fprintf(out, "\nsection header:\n");
797	for (i = 0; (u_int64_t)i < shnum; i++) {
798		v = (char *)sh + i * shentsize;
799		name = elf_get_word(e, v, SH_NAME);
800		type = elf_get_word(e, v, SH_TYPE);
801		flags = elf_get_word(e, v, SH_FLAGS);
802		addr = elf_get_addr(e, v, SH_ADDR);
803		offset = elf_get_off(e, v, SH_OFFSET);
804		size = elf_get_size(e, v, SH_SIZE);
805		shlink = elf_get_word(e, v, SH_LINK);
806		info = elf_get_word(e, v, SH_INFO);
807		addralign = elf_get_size(e, v, SH_ADDRALIGN);
808		entsize = elf_get_size(e, v, SH_ENTSIZE);
809		fprintf(out, "\n");
810		fprintf(out, "entry: %d\n", i);
811		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
812		fprintf(out, "\tsh_type: %s\n", sh_types(machine, type));
813		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
814		fprintf(out, "\tsh_addr: %#jx\n", addr);
815		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
816		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
817		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
818		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
819		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
820		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
821	}
822}
823
824static void
825elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
826{
827	u_int64_t offset;
828	u_int64_t entsize;
829	u_int64_t size;
830	u_int64_t name;
831	u_int64_t value;
832	u_int64_t info;
833	u_int64_t shndx;
834	void *st;
835	int len;
836	int i;
837
838	offset = elf_get_off(e, sh, SH_OFFSET);
839	entsize = elf_get_size(e, sh, SH_ENTSIZE);
840	size = elf_get_size(e, sh, SH_SIZE);
841	name = elf_get_word(e, sh, SH_NAME);
842	len = size / entsize;
843	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
844	for (i = 0; i < len; i++) {
845		st = (char *)e + offset + i * entsize;
846		name = elf_get_word(e, st, ST_NAME);
847		value = elf_get_addr(e, st, ST_VALUE);
848		size = elf_get_size(e, st, ST_SIZE);
849		info = elf_get_byte(e, st, ST_INFO);
850		shndx = elf_get_quarter(e, st, ST_SHNDX);
851		fprintf(out, "\n");
852		fprintf(out, "entry: %d\n", i);
853		fprintf(out, "\tst_name: %s\n", str + name);
854		fprintf(out, "\tst_value: %#jx\n", value);
855		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
856		fprintf(out, "\tst_info: %s %s\n",
857		    st_types[ELF32_ST_TYPE(info)],
858		    st_bindings[ELF32_ST_BIND(info)]);
859		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
860	}
861}
862
863static void
864elf_print_dynamic(Elf32_Ehdr *e, void *sh)
865{
866	u_int64_t offset;
867	u_int64_t entsize;
868	u_int64_t size;
869	int64_t tag;
870	u_int64_t ptr;
871	u_int64_t val;
872	void *d;
873	int i;
874
875	offset = elf_get_off(e, sh, SH_OFFSET);
876	entsize = elf_get_size(e, sh, SH_ENTSIZE);
877	size = elf_get_size(e, sh, SH_SIZE);
878	fprintf(out, "\ndynamic:\n");
879	for (i = 0; (u_int64_t)i < size / entsize; i++) {
880		d = (char *)e + offset + i * entsize;
881		tag = elf_get_size(e, d, D_TAG);
882		ptr = elf_get_size(e, d, D_PTR);
883		val = elf_get_addr(e, d, D_VAL);
884		fprintf(out, "\n");
885		fprintf(out, "entry: %d\n", i);
886		fprintf(out, "\td_tag: %s\n", d_tags(tag));
887		switch (tag) {
888		case DT_NEEDED:
889		case DT_SONAME:
890		case DT_RPATH:
891			fprintf(out, "\td_val: %s\n", dynstr + val);
892			break;
893		case DT_PLTRELSZ:
894		case DT_RELA:
895		case DT_RELASZ:
896		case DT_RELAENT:
897		case DT_STRSZ:
898		case DT_SYMENT:
899		case DT_RELSZ:
900		case DT_RELENT:
901		case DT_PLTREL:
902			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
903			break;
904		case DT_PLTGOT:
905		case DT_HASH:
906		case DT_STRTAB:
907		case DT_SYMTAB:
908		case DT_INIT:
909		case DT_FINI:
910		case DT_REL:
911		case DT_JMPREL:
912			fprintf(out, "\td_ptr: %#jx\n", ptr);
913			break;
914		case DT_NULL:
915		case DT_SYMBOLIC:
916		case DT_DEBUG:
917		case DT_TEXTREL:
918			break;
919		}
920	}
921}
922
923static void
924elf_print_rela(Elf32_Ehdr *e, void *sh)
925{
926	u_int64_t offset;
927	u_int64_t entsize;
928	u_int64_t size;
929	u_int64_t name;
930	u_int64_t info;
931	int64_t addend;
932	void *ra;
933	void *v;
934	int i;
935
936	offset = elf_get_off(e, sh, SH_OFFSET);
937	entsize = elf_get_size(e, sh, SH_ENTSIZE);
938	size = elf_get_size(e, sh, SH_SIZE);
939	name = elf_get_word(e, sh, SH_NAME);
940	v = (char *)e + offset;
941	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
942	for (i = 0; (u_int64_t)i < size / entsize; i++) {
943		ra = (char *)v + i * entsize;
944		offset = elf_get_addr(e, ra, RA_OFFSET);
945		info = elf_get_word(e, ra, RA_INFO);
946		addend = elf_get_off(e, ra, RA_ADDEND);
947		fprintf(out, "\n");
948		fprintf(out, "entry: %d\n", i);
949		fprintf(out, "\tr_offset: %#jx\n", offset);
950		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
951		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
952	}
953}
954
955static void
956elf_print_rel(Elf32_Ehdr *e, void *sh)
957{
958	u_int64_t offset;
959	u_int64_t entsize;
960	u_int64_t size;
961	u_int64_t name;
962	u_int64_t info;
963	void *r;
964	void *v;
965	int i;
966
967	offset = elf_get_off(e, sh, SH_OFFSET);
968	entsize = elf_get_size(e, sh, SH_ENTSIZE);
969	size = elf_get_size(e, sh, SH_SIZE);
970	name = elf_get_word(e, sh, SH_NAME);
971	v = (char *)e + offset;
972	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
973	for (i = 0; (u_int64_t)i < size / entsize; i++) {
974		r = (char *)v + i * entsize;
975		offset = elf_get_addr(e, r, R_OFFSET);
976		info = elf_get_word(e, r, R_INFO);
977		fprintf(out, "\n");
978		fprintf(out, "entry: %d\n", i);
979		fprintf(out, "\tr_offset: %#jx\n", offset);
980		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
981	}
982}
983
984static void
985elf_print_interp(Elf32_Ehdr *e, void *p)
986{
987	u_int64_t offset;
988	char *s;
989
990	offset = elf_get_off(e, p, P_OFFSET);
991	s = (char *)e + offset;
992	fprintf(out, "\ninterp:\n");
993	fprintf(out, "\t%s\n", s);
994}
995
996static void
997elf_print_got(Elf32_Ehdr *e, void *sh)
998{
999	u_int64_t offset;
1000	u_int64_t addralign;
1001	u_int64_t size;
1002	u_int64_t addr;
1003	void *v;
1004	int i;
1005
1006	offset = elf_get_off(e, sh, SH_OFFSET);
1007	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
1008	size = elf_get_size(e, sh, SH_SIZE);
1009	v = (char *)e + offset;
1010	fprintf(out, "\nglobal offset table:\n");
1011	for (i = 0; (u_int64_t)i < size / addralign; i++) {
1012		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
1013		fprintf(out, "\n");
1014		fprintf(out, "entry: %d\n", i);
1015		fprintf(out, "\t%#jx\n", addr);
1016	}
1017}
1018
1019static void
1020elf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
1021{
1022}
1023
1024static void
1025elf_print_note(Elf32_Ehdr *e, void *sh)
1026{
1027	u_int64_t offset;
1028	u_int64_t size;
1029	u_int64_t name;
1030	u_int32_t namesz;
1031	u_int32_t descsz;
1032	u_int32_t desc;
1033	char *n, *s;
1034
1035	offset = elf_get_off(e, sh, SH_OFFSET);
1036	size = elf_get_size(e, sh, SH_SIZE);
1037	name = elf_get_word(e, sh, SH_NAME);
1038	n = (char *)e + offset;
1039	fprintf(out, "\nnote (%s):\n", shstrtab + name);
1040 	while (n < ((char *)e + offset + size)) {
1041		namesz = elf_get_word(e, n, N_NAMESZ);
1042		descsz = elf_get_word(e, n, N_DESCSZ);
1043 		s = n + sizeof(Elf_Note);
1044 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
1045		fprintf(out, "\t%s %d\n", s, desc);
1046		n += sizeof(Elf_Note) + namesz + descsz;
1047	}
1048}
1049
1050static u_int64_t
1051elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
1052{
1053	u_int64_t val;
1054
1055	val = 0;
1056	switch (e->e_ident[EI_CLASS]) {
1057	case ELFCLASS32:
1058		val = ((uint8_t *)base)[elf32_offsets[member]];
1059		break;
1060	case ELFCLASS64:
1061		val = ((uint8_t *)base)[elf64_offsets[member]];
1062		break;
1063	case ELFCLASSNONE:
1064		errx(1, "invalid class");
1065	}
1066
1067	return val;
1068}
1069
1070static u_int64_t
1071elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
1072{
1073	u_int64_t val;
1074
1075	val = 0;
1076	switch (e->e_ident[EI_CLASS]) {
1077	case ELFCLASS32:
1078		base = (char *)base + elf32_offsets[member];
1079		switch (e->e_ident[EI_DATA]) {
1080		case ELFDATA2MSB:
1081			val = be16dec(base);
1082			break;
1083		case ELFDATA2LSB:
1084			val = le16dec(base);
1085			break;
1086		case ELFDATANONE:
1087			errx(1, "invalid data format");
1088		}
1089		break;
1090	case ELFCLASS64:
1091		base = (char *)base + elf64_offsets[member];
1092		switch (e->e_ident[EI_DATA]) {
1093		case ELFDATA2MSB:
1094			val = be16dec(base);
1095			break;
1096		case ELFDATA2LSB:
1097			val = le16dec(base);
1098			break;
1099		case ELFDATANONE:
1100			errx(1, "invalid data format");
1101		}
1102		break;
1103	case ELFCLASSNONE:
1104		errx(1, "invalid class");
1105	}
1106
1107	return val;
1108}
1109
1110#if 0
1111static u_int64_t
1112elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
1113{
1114	u_int64_t val;
1115
1116	val = 0;
1117	switch (e->e_ident[EI_CLASS]) {
1118	case ELFCLASS32:
1119		base = (char *)base + elf32_offsets[member];
1120		switch (e->e_ident[EI_DATA]) {
1121		case ELFDATA2MSB:
1122			val = be16dec(base);
1123			break;
1124		case ELFDATA2LSB:
1125			val = le16dec(base);
1126			break;
1127		case ELFDATANONE:
1128			errx(1, "invalid data format");
1129		}
1130		break;
1131	case ELFCLASS64:
1132		base = (char *)base + elf64_offsets[member];
1133		switch (e->e_ident[EI_DATA]) {
1134		case ELFDATA2MSB:
1135			val = be32dec(base);
1136			break;
1137		case ELFDATA2LSB:
1138			val = le32dec(base);
1139			break;
1140		case ELFDATANONE:
1141			errx(1, "invalid data format");
1142		}
1143		break;
1144	case ELFCLASSNONE:
1145		errx(1, "invalid class");
1146	}
1147
1148	return val;
1149}
1150#endif
1151
1152static u_int64_t
1153elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1154{
1155	u_int64_t val;
1156
1157	val = 0;
1158	switch (e->e_ident[EI_CLASS]) {
1159	case ELFCLASS32:
1160		base = (char *)base + elf32_offsets[member];
1161		switch (e->e_ident[EI_DATA]) {
1162		case ELFDATA2MSB:
1163			val = be32dec(base);
1164			break;
1165		case ELFDATA2LSB:
1166			val = le32dec(base);
1167			break;
1168		case ELFDATANONE:
1169			errx(1, "invalid data format");
1170		}
1171		break;
1172	case ELFCLASS64:
1173		base = (char *)base + elf64_offsets[member];
1174		switch (e->e_ident[EI_DATA]) {
1175		case ELFDATA2MSB:
1176			val = be32dec(base);
1177			break;
1178		case ELFDATA2LSB:
1179			val = le32dec(base);
1180			break;
1181		case ELFDATANONE:
1182			errx(1, "invalid data format");
1183		}
1184		break;
1185	case ELFCLASSNONE:
1186		errx(1, "invalid class");
1187	}
1188
1189	return val;
1190}
1191
1192static u_int64_t
1193elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1194{
1195	u_int64_t val;
1196
1197	val = 0;
1198	switch (e->e_ident[EI_CLASS]) {
1199	case ELFCLASS32:
1200		base = (char *)base + elf32_offsets[member];
1201		switch (e->e_ident[EI_DATA]) {
1202		case ELFDATA2MSB:
1203			val = be32dec(base);
1204			break;
1205		case ELFDATA2LSB:
1206			val = le32dec(base);
1207			break;
1208		case ELFDATANONE:
1209			errx(1, "invalid data format");
1210		}
1211		break;
1212	case ELFCLASS64:
1213		base = (char *)base + elf64_offsets[member];
1214		switch (e->e_ident[EI_DATA]) {
1215		case ELFDATA2MSB:
1216			val = be64dec(base);
1217			break;
1218		case ELFDATA2LSB:
1219			val = le64dec(base);
1220			break;
1221		case ELFDATANONE:
1222			errx(1, "invalid data format");
1223		}
1224		break;
1225	case ELFCLASSNONE:
1226		errx(1, "invalid class");
1227	}
1228
1229	return val;
1230}
1231
1232static void
1233usage(void)
1234{
1235	fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n");
1236	exit(1);
1237}
1238