1109313Sobrien/*-
2110252Sobrien * Copyright (c) 2003 David O'Brien.  All rights reserved.
3109313Sobrien * Copyright (c) 2001 Jake Burkholder
4109313Sobrien * All rights reserved.
5109313Sobrien *
6109313Sobrien * Redistribution and use in source and binary forms, with or without
7109313Sobrien * modification, are permitted provided that the following conditions
8109313Sobrien * are met:
9109313Sobrien * 1. Redistributions of source code must retain the above copyright
10109313Sobrien *    notice, this list of conditions and the following disclaimer.
11109313Sobrien * 2. Redistributions in binary form must reproduce the above copyright
12109313Sobrien *    notice, this list of conditions and the following disclaimer in the
13109313Sobrien *    documentation and/or other materials provided with the distribution.
14109313Sobrien *
15109313Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16109313Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17109313Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18109313Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19109313Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20109313Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21109313Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22109313Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23109313Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24109313Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25109313Sobrien * SUCH DAMAGE.
26109313Sobrien */
27109313Sobrien
28109313Sobrien#include <sys/cdefs.h>
29109313Sobrien__FBSDID("$FreeBSD: stable/10/usr.bin/elfdump/elfdump.c 307834 2016-10-24 00:46:38Z emaste $");
30109313Sobrien
31109313Sobrien#include <sys/types.h>
32275945Sbrueffer
33275945Sbrueffer#include <sys/capability.h>
34109313Sobrien#include <sys/elf32.h>
35109313Sobrien#include <sys/elf64.h>
36118680Smarcel#include <sys/endian.h>
37109313Sobrien#include <sys/mman.h>
38109313Sobrien#include <sys/stat.h>
39109313Sobrien#include <err.h>
40275945Sbrueffer#include <errno.h>
41109313Sobrien#include <fcntl.h>
42110257Sobrien#include <inttypes.h>
43109313Sobrien#include <stddef.h>
44109313Sobrien#include <stdio.h>
45109313Sobrien#include <stdlib.h>
46109313Sobrien#include <string.h>
47109313Sobrien#include <unistd.h>
48109313Sobrien
49109313Sobrien#define	ED_DYN		(1<<0)
50109313Sobrien#define	ED_EHDR		(1<<1)
51109313Sobrien#define	ED_GOT		(1<<2)
52109313Sobrien#define	ED_HASH		(1<<3)
53109313Sobrien#define	ED_INTERP	(1<<4)
54109313Sobrien#define	ED_NOTE		(1<<5)
55109313Sobrien#define	ED_PHDR		(1<<6)
56109313Sobrien#define	ED_REL		(1<<7)
57109313Sobrien#define	ED_SHDR		(1<<8)
58109313Sobrien#define	ED_SYMTAB	(1<<9)
59109313Sobrien#define	ED_ALL		((1<<10)-1)
60109313Sobrien
61109313Sobrien#define	elf_get_addr	elf_get_quad
62109313Sobrien#define	elf_get_off	elf_get_quad
63109313Sobrien#define	elf_get_size	elf_get_quad
64109313Sobrien
65109313Sobrienenum elf_member {
66109313Sobrien	D_TAG = 1, D_PTR, D_VAL,
67109313Sobrien
68109313Sobrien	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
69109313Sobrien	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
70109313Sobrien	E_SHNUM, E_SHSTRNDX,
71109313Sobrien
72109313Sobrien	N_NAMESZ, N_DESCSZ, N_TYPE,
73109313Sobrien
74109313Sobrien	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
75109313Sobrien	P_ALIGN,
76109313Sobrien
77109313Sobrien	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
78109313Sobrien	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
79109313Sobrien
80109313Sobrien	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
81109313Sobrien
82109313Sobrien	R_OFFSET, R_INFO,
83109313Sobrien
84109313Sobrien	RA_OFFSET, RA_INFO, RA_ADDEND
85109313Sobrien};
86109313Sobrien
87109313Sobrientypedef enum elf_member elf_member_t;
88109313Sobrien
89241737Sedstatic int elf32_offsets[] = {
90109313Sobrien	0,
91109313Sobrien
92109313Sobrien	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
93109313Sobrien	offsetof(Elf32_Dyn, d_un.d_val),
94109313Sobrien
95109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
96109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
97109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
98109313Sobrien	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
99109313Sobrien	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
100109313Sobrien	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
101109313Sobrien	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
102109313Sobrien	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
103109313Sobrien	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
104109313Sobrien	offsetof(Elf32_Ehdr, e_shstrndx),
105109313Sobrien
106109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
107109313Sobrien	offsetof(Elf_Note, n_type),
108109313Sobrien
109109313Sobrien	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
110109313Sobrien	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
111109313Sobrien	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
112109313Sobrien	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
113109313Sobrien
114109313Sobrien	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
115109313Sobrien	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
116109313Sobrien	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
117109313Sobrien	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
118109313Sobrien	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
119109313Sobrien
120109313Sobrien	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
121109313Sobrien	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
122109313Sobrien	offsetof(Elf32_Sym, st_shndx),
123119794Sschweikh
124109313Sobrien	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
125109313Sobrien
126109313Sobrien	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
127109313Sobrien	offsetof(Elf32_Rela, r_addend)
128109313Sobrien};
129109313Sobrien
130241737Sedstatic int elf64_offsets[] = {
131109313Sobrien	0,
132109313Sobrien
133109313Sobrien	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
134109313Sobrien	offsetof(Elf64_Dyn, d_un.d_val),
135119794Sschweikh
136109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
137109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
138109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
139109313Sobrien	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
140109313Sobrien	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
141109313Sobrien	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
142109313Sobrien	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
143109313Sobrien	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
144109313Sobrien	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
145109313Sobrien	offsetof(Elf64_Ehdr, e_shstrndx),
146109313Sobrien
147109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
148109313Sobrien	offsetof(Elf_Note, n_type),
149109313Sobrien
150109313Sobrien	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
151109313Sobrien	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
152109313Sobrien	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
153109313Sobrien	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
154109313Sobrien
155109313Sobrien	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
156109313Sobrien	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
157109313Sobrien	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
158109313Sobrien	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
159109313Sobrien	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
160109313Sobrien
161109313Sobrien	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
162109313Sobrien	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
163109313Sobrien	offsetof(Elf64_Sym, st_shndx),
164119794Sschweikh
165109313Sobrien	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
166109313Sobrien
167109313Sobrien	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
168109313Sobrien	offsetof(Elf64_Rela, r_addend)
169109313Sobrien};
170109313Sobrien
171109332Sobrien/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
172110256Sobrienstatic const char *
173270969Semasted_tags(u_int64_t tag)
174270969Semaste{
175270969Semaste	static char unknown_tag[48];
176270969Semaste
177109332Sobrien	switch (tag) {
178270969Semaste	case DT_NULL:		return "DT_NULL";
179270969Semaste	case DT_NEEDED:		return "DT_NEEDED";
180270969Semaste	case DT_PLTRELSZ:	return "DT_PLTRELSZ";
181270969Semaste	case DT_PLTGOT:		return "DT_PLTGOT";
182270969Semaste	case DT_HASH:		return "DT_HASH";
183270969Semaste	case DT_STRTAB:		return "DT_STRTAB";
184270969Semaste	case DT_SYMTAB:		return "DT_SYMTAB";
185270969Semaste	case DT_RELA:		return "DT_RELA";
186270969Semaste	case DT_RELASZ:		return "DT_RELASZ";
187270969Semaste	case DT_RELAENT:	return "DT_RELAENT";
188270969Semaste	case DT_STRSZ:		return "DT_STRSZ";
189270969Semaste	case DT_SYMENT:		return "DT_SYMENT";
190270969Semaste	case DT_INIT:		return "DT_INIT";
191270969Semaste	case DT_FINI:		return "DT_FINI";
192270969Semaste	case DT_SONAME:		return "DT_SONAME";
193270969Semaste	case DT_RPATH:		return "DT_RPATH";
194270969Semaste	case DT_SYMBOLIC:	return "DT_SYMBOLIC";
195270969Semaste	case DT_REL:		return "DT_REL";
196270969Semaste	case DT_RELSZ:		return "DT_RELSZ";
197270969Semaste	case DT_RELENT:		return "DT_RELENT";
198270969Semaste	case DT_PLTREL:		return "DT_PLTREL";
199270969Semaste	case DT_DEBUG:		return "DT_DEBUG";
200270969Semaste	case DT_TEXTREL:	return "DT_TEXTREL";
201270969Semaste	case DT_JMPREL:		return "DT_JMPREL";
202270969Semaste	case DT_BIND_NOW:	return "DT_BIND_NOW";
203270969Semaste	case DT_INIT_ARRAY:	return "DT_INIT_ARRAY";
204270969Semaste	case DT_FINI_ARRAY:	return "DT_FINI_ARRAY";
205270969Semaste	case DT_INIT_ARRAYSZ:	return "DT_INIT_ARRAYSZ";
206270969Semaste	case DT_FINI_ARRAYSZ:	return "DT_FINI_ARRAYSZ";
207270969Semaste	case DT_RUNPATH:	return "DT_RUNPATH";
208270969Semaste	case DT_FLAGS:		return "DT_FLAGS";
209270969Semaste	case DT_PREINIT_ARRAY:	return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */
210270969Semaste	case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ";
211109332Sobrien	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
212270969Semaste	case 0x6ffffdf5:	return "DT_GNU_PRELINKED";
213270969Semaste	case 0x6ffffdf6:	return "DT_GNU_CONFLICTSZ";
214270969Semaste	case 0x6ffffdf7:	return "DT_GNU_LIBLISTSZ";
215270969Semaste	case 0x6ffffdf8:	return "DT_SUNW_CHECKSUM";
216270969Semaste	case DT_PLTPADSZ:	return "DT_PLTPADSZ";
217270969Semaste	case DT_MOVEENT:	return "DT_MOVEENT";
218270969Semaste	case DT_MOVESZ:		return "DT_MOVESZ";
219270969Semaste	case DT_FEATURE:	return "DT_FEATURE";
220270969Semaste	case DT_POSFLAG_1:	return "DT_POSFLAG_1";
221270969Semaste	case DT_SYMINSZ:	return "DT_SYMINSZ";
222270969Semaste	case DT_SYMINENT :	return "DT_SYMINENT (DT_VALRNGHI)";
223270969Semaste	case DT_ADDRRNGLO:	return "DT_ADDRRNGLO";
224270969Semaste	case DT_GNU_HASH:	return "DT_GNU_HASH";
225270969Semaste	case 0x6ffffef8:	return "DT_GNU_CONFLICT";
226270969Semaste	case 0x6ffffef9:	return "DT_GNU_LIBLIST";
227270969Semaste	case DT_CONFIG:		return "DT_CONFIG";
228270969Semaste	case DT_DEPAUDIT:	return "DT_DEPAUDIT";
229270969Semaste	case DT_AUDIT:		return "DT_AUDIT";
230270969Semaste	case DT_PLTPAD:		return "DT_PLTPAD";
231270969Semaste	case DT_MOVETAB:	return "DT_MOVETAB";
232270969Semaste	case DT_SYMINFO :	return "DT_SYMINFO (DT_ADDRRNGHI)";
233270969Semaste	case DT_RELACOUNT:	return "DT_RELACOUNT";
234270969Semaste	case DT_RELCOUNT:	return "DT_RELCOUNT";
235270969Semaste	case DT_FLAGS_1:	return "DT_FLAGS_1";
236270969Semaste	case DT_VERDEF:		return "DT_VERDEF";
237270969Semaste	case DT_VERDEFNUM:	return "DT_VERDEFNUM";
238270969Semaste	case DT_VERNEED:	return "DT_VERNEED";
239270969Semaste	case DT_VERNEEDNUM:	return "DT_VERNEEDNUM";
240270969Semaste	case 0x6ffffff0:	return "DT_GNU_VERSYM";
241109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
242270969Semaste	case 0x70000000:	return "DT_IA_64_PLT_RESERVE";
243307834Semaste	case DT_AUXILIARY:	return "DT_AUXILIARY";
244307834Semaste	case DT_USED:		return "DT_USED";
245307834Semaste	case DT_FILTER:		return "DT_FILTER";
246109332Sobrien	}
247270969Semaste	snprintf(unknown_tag, sizeof(unknown_tag),
248270969Semaste		"ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag);
249270969Semaste	return (unknown_tag);
250119794Sschweikh}
251109313Sobrien
252110256Sobrienstatic const char *
253109457Smarcele_machines(u_int mach)
254109457Smarcel{
255153500Smarcel	static char machdesc[64];
256153500Smarcel
257109457Smarcel	switch (mach) {
258109457Smarcel	case EM_NONE:	return "EM_NONE";
259109457Smarcel	case EM_M32:	return "EM_M32";
260109457Smarcel	case EM_SPARC:	return "EM_SPARC";
261109457Smarcel	case EM_386:	return "EM_386";
262109457Smarcel	case EM_68K:	return "EM_68K";
263109457Smarcel	case EM_88K:	return "EM_88K";
264288173Semaste	case EM_IAMCU:	return "EM_IAMCU";
265109457Smarcel	case EM_860:	return "EM_860";
266109457Smarcel	case EM_MIPS:	return "EM_MIPS";
267153500Smarcel	case EM_PPC:	return "EM_PPC";
268261002Sjhibbits	case EM_PPC64:	return "EM_PPC64";
269153500Smarcel	case EM_ARM:	return "EM_ARM";
270153500Smarcel	case EM_ALPHA:	return "EM_ALPHA (legacy)";
271153500Smarcel	case EM_SPARCV9:return "EM_SPARCV9";
272109457Smarcel	case EM_IA_64:	return "EM_IA_64";
273153500Smarcel	case EM_X86_64:	return "EM_X86_64";
274270969Semaste	case EM_AARCH64:return "EM_AARCH64";
275288171Semaste	case EM_RISCV:	return "EM_RISCV";
276109457Smarcel	}
277153500Smarcel	snprintf(machdesc, sizeof(machdesc),
278153500Smarcel	    "(unknown machine) -- type 0x%x", mach);
279153500Smarcel	return (machdesc);
280119794Sschweikh}
281109313Sobrien
282241737Sedstatic const char *e_types[] = {
283109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
284109313Sobrien};
285109313Sobrien
286241737Sedstatic const char *ei_versions[] = {
287109313Sobrien	"EV_NONE", "EV_CURRENT"
288109313Sobrien};
289109313Sobrien
290241737Sedstatic const char *ei_classes[] = {
291109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
292109313Sobrien};
293109313Sobrien
294241737Sedstatic const char *ei_data[] = {
295109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
296109313Sobrien};
297109313Sobrien
298241737Sedstatic const char *ei_abis[256] = {
299109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
300226434Smarcel	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX",
301226434Smarcel	"ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64",
302226434Smarcel	"ELFOSABI_MODESTO", "ELFOSABI_OPENBSD",
303226434Smarcel	[255] = "ELFOSABI_STANDALONE"
304109313Sobrien};
305109313Sobrien
306241737Sedstatic const char *p_types[] = {
307109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
308126484Sjake	"PT_SHLIB", "PT_PHDR", "PT_TLS"
309109313Sobrien};
310109313Sobrien
311241737Sedstatic const char *p_flags[] = {
312109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
313109313Sobrien	"PF_X|PF_W|PF_R"
314109313Sobrien};
315109313Sobrien
316109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
317110256Sobrienstatic const char *
318270969Semastesh_types(uint64_t machine, uint64_t sht) {
319270969Semaste	static char unknown_buf[64];
320270969Semaste
321270969Semaste	if (sht < 0x60000000) {
322270969Semaste		switch (sht) {
323270969Semaste		case SHT_NULL:		return "SHT_NULL";
324270969Semaste		case SHT_PROGBITS:	return "SHT_PROGBITS";
325270969Semaste		case SHT_SYMTAB:	return "SHT_SYMTAB";
326270969Semaste		case SHT_STRTAB:	return "SHT_STRTAB";
327270969Semaste		case SHT_RELA:		return "SHT_RELA";
328270969Semaste		case SHT_HASH:		return "SHT_HASH";
329270969Semaste		case SHT_DYNAMIC:	return "SHT_DYNAMIC";
330270969Semaste		case SHT_NOTE:		return "SHT_NOTE";
331270969Semaste		case SHT_NOBITS:	return "SHT_NOBITS";
332270969Semaste		case SHT_REL:		return "SHT_REL";
333270969Semaste		case SHT_SHLIB:		return "SHT_SHLIB";
334270969Semaste		case SHT_DYNSYM:	return "SHT_DYNSYM";
335270969Semaste		case SHT_INIT_ARRAY:	return "SHT_INIT_ARRAY";
336270969Semaste		case SHT_FINI_ARRAY:	return "SHT_FINI_ARRAY";
337270969Semaste		case SHT_PREINIT_ARRAY:	return "SHT_PREINIT_ARRAY";
338270969Semaste		case SHT_GROUP:		return "SHT_GROUP";
339270969Semaste		case SHT_SYMTAB_SHNDX:	return "SHT_SYMTAB_SHNDX";
340270969Semaste		}
341270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
342270969Semaste		    "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht);
343270969Semaste		return (unknown_buf);
344270969Semaste	} else if (sht < 0x70000000) {
345270969Semaste		/* 0x60000000-0x6fffffff operating system-specific semantics */
346270969Semaste		switch (sht) {
347270969Semaste		case 0x6ffffff0:	return "XXX:VERSYM";
348270969Semaste		case SHT_SUNW_dof:	return "SHT_SUNW_dof";
349270969Semaste		case SHT_GNU_HASH:	return "SHT_GNU_HASH";
350270969Semaste		case 0x6ffffff7:	return "SHT_GNU_LIBLIST";
351270969Semaste		case 0x6ffffffc:	return "XXX:VERDEF";
352270969Semaste		case SHT_SUNW_verdef:	return "SHT_SUNW(GNU)_verdef";
353270969Semaste		case SHT_SUNW_verneed:	return "SHT_SUNW(GNU)_verneed";
354270969Semaste		case SHT_SUNW_versym:	return "SHT_SUNW(GNU)_versym";
355270969Semaste		}
356270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
357270969Semaste		    "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED",
358270969Semaste		     (uintmax_t)sht);
359270969Semaste		return (unknown_buf);
360270969Semaste	} else if (sht < 0x80000000) {
361270969Semaste		/* 0x70000000-0x7fffffff processor-specific semantics */
362270969Semaste		switch (machine) {
363270969Semaste		case EM_ARM:
364270969Semaste			switch (sht) {
365270969Semaste			case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX";
366270969Semaste			case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP";
367270969Semaste			case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES";
368270969Semaste			case SHT_ARM_DEBUGOVERLAY:
369270969Semaste			    return "SHT_ARM_DEBUGOVERLAY";
370270969Semaste			case SHT_ARM_OVERLAYSECTION:
371270969Semaste			    return "SHT_ARM_OVERLAYSECTION";
372270969Semaste			}
373270969Semaste			break;
374270969Semaste		case EM_IA_64:
375270969Semaste			switch (sht) {
376270969Semaste			case 0x70000000: return "SHT_IA_64_EXT";
377270969Semaste			case 0x70000001: return "SHT_IA_64_UNWIND";
378270969Semaste			}
379270969Semaste			break;
380270969Semaste		case EM_MIPS:
381270969Semaste			switch (sht) {
382294450Semaste			case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO";
383270969Semaste			case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS";
384294450Semaste			case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS";
385270969Semaste			}
386270969Semaste			break;
387270969Semaste		}
388270969Semaste		switch (sht) {
389270969Semaste		case 0x7ffffffd: return "XXX:AUXILIARY";
390270969Semaste		case 0x7fffffff: return "XXX:FILTER";
391270969Semaste		}
392270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
393270969Semaste		    "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED",
394270969Semaste		     (uintmax_t)sht);
395270969Semaste		return (unknown_buf);
396270969Semaste	} else {
397270969Semaste		/* 0x80000000-0xffffffff application programs */
398270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
399270969Semaste		    "ERROR: SHT 0x%jx NOT DEFINED",
400270969Semaste		     (uintmax_t)sht);
401270969Semaste		return (unknown_buf);
402109329Sobrien	}
403119795Sschweikh}
404109313Sobrien
405241737Sedstatic const char *sh_flags[] = {
406109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
407109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
408109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
409109313Sobrien};
410109313Sobrien
411241737Sedstatic const char *st_types[] = {
412109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
413109313Sobrien};
414109313Sobrien
415241737Sedstatic const char *st_bindings[] = {
416109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
417109313Sobrien};
418109313Sobrien
419241737Sedstatic char *dynstr;
420241737Sedstatic char *shstrtab;
421241737Sedstatic char *strtab;
422241737Sedstatic FILE *out;
423109313Sobrien
424241737Sedstatic u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
425241737Sedstatic u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base,
426241737Sed    elf_member_t member);
427241737Sed#if 0
428241737Sedstatic u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
429241737Sed#endif
430241737Sedstatic u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
431241737Sedstatic u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
432109313Sobrien
433267958Semastestatic void elf_print_ehdr(Elf32_Ehdr *e, void *sh);
434241737Sedstatic void elf_print_phdr(Elf32_Ehdr *e, void *p);
435241737Sedstatic void elf_print_shdr(Elf32_Ehdr *e, void *sh);
436241737Sedstatic void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
437241737Sedstatic void elf_print_dynamic(Elf32_Ehdr *e, void *sh);
438241737Sedstatic void elf_print_rel(Elf32_Ehdr *e, void *r);
439241737Sedstatic void elf_print_rela(Elf32_Ehdr *e, void *ra);
440241737Sedstatic void elf_print_interp(Elf32_Ehdr *e, void *p);
441241737Sedstatic void elf_print_got(Elf32_Ehdr *e, void *sh);
442241737Sedstatic void elf_print_hash(Elf32_Ehdr *e, void *sh);
443241737Sedstatic void elf_print_note(Elf32_Ehdr *e, void *sh);
444109313Sobrien
445241737Sedstatic void usage(void);
446109313Sobrien
447267958Semaste/*
448267958Semaste * Helpers for ELF files with shnum or shstrndx values that don't fit in the
449267958Semaste * ELF header.  If the values are too large then an escape value is used to
450267958Semaste * indicate that the actual value is found in one of section 0's fields.
451267958Semaste */
452267958Semastestatic uint64_t
453267958Semasteelf_get_shnum(Elf32_Ehdr *e, void *sh)
454267958Semaste{
455267958Semaste	uint64_t shnum;
456267958Semaste
457267958Semaste	shnum = elf_get_quarter(e, e, E_SHNUM);
458267958Semaste	if (shnum == 0)
459267958Semaste		shnum = elf_get_word(e, (char *)sh, SH_SIZE);
460267958Semaste	return shnum;
461267958Semaste}
462267958Semaste
463267958Semastestatic uint64_t
464267958Semasteelf_get_shstrndx(Elf32_Ehdr *e, void *sh)
465267958Semaste{
466267958Semaste	uint64_t shstrndx;
467267958Semaste
468267958Semaste	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
469267958Semaste	if (shstrndx == SHN_XINDEX)
470267958Semaste		shstrndx = elf_get_word(e, (char *)sh, SH_LINK);
471267958Semaste	return shstrndx;
472267958Semaste}
473267958Semaste
474109313Sobrienint
475109313Sobrienmain(int ac, char **av)
476109313Sobrien{
477275945Sbrueffer	cap_rights_t rights;
478109313Sobrien	u_int64_t phoff;
479109313Sobrien	u_int64_t shoff;
480109313Sobrien	u_int64_t phentsize;
481109313Sobrien	u_int64_t phnum;
482109313Sobrien	u_int64_t shentsize;
483109313Sobrien	u_int64_t shnum;
484109313Sobrien	u_int64_t shstrndx;
485109313Sobrien	u_int64_t offset;
486109313Sobrien	u_int64_t name;
487109313Sobrien	u_int64_t type;
488109313Sobrien	struct stat sb;
489109313Sobrien	u_int flags;
490110252Sobrien	Elf32_Ehdr *e;
491109313Sobrien	void *p;
492109313Sobrien	void *sh;
493109313Sobrien	void *v;
494109313Sobrien	int fd;
495109313Sobrien	int ch;
496109313Sobrien	int i;
497109313Sobrien
498109313Sobrien	out = stdout;
499109313Sobrien	flags = 0;
500109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
501109313Sobrien		switch (ch) {
502109313Sobrien		case 'a':
503109313Sobrien			flags = ED_ALL;
504109313Sobrien			break;
505109313Sobrien		case 'c':
506109313Sobrien			flags |= ED_SHDR;
507109313Sobrien			break;
508109313Sobrien		case 'd':
509109313Sobrien			flags |= ED_DYN;
510109313Sobrien			break;
511109313Sobrien		case 'e':
512109313Sobrien			flags |= ED_EHDR;
513109313Sobrien			break;
514109313Sobrien		case 'i':
515109313Sobrien			flags |= ED_INTERP;
516109313Sobrien			break;
517109313Sobrien		case 'G':
518109313Sobrien			flags |= ED_GOT;
519109313Sobrien			break;
520109313Sobrien		case 'h':
521109313Sobrien			flags |= ED_HASH;
522109313Sobrien			break;
523109313Sobrien		case 'n':
524109313Sobrien			flags |= ED_NOTE;
525109313Sobrien			break;
526109313Sobrien		case 'p':
527109313Sobrien			flags |= ED_PHDR;
528109313Sobrien			break;
529109313Sobrien		case 'r':
530109313Sobrien			flags |= ED_REL;
531109313Sobrien			break;
532109313Sobrien		case 's':
533109313Sobrien			flags |= ED_SYMTAB;
534109313Sobrien			break;
535109313Sobrien		case 'w':
536109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
537109313Sobrien				err(1, "%s", optarg);
538275945Sbrueffer			cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE);
539275945Sbrueffer			if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS)
540275945Sbrueffer				err(1, "unable to limit rights for %s", optarg);
541109313Sobrien			break;
542109313Sobrien		case '?':
543109313Sobrien		default:
544109313Sobrien			usage();
545109313Sobrien		}
546109313Sobrien	ac -= optind;
547109313Sobrien	av += optind;
548109313Sobrien	if (ac == 0 || flags == 0)
549109313Sobrien		usage();
550109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
551109313Sobrien	    fstat(fd, &sb) < 0)
552117009Sru		err(1, "%s", *av);
553275945Sbrueffer	cap_rights_init(&rights, CAP_MMAP_R);
554275945Sbrueffer	if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS)
555275945Sbrueffer		err(1, "unable to limit rights for %s", *av);
556275945Sbrueffer	close(STDIN_FILENO);
557275945Sbrueffer	cap_rights_init(&rights, CAP_WRITE);
558275945Sbrueffer	if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS)
559275945Sbrueffer		err(1, "unable to limit rights for stdout");
560275945Sbrueffer	if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS)
561275945Sbrueffer		err(1, "unable to limit rights for stderr");
562275945Sbrueffer	if (cap_enter() < 0 && errno != ENOSYS)
563275945Sbrueffer		err(1, "unable to enter capability mode");
564109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
565109313Sobrien	if (e == MAP_FAILED)
566109313Sobrien		err(1, NULL);
567109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
568109313Sobrien		errx(1, "not an elf file");
569109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
570109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
571109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
572109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
573109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
574110256Sobrien	p = (char *)e + phoff;
575267958Semaste	if (shoff > 0) {
576267958Semaste		sh = (char *)e + shoff;
577267958Semaste		shnum = elf_get_shnum(e, sh);
578267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
579267958Semaste		offset = elf_get_off(e, (char *)sh + shstrndx * shentsize,
580267958Semaste		    SH_OFFSET);
581267958Semaste		shstrtab = (char *)e + offset;
582267958Semaste	} else {
583267958Semaste		sh = NULL;
584267958Semaste		shnum = 0;
585267958Semaste		shstrndx = 0;
586267958Semaste		shstrtab = NULL;
587267958Semaste	}
588110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
589110256Sobrien		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
590110256Sobrien		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
591109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
592110252Sobrien			strtab = (char *)e + offset;
593109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
594110252Sobrien			dynstr = (char *)e + offset;
595109313Sobrien	}
596109313Sobrien	if (flags & ED_EHDR)
597267958Semaste		elf_print_ehdr(e, sh);
598109313Sobrien	if (flags & ED_PHDR)
599109313Sobrien		elf_print_phdr(e, p);
600109313Sobrien	if (flags & ED_SHDR)
601109313Sobrien		elf_print_shdr(e, sh);
602110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
603110256Sobrien		v = (char *)p + i * phentsize;
604109313Sobrien		type = elf_get_word(e, v, P_TYPE);
605109313Sobrien		switch (type) {
606109313Sobrien		case PT_INTERP:
607109313Sobrien			if (flags & ED_INTERP)
608109313Sobrien				elf_print_interp(e, v);
609109313Sobrien			break;
610109313Sobrien		case PT_NULL:
611109313Sobrien		case PT_LOAD:
612109313Sobrien		case PT_DYNAMIC:
613109313Sobrien		case PT_NOTE:
614109313Sobrien		case PT_SHLIB:
615109313Sobrien		case PT_PHDR:
616109313Sobrien			break;
617109313Sobrien		}
618109313Sobrien	}
619110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
620110256Sobrien		v = (char *)sh + i * shentsize;
621109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
622109313Sobrien		switch (type) {
623109313Sobrien		case SHT_SYMTAB:
624109313Sobrien			if (flags & ED_SYMTAB)
625109313Sobrien				elf_print_symtab(e, v, strtab);
626109313Sobrien			break;
627109313Sobrien		case SHT_DYNAMIC:
628109313Sobrien			if (flags & ED_DYN)
629109313Sobrien				elf_print_dynamic(e, v);
630109313Sobrien			break;
631109313Sobrien		case SHT_RELA:
632109313Sobrien			if (flags & ED_REL)
633109313Sobrien				elf_print_rela(e, v);
634109313Sobrien			break;
635109313Sobrien		case SHT_REL:
636109313Sobrien			if (flags & ED_REL)
637109313Sobrien				elf_print_rel(e, v);
638109313Sobrien			break;
639109313Sobrien		case SHT_NOTE:
640109313Sobrien			name = elf_get_word(e, v, SH_NAME);
641109313Sobrien			if (flags & ED_NOTE &&
642109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
643109313Sobrien				elf_print_note(e, v);
644109313Sobrien			break;
645109313Sobrien		case SHT_DYNSYM:
646109313Sobrien			if (flags & ED_SYMTAB)
647109313Sobrien				elf_print_symtab(e, v, dynstr);
648109313Sobrien			break;
649109313Sobrien		case SHT_PROGBITS:
650109313Sobrien			name = elf_get_word(e, v, SH_NAME);
651109313Sobrien			if (flags & ED_GOT &&
652109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
653109313Sobrien				elf_print_got(e, v);
654109313Sobrien			break;
655109313Sobrien		case SHT_HASH:
656109313Sobrien			if (flags & ED_HASH)
657109313Sobrien				elf_print_hash(e, v);
658109313Sobrien			break;
659109313Sobrien		case SHT_NULL:
660109313Sobrien		case SHT_STRTAB:
661109313Sobrien		case SHT_NOBITS:
662109313Sobrien		case SHT_SHLIB:
663109313Sobrien			break;
664109313Sobrien		}
665109313Sobrien	}
666109313Sobrien
667109313Sobrien	return 0;
668109313Sobrien}
669109313Sobrien
670241737Sedstatic void
671267958Semasteelf_print_ehdr(Elf32_Ehdr *e, void *sh)
672109313Sobrien{
673109313Sobrien	u_int64_t class;
674109313Sobrien	u_int64_t data;
675109313Sobrien	u_int64_t osabi;
676109313Sobrien	u_int64_t type;
677109313Sobrien	u_int64_t machine;
678109313Sobrien	u_int64_t version;
679109313Sobrien	u_int64_t entry;
680109313Sobrien	u_int64_t phoff;
681109313Sobrien	u_int64_t shoff;
682109313Sobrien	u_int64_t flags;
683109313Sobrien	u_int64_t ehsize;
684109313Sobrien	u_int64_t phentsize;
685109313Sobrien	u_int64_t phnum;
686109313Sobrien	u_int64_t shentsize;
687109313Sobrien	u_int64_t shnum;
688109313Sobrien	u_int64_t shstrndx;
689109313Sobrien
690109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
691109313Sobrien	data = elf_get_byte(e, e, E_DATA);
692109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
693109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
694109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
695109313Sobrien	version = elf_get_word(e, e, E_VERSION);
696109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
697109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
698109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
699109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
700109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
701109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
702109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
703109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
704109313Sobrien	fprintf(out, "\nelf header:\n");
705109313Sobrien	fprintf(out, "\n");
706109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
707109313Sobrien	    ei_abis[osabi]);
708109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
709109457Smarcel	fprintf(out, "\te_machine: %s\n", e_machines(machine));
710109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
711110257Sobrien	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
712110257Sobrien	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
713110257Sobrien	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
714110257Sobrien	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
715110257Sobrien	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
716110257Sobrien	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
717110257Sobrien	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
718110257Sobrien	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
719267958Semaste	if (sh != NULL) {
720267958Semaste		shnum = elf_get_shnum(e, sh);
721267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
722267958Semaste		fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
723267958Semaste		fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
724267958Semaste	}
725109313Sobrien}
726109313Sobrien
727241737Sedstatic void
728110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p)
729109313Sobrien{
730109313Sobrien	u_int64_t phentsize;
731109313Sobrien	u_int64_t phnum;
732109313Sobrien	u_int64_t type;
733109313Sobrien	u_int64_t offset;
734109313Sobrien	u_int64_t vaddr;
735109313Sobrien	u_int64_t paddr;
736109313Sobrien	u_int64_t filesz;
737109313Sobrien	u_int64_t memsz;
738109313Sobrien	u_int64_t flags;
739109313Sobrien	u_int64_t align;
740109313Sobrien	void *v;
741109313Sobrien	int i;
742109313Sobrien
743109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
744109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
745109313Sobrien	fprintf(out, "\nprogram header:\n");
746110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
747110256Sobrien		v = (char *)p + i * phentsize;
748109313Sobrien		type = elf_get_word(e, v, P_TYPE);
749109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
750109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
751109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
752109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
753109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
754109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
755109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
756109313Sobrien		fprintf(out, "\n");
757109313Sobrien		fprintf(out, "entry: %d\n", i);
758109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
759110257Sobrien		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
760110257Sobrien		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
761110257Sobrien		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
762110257Sobrien		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
763110257Sobrien		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
764109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
765110257Sobrien		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
766109313Sobrien	}
767109313Sobrien}
768109313Sobrien
769241737Sedstatic void
770110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh)
771109313Sobrien{
772109313Sobrien	u_int64_t shentsize;
773109313Sobrien	u_int64_t shnum;
774109313Sobrien	u_int64_t name;
775109313Sobrien	u_int64_t type;
776109313Sobrien	u_int64_t flags;
777109313Sobrien	u_int64_t addr;
778109313Sobrien	u_int64_t offset;
779109313Sobrien	u_int64_t size;
780110256Sobrien	u_int64_t shlink;
781109313Sobrien	u_int64_t info;
782109313Sobrien	u_int64_t addralign;
783109313Sobrien	u_int64_t entsize;
784270969Semaste	u_int64_t machine;
785109313Sobrien	void *v;
786109313Sobrien	int i;
787109313Sobrien
788267958Semaste	if (sh == NULL) {
789267958Semaste		fprintf(out, "\nNo section headers\n");
790267958Semaste		return;
791267958Semaste	}
792267958Semaste
793270969Semaste	machine = elf_get_quarter(e, e, E_MACHINE);
794109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
795267958Semaste	shnum = elf_get_shnum(e, sh);
796109313Sobrien	fprintf(out, "\nsection header:\n");
797110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
798110256Sobrien		v = (char *)sh + i * shentsize;
799109313Sobrien		name = elf_get_word(e, v, SH_NAME);
800109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
801109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
802109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
803109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
804109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
805110256Sobrien		shlink = elf_get_word(e, v, SH_LINK);
806109313Sobrien		info = elf_get_word(e, v, SH_INFO);
807109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
808109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
809109313Sobrien		fprintf(out, "\n");
810109313Sobrien		fprintf(out, "entry: %d\n", i);
811109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
812270969Semaste		fprintf(out, "\tsh_type: %s\n", sh_types(machine, type));
813109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
814110257Sobrien		fprintf(out, "\tsh_addr: %#jx\n", addr);
815110257Sobrien		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
816110257Sobrien		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
817110257Sobrien		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
818110257Sobrien		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
819110257Sobrien		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
820110257Sobrien		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
821109313Sobrien	}
822109313Sobrien}
823109313Sobrien
824241737Sedstatic void
825110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
826109313Sobrien{
827109313Sobrien	u_int64_t offset;
828109313Sobrien	u_int64_t entsize;
829109313Sobrien	u_int64_t size;
830109313Sobrien	u_int64_t name;
831109313Sobrien	u_int64_t value;
832109313Sobrien	u_int64_t info;
833109313Sobrien	u_int64_t shndx;
834109313Sobrien	void *st;
835109313Sobrien	int len;
836109313Sobrien	int i;
837109313Sobrien
838109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
839109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
840109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
841109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
842109313Sobrien	len = size / entsize;
843109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
844109313Sobrien	for (i = 0; i < len; i++) {
845110256Sobrien		st = (char *)e + offset + i * entsize;
846109313Sobrien		name = elf_get_word(e, st, ST_NAME);
847109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
848109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
849109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
850109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
851109313Sobrien		fprintf(out, "\n");
852109313Sobrien		fprintf(out, "entry: %d\n", i);
853109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
854110257Sobrien		fprintf(out, "\tst_value: %#jx\n", value);
855110257Sobrien		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
856109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
857109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
858109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
859110257Sobrien		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
860109313Sobrien	}
861109313Sobrien}
862109313Sobrien
863241737Sedstatic void
864110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh)
865109313Sobrien{
866109313Sobrien	u_int64_t offset;
867109313Sobrien	u_int64_t entsize;
868109313Sobrien	u_int64_t size;
869109313Sobrien	int64_t tag;
870109313Sobrien	u_int64_t ptr;
871109313Sobrien	u_int64_t val;
872109313Sobrien	void *d;
873109313Sobrien	int i;
874109313Sobrien
875109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
876109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
877109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
878109313Sobrien	fprintf(out, "\ndynamic:\n");
879110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
880110256Sobrien		d = (char *)e + offset + i * entsize;
881109313Sobrien		tag = elf_get_size(e, d, D_TAG);
882109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
883109313Sobrien		val = elf_get_addr(e, d, D_VAL);
884109313Sobrien		fprintf(out, "\n");
885109313Sobrien		fprintf(out, "entry: %d\n", i);
886109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
887109313Sobrien		switch (tag) {
888109313Sobrien		case DT_NEEDED:
889109313Sobrien		case DT_SONAME:
890109313Sobrien		case DT_RPATH:
891109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
892109313Sobrien			break;
893109313Sobrien		case DT_PLTRELSZ:
894109313Sobrien		case DT_RELA:
895109313Sobrien		case DT_RELASZ:
896109313Sobrien		case DT_RELAENT:
897109313Sobrien		case DT_STRSZ:
898109313Sobrien		case DT_SYMENT:
899109313Sobrien		case DT_RELSZ:
900109313Sobrien		case DT_RELENT:
901109313Sobrien		case DT_PLTREL:
902110257Sobrien			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
903109313Sobrien			break;
904109313Sobrien		case DT_PLTGOT:
905109313Sobrien		case DT_HASH:
906109313Sobrien		case DT_STRTAB:
907109313Sobrien		case DT_SYMTAB:
908109313Sobrien		case DT_INIT:
909109313Sobrien		case DT_FINI:
910109313Sobrien		case DT_REL:
911109313Sobrien		case DT_JMPREL:
912110257Sobrien			fprintf(out, "\td_ptr: %#jx\n", ptr);
913109313Sobrien			break;
914109313Sobrien		case DT_NULL:
915109313Sobrien		case DT_SYMBOLIC:
916109313Sobrien		case DT_DEBUG:
917109313Sobrien		case DT_TEXTREL:
918109313Sobrien			break;
919109313Sobrien		}
920109313Sobrien	}
921109313Sobrien}
922109313Sobrien
923241737Sedstatic void
924110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh)
925109313Sobrien{
926109313Sobrien	u_int64_t offset;
927109313Sobrien	u_int64_t entsize;
928109313Sobrien	u_int64_t size;
929109313Sobrien	u_int64_t name;
930109313Sobrien	u_int64_t info;
931109313Sobrien	int64_t addend;
932109313Sobrien	void *ra;
933109313Sobrien	void *v;
934109313Sobrien	int i;
935109313Sobrien
936109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
937109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
938109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
939109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
940110256Sobrien	v = (char *)e + offset;
941109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
942110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
943110256Sobrien		ra = (char *)v + i * entsize;
944109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
945109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
946109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
947109313Sobrien		fprintf(out, "\n");
948109313Sobrien		fprintf(out, "entry: %d\n", i);
949110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
950110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
951110257Sobrien		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
952109313Sobrien	}
953109313Sobrien}
954109313Sobrien
955241737Sedstatic void
956110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh)
957109313Sobrien{
958109313Sobrien	u_int64_t offset;
959109313Sobrien	u_int64_t entsize;
960109313Sobrien	u_int64_t size;
961109313Sobrien	u_int64_t name;
962109313Sobrien	u_int64_t info;
963109313Sobrien	void *r;
964109313Sobrien	void *v;
965109313Sobrien	int i;
966109313Sobrien
967109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
968109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
969109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
970109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
971110256Sobrien	v = (char *)e + offset;
972109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
973110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
974110256Sobrien		r = (char *)v + i * entsize;
975109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
976109313Sobrien		info = elf_get_word(e, r, R_INFO);
977109313Sobrien		fprintf(out, "\n");
978109313Sobrien		fprintf(out, "entry: %d\n", i);
979110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
980110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
981109313Sobrien	}
982109313Sobrien}
983109313Sobrien
984241737Sedstatic void
985110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p)
986109313Sobrien{
987109313Sobrien	u_int64_t offset;
988109313Sobrien	char *s;
989109313Sobrien
990109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
991110252Sobrien	s = (char *)e + offset;
992109313Sobrien	fprintf(out, "\ninterp:\n");
993109313Sobrien	fprintf(out, "\t%s\n", s);
994109313Sobrien}
995109313Sobrien
996241737Sedstatic void
997110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh)
998109313Sobrien{
999109313Sobrien	u_int64_t offset;
1000109313Sobrien	u_int64_t addralign;
1001109313Sobrien	u_int64_t size;
1002109313Sobrien	u_int64_t addr;
1003109313Sobrien	void *v;
1004109313Sobrien	int i;
1005109313Sobrien
1006109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
1007109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
1008109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
1009110256Sobrien	v = (char *)e + offset;
1010109313Sobrien	fprintf(out, "\nglobal offset table:\n");
1011110256Sobrien	for (i = 0; (u_int64_t)i < size / addralign; i++) {
1012110256Sobrien		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
1013109313Sobrien		fprintf(out, "\n");
1014109313Sobrien		fprintf(out, "entry: %d\n", i);
1015110257Sobrien		fprintf(out, "\t%#jx\n", addr);
1016109313Sobrien	}
1017109313Sobrien}
1018109313Sobrien
1019241737Sedstatic void
1020110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
1021109313Sobrien{
1022109313Sobrien}
1023109313Sobrien
1024241737Sedstatic void
1025110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh)
1026109313Sobrien{
1027109313Sobrien	u_int64_t offset;
1028109313Sobrien	u_int64_t size;
1029109313Sobrien	u_int64_t name;
1030109313Sobrien	u_int32_t namesz;
1031109313Sobrien	u_int32_t descsz;
1032109313Sobrien	u_int32_t desc;
1033110256Sobrien	char *n, *s;
1034109313Sobrien
1035109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
1036109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
1037109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
1038110256Sobrien	n = (char *)e + offset;
1039109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
1040110256Sobrien 	while (n < ((char *)e + offset + size)) {
1041109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
1042109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
1043110256Sobrien 		s = n + sizeof(Elf_Note);
1044110256Sobrien 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
1045109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
1046109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
1047109313Sobrien	}
1048109313Sobrien}
1049109313Sobrien
1050241737Sedstatic u_int64_t
1051109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
1052109313Sobrien{
1053109313Sobrien	u_int64_t val;
1054109313Sobrien
1055109313Sobrien	val = 0;
1056109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1057109313Sobrien	case ELFCLASS32:
1058226434Smarcel		val = ((uint8_t *)base)[elf32_offsets[member]];
1059109313Sobrien		break;
1060109313Sobrien	case ELFCLASS64:
1061226434Smarcel		val = ((uint8_t *)base)[elf64_offsets[member]];
1062109313Sobrien		break;
1063109313Sobrien	case ELFCLASSNONE:
1064109313Sobrien		errx(1, "invalid class");
1065109313Sobrien	}
1066109313Sobrien
1067109313Sobrien	return val;
1068109313Sobrien}
1069109313Sobrien
1070241737Sedstatic u_int64_t
1071109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
1072109313Sobrien{
1073109313Sobrien	u_int64_t val;
1074109313Sobrien
1075109313Sobrien	val = 0;
1076109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1077109313Sobrien	case ELFCLASS32:
1078118680Smarcel		base = (char *)base + elf32_offsets[member];
1079109313Sobrien		switch (e->e_ident[EI_DATA]) {
1080109313Sobrien		case ELFDATA2MSB:
1081118680Smarcel			val = be16dec(base);
1082109313Sobrien			break;
1083109313Sobrien		case ELFDATA2LSB:
1084118680Smarcel			val = le16dec(base);
1085109313Sobrien			break;
1086109313Sobrien		case ELFDATANONE:
1087109313Sobrien			errx(1, "invalid data format");
1088109313Sobrien		}
1089109313Sobrien		break;
1090109313Sobrien	case ELFCLASS64:
1091118680Smarcel		base = (char *)base + elf64_offsets[member];
1092109313Sobrien		switch (e->e_ident[EI_DATA]) {
1093109313Sobrien		case ELFDATA2MSB:
1094118680Smarcel			val = be16dec(base);
1095109313Sobrien			break;
1096109313Sobrien		case ELFDATA2LSB:
1097118680Smarcel			val = le16dec(base);
1098109313Sobrien			break;
1099109313Sobrien		case ELFDATANONE:
1100109313Sobrien			errx(1, "invalid data format");
1101109313Sobrien		}
1102109313Sobrien		break;
1103109313Sobrien	case ELFCLASSNONE:
1104109313Sobrien		errx(1, "invalid class");
1105109313Sobrien	}
1106109313Sobrien
1107109313Sobrien	return val;
1108109313Sobrien}
1109109313Sobrien
1110241737Sed#if 0
1111241737Sedstatic u_int64_t
1112109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
1113109313Sobrien{
1114109313Sobrien	u_int64_t val;
1115109313Sobrien
1116109313Sobrien	val = 0;
1117109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1118109313Sobrien	case ELFCLASS32:
1119118680Smarcel		base = (char *)base + elf32_offsets[member];
1120109313Sobrien		switch (e->e_ident[EI_DATA]) {
1121109313Sobrien		case ELFDATA2MSB:
1122118680Smarcel			val = be16dec(base);
1123109313Sobrien			break;
1124109313Sobrien		case ELFDATA2LSB:
1125118680Smarcel			val = le16dec(base);
1126109313Sobrien			break;
1127109313Sobrien		case ELFDATANONE:
1128109313Sobrien			errx(1, "invalid data format");
1129109313Sobrien		}
1130109313Sobrien		break;
1131109313Sobrien	case ELFCLASS64:
1132118680Smarcel		base = (char *)base + elf64_offsets[member];
1133109313Sobrien		switch (e->e_ident[EI_DATA]) {
1134109313Sobrien		case ELFDATA2MSB:
1135118680Smarcel			val = be32dec(base);
1136109313Sobrien			break;
1137109313Sobrien		case ELFDATA2LSB:
1138118680Smarcel			val = le32dec(base);
1139109313Sobrien			break;
1140109313Sobrien		case ELFDATANONE:
1141109313Sobrien			errx(1, "invalid data format");
1142109313Sobrien		}
1143109313Sobrien		break;
1144109313Sobrien	case ELFCLASSNONE:
1145109313Sobrien		errx(1, "invalid class");
1146109313Sobrien	}
1147109313Sobrien
1148109313Sobrien	return val;
1149109313Sobrien}
1150241737Sed#endif
1151109313Sobrien
1152241737Sedstatic u_int64_t
1153109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1154109313Sobrien{
1155109313Sobrien	u_int64_t val;
1156109313Sobrien
1157109313Sobrien	val = 0;
1158109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1159109313Sobrien	case ELFCLASS32:
1160118680Smarcel		base = (char *)base + elf32_offsets[member];
1161109313Sobrien		switch (e->e_ident[EI_DATA]) {
1162109313Sobrien		case ELFDATA2MSB:
1163118680Smarcel			val = be32dec(base);
1164109313Sobrien			break;
1165109313Sobrien		case ELFDATA2LSB:
1166118680Smarcel			val = le32dec(base);
1167109313Sobrien			break;
1168109313Sobrien		case ELFDATANONE:
1169109313Sobrien			errx(1, "invalid data format");
1170109313Sobrien		}
1171109313Sobrien		break;
1172109313Sobrien	case ELFCLASS64:
1173118680Smarcel		base = (char *)base + elf64_offsets[member];
1174109313Sobrien		switch (e->e_ident[EI_DATA]) {
1175109313Sobrien		case ELFDATA2MSB:
1176118680Smarcel			val = be32dec(base);
1177109313Sobrien			break;
1178109313Sobrien		case ELFDATA2LSB:
1179118680Smarcel			val = le32dec(base);
1180109313Sobrien			break;
1181109313Sobrien		case ELFDATANONE:
1182109313Sobrien			errx(1, "invalid data format");
1183109313Sobrien		}
1184109313Sobrien		break;
1185109313Sobrien	case ELFCLASSNONE:
1186109313Sobrien		errx(1, "invalid class");
1187109313Sobrien	}
1188109313Sobrien
1189109313Sobrien	return val;
1190109313Sobrien}
1191109313Sobrien
1192241737Sedstatic u_int64_t
1193109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1194109313Sobrien{
1195109313Sobrien	u_int64_t val;
1196109313Sobrien
1197109313Sobrien	val = 0;
1198109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1199109313Sobrien	case ELFCLASS32:
1200118680Smarcel		base = (char *)base + elf32_offsets[member];
1201109313Sobrien		switch (e->e_ident[EI_DATA]) {
1202109313Sobrien		case ELFDATA2MSB:
1203118680Smarcel			val = be32dec(base);
1204109313Sobrien			break;
1205109313Sobrien		case ELFDATA2LSB:
1206118680Smarcel			val = le32dec(base);
1207109313Sobrien			break;
1208109313Sobrien		case ELFDATANONE:
1209109313Sobrien			errx(1, "invalid data format");
1210109313Sobrien		}
1211109313Sobrien		break;
1212109313Sobrien	case ELFCLASS64:
1213118680Smarcel		base = (char *)base + elf64_offsets[member];
1214109313Sobrien		switch (e->e_ident[EI_DATA]) {
1215109313Sobrien		case ELFDATA2MSB:
1216118680Smarcel			val = be64dec(base);
1217109313Sobrien			break;
1218109313Sobrien		case ELFDATA2LSB:
1219118680Smarcel			val = le64dec(base);
1220109313Sobrien			break;
1221109313Sobrien		case ELFDATANONE:
1222109313Sobrien			errx(1, "invalid data format");
1223109313Sobrien		}
1224109313Sobrien		break;
1225109313Sobrien	case ELFCLASSNONE:
1226109313Sobrien		errx(1, "invalid class");
1227109313Sobrien	}
1228109313Sobrien
1229109313Sobrien	return val;
1230109313Sobrien}
1231109313Sobrien
1232241737Sedstatic void
1233109313Sobrienusage(void)
1234109313Sobrien{
1235117009Sru	fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n");
1236109313Sobrien	exit(1);
1237109313Sobrien}
1238