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$");
30109313Sobrien
31109313Sobrien#include <sys/types.h>
32109313Sobrien#include <sys/elf32.h>
33109313Sobrien#include <sys/elf64.h>
34118680Smarcel#include <sys/endian.h>
35109313Sobrien#include <sys/mman.h>
36109313Sobrien#include <sys/stat.h>
37109313Sobrien#include <err.h>
38109313Sobrien#include <fcntl.h>
39110257Sobrien#include <inttypes.h>
40109313Sobrien#include <stddef.h>
41109313Sobrien#include <stdio.h>
42109313Sobrien#include <stdlib.h>
43109313Sobrien#include <string.h>
44109313Sobrien#include <unistd.h>
45109313Sobrien
46109313Sobrien#define	ED_DYN		(1<<0)
47109313Sobrien#define	ED_EHDR		(1<<1)
48109313Sobrien#define	ED_GOT		(1<<2)
49109313Sobrien#define	ED_HASH		(1<<3)
50109313Sobrien#define	ED_INTERP	(1<<4)
51109313Sobrien#define	ED_NOTE		(1<<5)
52109313Sobrien#define	ED_PHDR		(1<<6)
53109313Sobrien#define	ED_REL		(1<<7)
54109313Sobrien#define	ED_SHDR		(1<<8)
55109313Sobrien#define	ED_SYMTAB	(1<<9)
56109313Sobrien#define	ED_ALL		((1<<10)-1)
57109313Sobrien
58109313Sobrien#define	elf_get_addr	elf_get_quad
59109313Sobrien#define	elf_get_off	elf_get_quad
60109313Sobrien#define	elf_get_size	elf_get_quad
61109313Sobrien
62109313Sobrienenum elf_member {
63109313Sobrien	D_TAG = 1, D_PTR, D_VAL,
64109313Sobrien
65109313Sobrien	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
66109313Sobrien	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
67109313Sobrien	E_SHNUM, E_SHSTRNDX,
68109313Sobrien
69109313Sobrien	N_NAMESZ, N_DESCSZ, N_TYPE,
70109313Sobrien
71109313Sobrien	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
72109313Sobrien	P_ALIGN,
73109313Sobrien
74109313Sobrien	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
75109313Sobrien	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
76109313Sobrien
77109313Sobrien	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
78109313Sobrien
79109313Sobrien	R_OFFSET, R_INFO,
80109313Sobrien
81109313Sobrien	RA_OFFSET, RA_INFO, RA_ADDEND
82109313Sobrien};
83109313Sobrien
84109313Sobrientypedef enum elf_member elf_member_t;
85109313Sobrien
86241737Sedstatic int elf32_offsets[] = {
87109313Sobrien	0,
88109313Sobrien
89109313Sobrien	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
90109313Sobrien	offsetof(Elf32_Dyn, d_un.d_val),
91109313Sobrien
92109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
93109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
94109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
95109313Sobrien	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
96109313Sobrien	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
97109313Sobrien	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
98109313Sobrien	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
99109313Sobrien	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
100109313Sobrien	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
101109313Sobrien	offsetof(Elf32_Ehdr, e_shstrndx),
102109313Sobrien
103109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
104109313Sobrien	offsetof(Elf_Note, n_type),
105109313Sobrien
106109313Sobrien	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
107109313Sobrien	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
108109313Sobrien	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
109109313Sobrien	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
110109313Sobrien
111109313Sobrien	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
112109313Sobrien	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
113109313Sobrien	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
114109313Sobrien	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
115109313Sobrien	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
116109313Sobrien
117109313Sobrien	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
118109313Sobrien	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
119109313Sobrien	offsetof(Elf32_Sym, st_shndx),
120119794Sschweikh
121109313Sobrien	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
122109313Sobrien
123109313Sobrien	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
124109313Sobrien	offsetof(Elf32_Rela, r_addend)
125109313Sobrien};
126109313Sobrien
127241737Sedstatic int elf64_offsets[] = {
128109313Sobrien	0,
129109313Sobrien
130109313Sobrien	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
131109313Sobrien	offsetof(Elf64_Dyn, d_un.d_val),
132119794Sschweikh
133109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
134109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
135109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
136109313Sobrien	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
137109313Sobrien	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
138109313Sobrien	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
139109313Sobrien	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
140109313Sobrien	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
141109313Sobrien	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
142109313Sobrien	offsetof(Elf64_Ehdr, e_shstrndx),
143109313Sobrien
144109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
145109313Sobrien	offsetof(Elf_Note, n_type),
146109313Sobrien
147109313Sobrien	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
148109313Sobrien	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
149109313Sobrien	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
150109313Sobrien	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
151109313Sobrien
152109313Sobrien	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
153109313Sobrien	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
154109313Sobrien	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
155109313Sobrien	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
156109313Sobrien	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
157109313Sobrien
158109313Sobrien	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
159109313Sobrien	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
160109313Sobrien	offsetof(Elf64_Sym, st_shndx),
161119794Sschweikh
162109313Sobrien	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
163109313Sobrien
164109313Sobrien	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
165109313Sobrien	offsetof(Elf64_Rela, r_addend)
166109313Sobrien};
167109313Sobrien
168109332Sobrien/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
169110256Sobrienstatic const char *
170270969Semasted_tags(u_int64_t tag)
171270969Semaste{
172270969Semaste	static char unknown_tag[48];
173270969Semaste
174109332Sobrien	switch (tag) {
175270969Semaste	case DT_NULL:		return "DT_NULL";
176270969Semaste	case DT_NEEDED:		return "DT_NEEDED";
177270969Semaste	case DT_PLTRELSZ:	return "DT_PLTRELSZ";
178270969Semaste	case DT_PLTGOT:		return "DT_PLTGOT";
179270969Semaste	case DT_HASH:		return "DT_HASH";
180270969Semaste	case DT_STRTAB:		return "DT_STRTAB";
181270969Semaste	case DT_SYMTAB:		return "DT_SYMTAB";
182270969Semaste	case DT_RELA:		return "DT_RELA";
183270969Semaste	case DT_RELASZ:		return "DT_RELASZ";
184270969Semaste	case DT_RELAENT:	return "DT_RELAENT";
185270969Semaste	case DT_STRSZ:		return "DT_STRSZ";
186270969Semaste	case DT_SYMENT:		return "DT_SYMENT";
187270969Semaste	case DT_INIT:		return "DT_INIT";
188270969Semaste	case DT_FINI:		return "DT_FINI";
189270969Semaste	case DT_SONAME:		return "DT_SONAME";
190270969Semaste	case DT_RPATH:		return "DT_RPATH";
191270969Semaste	case DT_SYMBOLIC:	return "DT_SYMBOLIC";
192270969Semaste	case DT_REL:		return "DT_REL";
193270969Semaste	case DT_RELSZ:		return "DT_RELSZ";
194270969Semaste	case DT_RELENT:		return "DT_RELENT";
195270969Semaste	case DT_PLTREL:		return "DT_PLTREL";
196270969Semaste	case DT_DEBUG:		return "DT_DEBUG";
197270969Semaste	case DT_TEXTREL:	return "DT_TEXTREL";
198270969Semaste	case DT_JMPREL:		return "DT_JMPREL";
199270969Semaste	case DT_BIND_NOW:	return "DT_BIND_NOW";
200270969Semaste	case DT_INIT_ARRAY:	return "DT_INIT_ARRAY";
201270969Semaste	case DT_FINI_ARRAY:	return "DT_FINI_ARRAY";
202270969Semaste	case DT_INIT_ARRAYSZ:	return "DT_INIT_ARRAYSZ";
203270969Semaste	case DT_FINI_ARRAYSZ:	return "DT_FINI_ARRAYSZ";
204270969Semaste	case DT_RUNPATH:	return "DT_RUNPATH";
205270969Semaste	case DT_FLAGS:		return "DT_FLAGS";
206270969Semaste	case DT_PREINIT_ARRAY:	return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */
207270969Semaste	case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ";
208109332Sobrien	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
209270969Semaste	case 0x6ffffdf5:	return "DT_GNU_PRELINKED";
210270969Semaste	case 0x6ffffdf6:	return "DT_GNU_CONFLICTSZ";
211270969Semaste	case 0x6ffffdf7:	return "DT_GNU_LIBLISTSZ";
212270969Semaste	case 0x6ffffdf8:	return "DT_SUNW_CHECKSUM";
213270969Semaste	case DT_PLTPADSZ:	return "DT_PLTPADSZ";
214270969Semaste	case DT_MOVEENT:	return "DT_MOVEENT";
215270969Semaste	case DT_MOVESZ:		return "DT_MOVESZ";
216270969Semaste	case DT_FEATURE:	return "DT_FEATURE";
217270969Semaste	case DT_POSFLAG_1:	return "DT_POSFLAG_1";
218270969Semaste	case DT_SYMINSZ:	return "DT_SYMINSZ";
219270969Semaste	case DT_SYMINENT :	return "DT_SYMINENT (DT_VALRNGHI)";
220270969Semaste	case DT_ADDRRNGLO:	return "DT_ADDRRNGLO";
221270969Semaste	case DT_GNU_HASH:	return "DT_GNU_HASH";
222270969Semaste	case 0x6ffffef8:	return "DT_GNU_CONFLICT";
223270969Semaste	case 0x6ffffef9:	return "DT_GNU_LIBLIST";
224270969Semaste	case DT_CONFIG:		return "DT_CONFIG";
225270969Semaste	case DT_DEPAUDIT:	return "DT_DEPAUDIT";
226270969Semaste	case DT_AUDIT:		return "DT_AUDIT";
227270969Semaste	case DT_PLTPAD:		return "DT_PLTPAD";
228270969Semaste	case DT_MOVETAB:	return "DT_MOVETAB";
229270969Semaste	case DT_SYMINFO :	return "DT_SYMINFO (DT_ADDRRNGHI)";
230270969Semaste	case DT_RELACOUNT:	return "DT_RELACOUNT";
231270969Semaste	case DT_RELCOUNT:	return "DT_RELCOUNT";
232270969Semaste	case DT_FLAGS_1:	return "DT_FLAGS_1";
233270969Semaste	case DT_VERDEF:		return "DT_VERDEF";
234270969Semaste	case DT_VERDEFNUM:	return "DT_VERDEFNUM";
235270969Semaste	case DT_VERNEED:	return "DT_VERNEED";
236270969Semaste	case DT_VERNEEDNUM:	return "DT_VERNEEDNUM";
237270969Semaste	case 0x6ffffff0:	return "DT_GNU_VERSYM";
238109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
239270969Semaste	case 0x70000000:	return "DT_IA_64_PLT_RESERVE";
240270969Semaste	case 0x7ffffffd:	return "DT_SUNW_AUXILIARY";
241270969Semaste	case 0x7ffffffe:	return "DT_SUNW_USED";
242270969Semaste	case 0x7fffffff:	return "DT_SUNW_FILTER";
243109332Sobrien	}
244270969Semaste	snprintf(unknown_tag, sizeof(unknown_tag),
245270969Semaste		"ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag);
246270969Semaste	return (unknown_tag);
247119794Sschweikh}
248109313Sobrien
249110256Sobrienstatic const char *
250109457Smarcele_machines(u_int mach)
251109457Smarcel{
252153500Smarcel	static char machdesc[64];
253153500Smarcel
254109457Smarcel	switch (mach) {
255109457Smarcel	case EM_NONE:	return "EM_NONE";
256109457Smarcel	case EM_M32:	return "EM_M32";
257109457Smarcel	case EM_SPARC:	return "EM_SPARC";
258109457Smarcel	case EM_386:	return "EM_386";
259109457Smarcel	case EM_68K:	return "EM_68K";
260109457Smarcel	case EM_88K:	return "EM_88K";
261109457Smarcel	case EM_860:	return "EM_860";
262109457Smarcel	case EM_MIPS:	return "EM_MIPS";
263153500Smarcel	case EM_PPC:	return "EM_PPC";
264261002Sjhibbits	case EM_PPC64:	return "EM_PPC64";
265153500Smarcel	case EM_ARM:	return "EM_ARM";
266153500Smarcel	case EM_ALPHA:	return "EM_ALPHA (legacy)";
267153500Smarcel	case EM_SPARCV9:return "EM_SPARCV9";
268109457Smarcel	case EM_IA_64:	return "EM_IA_64";
269153500Smarcel	case EM_X86_64:	return "EM_X86_64";
270270969Semaste	case EM_AARCH64:return "EM_AARCH64";
271109457Smarcel	}
272153500Smarcel	snprintf(machdesc, sizeof(machdesc),
273153500Smarcel	    "(unknown machine) -- type 0x%x", mach);
274153500Smarcel	return (machdesc);
275119794Sschweikh}
276109313Sobrien
277241737Sedstatic const char *e_types[] = {
278109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
279109313Sobrien};
280109313Sobrien
281241737Sedstatic const char *ei_versions[] = {
282109313Sobrien	"EV_NONE", "EV_CURRENT"
283109313Sobrien};
284109313Sobrien
285241737Sedstatic const char *ei_classes[] = {
286109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
287109313Sobrien};
288109313Sobrien
289241737Sedstatic const char *ei_data[] = {
290109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
291109313Sobrien};
292109313Sobrien
293241737Sedstatic const char *ei_abis[256] = {
294109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
295226434Smarcel	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX",
296226434Smarcel	"ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64",
297226434Smarcel	"ELFOSABI_MODESTO", "ELFOSABI_OPENBSD",
298226434Smarcel	[255] = "ELFOSABI_STANDALONE"
299109313Sobrien};
300109313Sobrien
301241737Sedstatic const char *p_types[] = {
302109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
303126484Sjake	"PT_SHLIB", "PT_PHDR", "PT_TLS"
304109313Sobrien};
305109313Sobrien
306241737Sedstatic const char *p_flags[] = {
307109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
308109313Sobrien	"PF_X|PF_W|PF_R"
309109313Sobrien};
310109313Sobrien
311109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
312110256Sobrienstatic const char *
313270969Semastesh_types(uint64_t machine, uint64_t sht) {
314270969Semaste	static char unknown_buf[64];
315270969Semaste
316270969Semaste	if (sht < 0x60000000) {
317270969Semaste		switch (sht) {
318270969Semaste		case SHT_NULL:		return "SHT_NULL";
319270969Semaste		case SHT_PROGBITS:	return "SHT_PROGBITS";
320270969Semaste		case SHT_SYMTAB:	return "SHT_SYMTAB";
321270969Semaste		case SHT_STRTAB:	return "SHT_STRTAB";
322270969Semaste		case SHT_RELA:		return "SHT_RELA";
323270969Semaste		case SHT_HASH:		return "SHT_HASH";
324270969Semaste		case SHT_DYNAMIC:	return "SHT_DYNAMIC";
325270969Semaste		case SHT_NOTE:		return "SHT_NOTE";
326270969Semaste		case SHT_NOBITS:	return "SHT_NOBITS";
327270969Semaste		case SHT_REL:		return "SHT_REL";
328270969Semaste		case SHT_SHLIB:		return "SHT_SHLIB";
329270969Semaste		case SHT_DYNSYM:	return "SHT_DYNSYM";
330270969Semaste		case SHT_INIT_ARRAY:	return "SHT_INIT_ARRAY";
331270969Semaste		case SHT_FINI_ARRAY:	return "SHT_FINI_ARRAY";
332270969Semaste		case SHT_PREINIT_ARRAY:	return "SHT_PREINIT_ARRAY";
333270969Semaste		case SHT_GROUP:		return "SHT_GROUP";
334270969Semaste		case SHT_SYMTAB_SHNDX:	return "SHT_SYMTAB_SHNDX";
335270969Semaste		}
336270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
337270969Semaste		    "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht);
338270969Semaste		return (unknown_buf);
339270969Semaste	} else if (sht < 0x70000000) {
340270969Semaste		/* 0x60000000-0x6fffffff operating system-specific semantics */
341270969Semaste		switch (sht) {
342270969Semaste		case 0x6ffffff0:	return "XXX:VERSYM";
343270969Semaste		case SHT_SUNW_dof:	return "SHT_SUNW_dof";
344270969Semaste		case SHT_GNU_HASH:	return "SHT_GNU_HASH";
345270969Semaste		case 0x6ffffff7:	return "SHT_GNU_LIBLIST";
346270969Semaste		case 0x6ffffffc:	return "XXX:VERDEF";
347270969Semaste		case SHT_SUNW_verdef:	return "SHT_SUNW(GNU)_verdef";
348270969Semaste		case SHT_SUNW_verneed:	return "SHT_SUNW(GNU)_verneed";
349270969Semaste		case SHT_SUNW_versym:	return "SHT_SUNW(GNU)_versym";
350270969Semaste		}
351270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
352270969Semaste		    "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED",
353270969Semaste		     (uintmax_t)sht);
354270969Semaste		return (unknown_buf);
355270969Semaste	} else if (sht < 0x80000000) {
356270969Semaste		/* 0x70000000-0x7fffffff processor-specific semantics */
357270969Semaste		switch (machine) {
358270969Semaste		case EM_ARM:
359270969Semaste			switch (sht) {
360270969Semaste			case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX";
361270969Semaste			case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP";
362270969Semaste			case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES";
363270969Semaste			case SHT_ARM_DEBUGOVERLAY:
364270969Semaste			    return "SHT_ARM_DEBUGOVERLAY";
365270969Semaste			case SHT_ARM_OVERLAYSECTION:
366270969Semaste			    return "SHT_ARM_OVERLAYSECTION";
367270969Semaste			}
368270969Semaste			break;
369270969Semaste		case EM_IA_64:
370270969Semaste			switch (sht) {
371270969Semaste			case 0x70000000: return "SHT_IA_64_EXT";
372270969Semaste			case 0x70000001: return "SHT_IA_64_UNWIND";
373270969Semaste			}
374270969Semaste			break;
375270969Semaste		case EM_MIPS:
376270969Semaste			switch (sht) {
377270969Semaste			case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS";
378270969Semaste			}
379270969Semaste			break;
380270969Semaste		}
381270969Semaste		switch (sht) {
382270969Semaste		case 0x7ffffffd: return "XXX:AUXILIARY";
383270969Semaste		case 0x7fffffff: return "XXX:FILTER";
384270969Semaste		}
385270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
386270969Semaste		    "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED",
387270969Semaste		     (uintmax_t)sht);
388270969Semaste		return (unknown_buf);
389270969Semaste	} else {
390270969Semaste		/* 0x80000000-0xffffffff application programs */
391270969Semaste		snprintf(unknown_buf, sizeof(unknown_buf),
392270969Semaste		    "ERROR: SHT 0x%jx NOT DEFINED",
393270969Semaste		     (uintmax_t)sht);
394270969Semaste		return (unknown_buf);
395109329Sobrien	}
396119795Sschweikh}
397109313Sobrien
398241737Sedstatic const char *sh_flags[] = {
399109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
400109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
401109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
402109313Sobrien};
403109313Sobrien
404241737Sedstatic const char *st_types[] = {
405109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
406109313Sobrien};
407109313Sobrien
408241737Sedstatic const char *st_bindings[] = {
409109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
410109313Sobrien};
411109313Sobrien
412241737Sedstatic char *dynstr;
413241737Sedstatic char *shstrtab;
414241737Sedstatic char *strtab;
415241737Sedstatic FILE *out;
416109313Sobrien
417241737Sedstatic u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
418241737Sedstatic u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base,
419241737Sed    elf_member_t member);
420241737Sed#if 0
421241737Sedstatic u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
422241737Sed#endif
423241737Sedstatic u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
424241737Sedstatic u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
425109313Sobrien
426267958Semastestatic void elf_print_ehdr(Elf32_Ehdr *e, void *sh);
427241737Sedstatic void elf_print_phdr(Elf32_Ehdr *e, void *p);
428241737Sedstatic void elf_print_shdr(Elf32_Ehdr *e, void *sh);
429241737Sedstatic void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
430241737Sedstatic void elf_print_dynamic(Elf32_Ehdr *e, void *sh);
431241737Sedstatic void elf_print_rel(Elf32_Ehdr *e, void *r);
432241737Sedstatic void elf_print_rela(Elf32_Ehdr *e, void *ra);
433241737Sedstatic void elf_print_interp(Elf32_Ehdr *e, void *p);
434241737Sedstatic void elf_print_got(Elf32_Ehdr *e, void *sh);
435241737Sedstatic void elf_print_hash(Elf32_Ehdr *e, void *sh);
436241737Sedstatic void elf_print_note(Elf32_Ehdr *e, void *sh);
437109313Sobrien
438241737Sedstatic void usage(void);
439109313Sobrien
440267958Semaste/*
441267958Semaste * Helpers for ELF files with shnum or shstrndx values that don't fit in the
442267958Semaste * ELF header.  If the values are too large then an escape value is used to
443267958Semaste * indicate that the actual value is found in one of section 0's fields.
444267958Semaste */
445267958Semastestatic uint64_t
446267958Semasteelf_get_shnum(Elf32_Ehdr *e, void *sh)
447267958Semaste{
448267958Semaste	uint64_t shnum;
449267958Semaste
450267958Semaste	shnum = elf_get_quarter(e, e, E_SHNUM);
451267958Semaste	if (shnum == 0)
452267958Semaste		shnum = elf_get_word(e, (char *)sh, SH_SIZE);
453267958Semaste	return shnum;
454267958Semaste}
455267958Semaste
456267958Semastestatic uint64_t
457267958Semasteelf_get_shstrndx(Elf32_Ehdr *e, void *sh)
458267958Semaste{
459267958Semaste	uint64_t shstrndx;
460267958Semaste
461267958Semaste	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
462267958Semaste	if (shstrndx == SHN_XINDEX)
463267958Semaste		shstrndx = elf_get_word(e, (char *)sh, SH_LINK);
464267958Semaste	return shstrndx;
465267958Semaste}
466267958Semaste
467109313Sobrienint
468109313Sobrienmain(int ac, char **av)
469109313Sobrien{
470109313Sobrien	u_int64_t phoff;
471109313Sobrien	u_int64_t shoff;
472109313Sobrien	u_int64_t phentsize;
473109313Sobrien	u_int64_t phnum;
474109313Sobrien	u_int64_t shentsize;
475109313Sobrien	u_int64_t shnum;
476109313Sobrien	u_int64_t shstrndx;
477109313Sobrien	u_int64_t offset;
478109313Sobrien	u_int64_t name;
479109313Sobrien	u_int64_t type;
480109313Sobrien	struct stat sb;
481109313Sobrien	u_int flags;
482110252Sobrien	Elf32_Ehdr *e;
483109313Sobrien	void *p;
484109313Sobrien	void *sh;
485109313Sobrien	void *v;
486109313Sobrien	int fd;
487109313Sobrien	int ch;
488109313Sobrien	int i;
489109313Sobrien
490109313Sobrien	out = stdout;
491109313Sobrien	flags = 0;
492109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
493109313Sobrien		switch (ch) {
494109313Sobrien		case 'a':
495109313Sobrien			flags = ED_ALL;
496109313Sobrien			break;
497109313Sobrien		case 'c':
498109313Sobrien			flags |= ED_SHDR;
499109313Sobrien			break;
500109313Sobrien		case 'd':
501109313Sobrien			flags |= ED_DYN;
502109313Sobrien			break;
503109313Sobrien		case 'e':
504109313Sobrien			flags |= ED_EHDR;
505109313Sobrien			break;
506109313Sobrien		case 'i':
507109313Sobrien			flags |= ED_INTERP;
508109313Sobrien			break;
509109313Sobrien		case 'G':
510109313Sobrien			flags |= ED_GOT;
511109313Sobrien			break;
512109313Sobrien		case 'h':
513109313Sobrien			flags |= ED_HASH;
514109313Sobrien			break;
515109313Sobrien		case 'n':
516109313Sobrien			flags |= ED_NOTE;
517109313Sobrien			break;
518109313Sobrien		case 'p':
519109313Sobrien			flags |= ED_PHDR;
520109313Sobrien			break;
521109313Sobrien		case 'r':
522109313Sobrien			flags |= ED_REL;
523109313Sobrien			break;
524109313Sobrien		case 's':
525109313Sobrien			flags |= ED_SYMTAB;
526109313Sobrien			break;
527109313Sobrien		case 'w':
528109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
529109313Sobrien				err(1, "%s", optarg);
530109313Sobrien			break;
531109313Sobrien		case '?':
532109313Sobrien		default:
533109313Sobrien			usage();
534109313Sobrien		}
535109313Sobrien	ac -= optind;
536109313Sobrien	av += optind;
537109313Sobrien	if (ac == 0 || flags == 0)
538109313Sobrien		usage();
539109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
540109313Sobrien	    fstat(fd, &sb) < 0)
541117009Sru		err(1, "%s", *av);
542109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
543109313Sobrien	if (e == MAP_FAILED)
544109313Sobrien		err(1, NULL);
545109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
546109313Sobrien		errx(1, "not an elf file");
547109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
548109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
549109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
550109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
551109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
552110256Sobrien	p = (char *)e + phoff;
553267958Semaste	if (shoff > 0) {
554267958Semaste		sh = (char *)e + shoff;
555267958Semaste		shnum = elf_get_shnum(e, sh);
556267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
557267958Semaste		offset = elf_get_off(e, (char *)sh + shstrndx * shentsize,
558267958Semaste		    SH_OFFSET);
559267958Semaste		shstrtab = (char *)e + offset;
560267958Semaste	} else {
561267958Semaste		sh = NULL;
562267958Semaste		shnum = 0;
563267958Semaste		shstrndx = 0;
564267958Semaste		shstrtab = NULL;
565267958Semaste	}
566110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
567110256Sobrien		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
568110256Sobrien		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
569109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
570110252Sobrien			strtab = (char *)e + offset;
571109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
572110252Sobrien			dynstr = (char *)e + offset;
573109313Sobrien	}
574109313Sobrien	if (flags & ED_EHDR)
575267958Semaste		elf_print_ehdr(e, sh);
576109313Sobrien	if (flags & ED_PHDR)
577109313Sobrien		elf_print_phdr(e, p);
578109313Sobrien	if (flags & ED_SHDR)
579109313Sobrien		elf_print_shdr(e, sh);
580110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
581110256Sobrien		v = (char *)p + i * phentsize;
582109313Sobrien		type = elf_get_word(e, v, P_TYPE);
583109313Sobrien		switch (type) {
584109313Sobrien		case PT_INTERP:
585109313Sobrien			if (flags & ED_INTERP)
586109313Sobrien				elf_print_interp(e, v);
587109313Sobrien			break;
588109313Sobrien		case PT_NULL:
589109313Sobrien		case PT_LOAD:
590109313Sobrien		case PT_DYNAMIC:
591109313Sobrien		case PT_NOTE:
592109313Sobrien		case PT_SHLIB:
593109313Sobrien		case PT_PHDR:
594109313Sobrien			break;
595109313Sobrien		}
596109313Sobrien	}
597110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
598110256Sobrien		v = (char *)sh + i * shentsize;
599109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
600109313Sobrien		switch (type) {
601109313Sobrien		case SHT_SYMTAB:
602109313Sobrien			if (flags & ED_SYMTAB)
603109313Sobrien				elf_print_symtab(e, v, strtab);
604109313Sobrien			break;
605109313Sobrien		case SHT_DYNAMIC:
606109313Sobrien			if (flags & ED_DYN)
607109313Sobrien				elf_print_dynamic(e, v);
608109313Sobrien			break;
609109313Sobrien		case SHT_RELA:
610109313Sobrien			if (flags & ED_REL)
611109313Sobrien				elf_print_rela(e, v);
612109313Sobrien			break;
613109313Sobrien		case SHT_REL:
614109313Sobrien			if (flags & ED_REL)
615109313Sobrien				elf_print_rel(e, v);
616109313Sobrien			break;
617109313Sobrien		case SHT_NOTE:
618109313Sobrien			name = elf_get_word(e, v, SH_NAME);
619109313Sobrien			if (flags & ED_NOTE &&
620109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
621109313Sobrien				elf_print_note(e, v);
622109313Sobrien			break;
623109313Sobrien		case SHT_DYNSYM:
624109313Sobrien			if (flags & ED_SYMTAB)
625109313Sobrien				elf_print_symtab(e, v, dynstr);
626109313Sobrien			break;
627109313Sobrien		case SHT_PROGBITS:
628109313Sobrien			name = elf_get_word(e, v, SH_NAME);
629109313Sobrien			if (flags & ED_GOT &&
630109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
631109313Sobrien				elf_print_got(e, v);
632109313Sobrien			break;
633109313Sobrien		case SHT_HASH:
634109313Sobrien			if (flags & ED_HASH)
635109313Sobrien				elf_print_hash(e, v);
636109313Sobrien			break;
637109313Sobrien		case SHT_NULL:
638109313Sobrien		case SHT_STRTAB:
639109313Sobrien		case SHT_NOBITS:
640109313Sobrien		case SHT_SHLIB:
641109313Sobrien			break;
642109313Sobrien		}
643109313Sobrien	}
644109313Sobrien
645109313Sobrien	return 0;
646109313Sobrien}
647109313Sobrien
648241737Sedstatic void
649267958Semasteelf_print_ehdr(Elf32_Ehdr *e, void *sh)
650109313Sobrien{
651109313Sobrien	u_int64_t class;
652109313Sobrien	u_int64_t data;
653109313Sobrien	u_int64_t osabi;
654109313Sobrien	u_int64_t type;
655109313Sobrien	u_int64_t machine;
656109313Sobrien	u_int64_t version;
657109313Sobrien	u_int64_t entry;
658109313Sobrien	u_int64_t phoff;
659109313Sobrien	u_int64_t shoff;
660109313Sobrien	u_int64_t flags;
661109313Sobrien	u_int64_t ehsize;
662109313Sobrien	u_int64_t phentsize;
663109313Sobrien	u_int64_t phnum;
664109313Sobrien	u_int64_t shentsize;
665109313Sobrien	u_int64_t shnum;
666109313Sobrien	u_int64_t shstrndx;
667109313Sobrien
668109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
669109313Sobrien	data = elf_get_byte(e, e, E_DATA);
670109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
671109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
672109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
673109313Sobrien	version = elf_get_word(e, e, E_VERSION);
674109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
675109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
676109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
677109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
678109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
679109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
680109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
681109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
682109313Sobrien	fprintf(out, "\nelf header:\n");
683109313Sobrien	fprintf(out, "\n");
684109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
685109313Sobrien	    ei_abis[osabi]);
686109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
687109457Smarcel	fprintf(out, "\te_machine: %s\n", e_machines(machine));
688109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
689110257Sobrien	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
690110257Sobrien	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
691110257Sobrien	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
692110257Sobrien	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
693110257Sobrien	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
694110257Sobrien	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
695110257Sobrien	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
696110257Sobrien	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
697267958Semaste	if (sh != NULL) {
698267958Semaste		shnum = elf_get_shnum(e, sh);
699267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
700267958Semaste		fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
701267958Semaste		fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
702267958Semaste	}
703109313Sobrien}
704109313Sobrien
705241737Sedstatic void
706110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p)
707109313Sobrien{
708109313Sobrien	u_int64_t phentsize;
709109313Sobrien	u_int64_t phnum;
710109313Sobrien	u_int64_t type;
711109313Sobrien	u_int64_t offset;
712109313Sobrien	u_int64_t vaddr;
713109313Sobrien	u_int64_t paddr;
714109313Sobrien	u_int64_t filesz;
715109313Sobrien	u_int64_t memsz;
716109313Sobrien	u_int64_t flags;
717109313Sobrien	u_int64_t align;
718109313Sobrien	void *v;
719109313Sobrien	int i;
720109313Sobrien
721109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
722109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
723109313Sobrien	fprintf(out, "\nprogram header:\n");
724110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
725110256Sobrien		v = (char *)p + i * phentsize;
726109313Sobrien		type = elf_get_word(e, v, P_TYPE);
727109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
728109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
729109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
730109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
731109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
732109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
733109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
734109313Sobrien		fprintf(out, "\n");
735109313Sobrien		fprintf(out, "entry: %d\n", i);
736109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
737110257Sobrien		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
738110257Sobrien		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
739110257Sobrien		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
740110257Sobrien		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
741110257Sobrien		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
742109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
743110257Sobrien		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
744109313Sobrien	}
745109313Sobrien}
746109313Sobrien
747241737Sedstatic void
748110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh)
749109313Sobrien{
750109313Sobrien	u_int64_t shentsize;
751109313Sobrien	u_int64_t shnum;
752109313Sobrien	u_int64_t name;
753109313Sobrien	u_int64_t type;
754109313Sobrien	u_int64_t flags;
755109313Sobrien	u_int64_t addr;
756109313Sobrien	u_int64_t offset;
757109313Sobrien	u_int64_t size;
758110256Sobrien	u_int64_t shlink;
759109313Sobrien	u_int64_t info;
760109313Sobrien	u_int64_t addralign;
761109313Sobrien	u_int64_t entsize;
762270969Semaste	u_int64_t machine;
763109313Sobrien	void *v;
764109313Sobrien	int i;
765109313Sobrien
766267958Semaste	if (sh == NULL) {
767267958Semaste		fprintf(out, "\nNo section headers\n");
768267958Semaste		return;
769267958Semaste	}
770267958Semaste
771270969Semaste	machine = elf_get_quarter(e, e, E_MACHINE);
772109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
773267958Semaste	shnum = elf_get_shnum(e, sh);
774109313Sobrien	fprintf(out, "\nsection header:\n");
775110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
776110256Sobrien		v = (char *)sh + i * shentsize;
777109313Sobrien		name = elf_get_word(e, v, SH_NAME);
778109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
779109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
780109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
781109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
782109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
783110256Sobrien		shlink = elf_get_word(e, v, SH_LINK);
784109313Sobrien		info = elf_get_word(e, v, SH_INFO);
785109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
786109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
787109313Sobrien		fprintf(out, "\n");
788109313Sobrien		fprintf(out, "entry: %d\n", i);
789109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
790270969Semaste		fprintf(out, "\tsh_type: %s\n", sh_types(machine, type));
791109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
792110257Sobrien		fprintf(out, "\tsh_addr: %#jx\n", addr);
793110257Sobrien		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
794110257Sobrien		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
795110257Sobrien		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
796110257Sobrien		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
797110257Sobrien		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
798110257Sobrien		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
799109313Sobrien	}
800109313Sobrien}
801109313Sobrien
802241737Sedstatic void
803110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
804109313Sobrien{
805109313Sobrien	u_int64_t offset;
806109313Sobrien	u_int64_t entsize;
807109313Sobrien	u_int64_t size;
808109313Sobrien	u_int64_t name;
809109313Sobrien	u_int64_t value;
810109313Sobrien	u_int64_t info;
811109313Sobrien	u_int64_t shndx;
812109313Sobrien	void *st;
813109313Sobrien	int len;
814109313Sobrien	int i;
815109313Sobrien
816109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
817109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
818109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
819109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
820109313Sobrien	len = size / entsize;
821109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
822109313Sobrien	for (i = 0; i < len; i++) {
823110256Sobrien		st = (char *)e + offset + i * entsize;
824109313Sobrien		name = elf_get_word(e, st, ST_NAME);
825109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
826109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
827109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
828109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
829109313Sobrien		fprintf(out, "\n");
830109313Sobrien		fprintf(out, "entry: %d\n", i);
831109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
832110257Sobrien		fprintf(out, "\tst_value: %#jx\n", value);
833110257Sobrien		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
834109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
835109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
836109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
837110257Sobrien		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
838109313Sobrien	}
839109313Sobrien}
840109313Sobrien
841241737Sedstatic void
842110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh)
843109313Sobrien{
844109313Sobrien	u_int64_t offset;
845109313Sobrien	u_int64_t entsize;
846109313Sobrien	u_int64_t size;
847109313Sobrien	int64_t tag;
848109313Sobrien	u_int64_t ptr;
849109313Sobrien	u_int64_t val;
850109313Sobrien	void *d;
851109313Sobrien	int i;
852109313Sobrien
853109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
854109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
855109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
856109313Sobrien	fprintf(out, "\ndynamic:\n");
857110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
858110256Sobrien		d = (char *)e + offset + i * entsize;
859109313Sobrien		tag = elf_get_size(e, d, D_TAG);
860109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
861109313Sobrien		val = elf_get_addr(e, d, D_VAL);
862109313Sobrien		fprintf(out, "\n");
863109313Sobrien		fprintf(out, "entry: %d\n", i);
864109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
865109313Sobrien		switch (tag) {
866109313Sobrien		case DT_NEEDED:
867109313Sobrien		case DT_SONAME:
868109313Sobrien		case DT_RPATH:
869109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
870109313Sobrien			break;
871109313Sobrien		case DT_PLTRELSZ:
872109313Sobrien		case DT_RELA:
873109313Sobrien		case DT_RELASZ:
874109313Sobrien		case DT_RELAENT:
875109313Sobrien		case DT_STRSZ:
876109313Sobrien		case DT_SYMENT:
877109313Sobrien		case DT_RELSZ:
878109313Sobrien		case DT_RELENT:
879109313Sobrien		case DT_PLTREL:
880110257Sobrien			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
881109313Sobrien			break;
882109313Sobrien		case DT_PLTGOT:
883109313Sobrien		case DT_HASH:
884109313Sobrien		case DT_STRTAB:
885109313Sobrien		case DT_SYMTAB:
886109313Sobrien		case DT_INIT:
887109313Sobrien		case DT_FINI:
888109313Sobrien		case DT_REL:
889109313Sobrien		case DT_JMPREL:
890110257Sobrien			fprintf(out, "\td_ptr: %#jx\n", ptr);
891109313Sobrien			break;
892109313Sobrien		case DT_NULL:
893109313Sobrien		case DT_SYMBOLIC:
894109313Sobrien		case DT_DEBUG:
895109313Sobrien		case DT_TEXTREL:
896109313Sobrien			break;
897109313Sobrien		}
898109313Sobrien	}
899109313Sobrien}
900109313Sobrien
901241737Sedstatic void
902110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh)
903109313Sobrien{
904109313Sobrien	u_int64_t offset;
905109313Sobrien	u_int64_t entsize;
906109313Sobrien	u_int64_t size;
907109313Sobrien	u_int64_t name;
908109313Sobrien	u_int64_t info;
909109313Sobrien	int64_t addend;
910109313Sobrien	void *ra;
911109313Sobrien	void *v;
912109313Sobrien	int i;
913109313Sobrien
914109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
915109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
916109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
917109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
918110256Sobrien	v = (char *)e + offset;
919109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
920110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
921110256Sobrien		ra = (char *)v + i * entsize;
922109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
923109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
924109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
925109313Sobrien		fprintf(out, "\n");
926109313Sobrien		fprintf(out, "entry: %d\n", i);
927110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
928110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
929110257Sobrien		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
930109313Sobrien	}
931109313Sobrien}
932109313Sobrien
933241737Sedstatic void
934110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh)
935109313Sobrien{
936109313Sobrien	u_int64_t offset;
937109313Sobrien	u_int64_t entsize;
938109313Sobrien	u_int64_t size;
939109313Sobrien	u_int64_t name;
940109313Sobrien	u_int64_t info;
941109313Sobrien	void *r;
942109313Sobrien	void *v;
943109313Sobrien	int i;
944109313Sobrien
945109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
946109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
947109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
948109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
949110256Sobrien	v = (char *)e + offset;
950109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
951110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
952110256Sobrien		r = (char *)v + i * entsize;
953109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
954109313Sobrien		info = elf_get_word(e, r, R_INFO);
955109313Sobrien		fprintf(out, "\n");
956109313Sobrien		fprintf(out, "entry: %d\n", i);
957110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
958110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
959109313Sobrien	}
960109313Sobrien}
961109313Sobrien
962241737Sedstatic void
963110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p)
964109313Sobrien{
965109313Sobrien	u_int64_t offset;
966109313Sobrien	char *s;
967109313Sobrien
968109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
969110252Sobrien	s = (char *)e + offset;
970109313Sobrien	fprintf(out, "\ninterp:\n");
971109313Sobrien	fprintf(out, "\t%s\n", s);
972109313Sobrien}
973109313Sobrien
974241737Sedstatic void
975110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh)
976109313Sobrien{
977109313Sobrien	u_int64_t offset;
978109313Sobrien	u_int64_t addralign;
979109313Sobrien	u_int64_t size;
980109313Sobrien	u_int64_t addr;
981109313Sobrien	void *v;
982109313Sobrien	int i;
983109313Sobrien
984109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
985109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
986109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
987110256Sobrien	v = (char *)e + offset;
988109313Sobrien	fprintf(out, "\nglobal offset table:\n");
989110256Sobrien	for (i = 0; (u_int64_t)i < size / addralign; i++) {
990110256Sobrien		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
991109313Sobrien		fprintf(out, "\n");
992109313Sobrien		fprintf(out, "entry: %d\n", i);
993110257Sobrien		fprintf(out, "\t%#jx\n", addr);
994109313Sobrien	}
995109313Sobrien}
996109313Sobrien
997241737Sedstatic void
998110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
999109313Sobrien{
1000109313Sobrien}
1001109313Sobrien
1002241737Sedstatic void
1003110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh)
1004109313Sobrien{
1005109313Sobrien	u_int64_t offset;
1006109313Sobrien	u_int64_t size;
1007109313Sobrien	u_int64_t name;
1008109313Sobrien	u_int32_t namesz;
1009109313Sobrien	u_int32_t descsz;
1010109313Sobrien	u_int32_t desc;
1011110256Sobrien	char *n, *s;
1012109313Sobrien
1013109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
1014109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
1015109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
1016110256Sobrien	n = (char *)e + offset;
1017109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
1018110256Sobrien 	while (n < ((char *)e + offset + size)) {
1019109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
1020109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
1021110256Sobrien 		s = n + sizeof(Elf_Note);
1022110256Sobrien 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
1023109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
1024109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
1025109313Sobrien	}
1026109313Sobrien}
1027109313Sobrien
1028241737Sedstatic u_int64_t
1029109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
1030109313Sobrien{
1031109313Sobrien	u_int64_t val;
1032109313Sobrien
1033109313Sobrien	val = 0;
1034109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1035109313Sobrien	case ELFCLASS32:
1036226434Smarcel		val = ((uint8_t *)base)[elf32_offsets[member]];
1037109313Sobrien		break;
1038109313Sobrien	case ELFCLASS64:
1039226434Smarcel		val = ((uint8_t *)base)[elf64_offsets[member]];
1040109313Sobrien		break;
1041109313Sobrien	case ELFCLASSNONE:
1042109313Sobrien		errx(1, "invalid class");
1043109313Sobrien	}
1044109313Sobrien
1045109313Sobrien	return val;
1046109313Sobrien}
1047109313Sobrien
1048241737Sedstatic u_int64_t
1049109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
1050109313Sobrien{
1051109313Sobrien	u_int64_t val;
1052109313Sobrien
1053109313Sobrien	val = 0;
1054109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1055109313Sobrien	case ELFCLASS32:
1056118680Smarcel		base = (char *)base + elf32_offsets[member];
1057109313Sobrien		switch (e->e_ident[EI_DATA]) {
1058109313Sobrien		case ELFDATA2MSB:
1059118680Smarcel			val = be16dec(base);
1060109313Sobrien			break;
1061109313Sobrien		case ELFDATA2LSB:
1062118680Smarcel			val = le16dec(base);
1063109313Sobrien			break;
1064109313Sobrien		case ELFDATANONE:
1065109313Sobrien			errx(1, "invalid data format");
1066109313Sobrien		}
1067109313Sobrien		break;
1068109313Sobrien	case ELFCLASS64:
1069118680Smarcel		base = (char *)base + elf64_offsets[member];
1070109313Sobrien		switch (e->e_ident[EI_DATA]) {
1071109313Sobrien		case ELFDATA2MSB:
1072118680Smarcel			val = be16dec(base);
1073109313Sobrien			break;
1074109313Sobrien		case ELFDATA2LSB:
1075118680Smarcel			val = le16dec(base);
1076109313Sobrien			break;
1077109313Sobrien		case ELFDATANONE:
1078109313Sobrien			errx(1, "invalid data format");
1079109313Sobrien		}
1080109313Sobrien		break;
1081109313Sobrien	case ELFCLASSNONE:
1082109313Sobrien		errx(1, "invalid class");
1083109313Sobrien	}
1084109313Sobrien
1085109313Sobrien	return val;
1086109313Sobrien}
1087109313Sobrien
1088241737Sed#if 0
1089241737Sedstatic u_int64_t
1090109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
1091109313Sobrien{
1092109313Sobrien	u_int64_t val;
1093109313Sobrien
1094109313Sobrien	val = 0;
1095109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1096109313Sobrien	case ELFCLASS32:
1097118680Smarcel		base = (char *)base + elf32_offsets[member];
1098109313Sobrien		switch (e->e_ident[EI_DATA]) {
1099109313Sobrien		case ELFDATA2MSB:
1100118680Smarcel			val = be16dec(base);
1101109313Sobrien			break;
1102109313Sobrien		case ELFDATA2LSB:
1103118680Smarcel			val = le16dec(base);
1104109313Sobrien			break;
1105109313Sobrien		case ELFDATANONE:
1106109313Sobrien			errx(1, "invalid data format");
1107109313Sobrien		}
1108109313Sobrien		break;
1109109313Sobrien	case ELFCLASS64:
1110118680Smarcel		base = (char *)base + elf64_offsets[member];
1111109313Sobrien		switch (e->e_ident[EI_DATA]) {
1112109313Sobrien		case ELFDATA2MSB:
1113118680Smarcel			val = be32dec(base);
1114109313Sobrien			break;
1115109313Sobrien		case ELFDATA2LSB:
1116118680Smarcel			val = le32dec(base);
1117109313Sobrien			break;
1118109313Sobrien		case ELFDATANONE:
1119109313Sobrien			errx(1, "invalid data format");
1120109313Sobrien		}
1121109313Sobrien		break;
1122109313Sobrien	case ELFCLASSNONE:
1123109313Sobrien		errx(1, "invalid class");
1124109313Sobrien	}
1125109313Sobrien
1126109313Sobrien	return val;
1127109313Sobrien}
1128241737Sed#endif
1129109313Sobrien
1130241737Sedstatic u_int64_t
1131109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1132109313Sobrien{
1133109313Sobrien	u_int64_t val;
1134109313Sobrien
1135109313Sobrien	val = 0;
1136109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1137109313Sobrien	case ELFCLASS32:
1138118680Smarcel		base = (char *)base + elf32_offsets[member];
1139109313Sobrien		switch (e->e_ident[EI_DATA]) {
1140109313Sobrien		case ELFDATA2MSB:
1141118680Smarcel			val = be32dec(base);
1142109313Sobrien			break;
1143109313Sobrien		case ELFDATA2LSB:
1144118680Smarcel			val = le32dec(base);
1145109313Sobrien			break;
1146109313Sobrien		case ELFDATANONE:
1147109313Sobrien			errx(1, "invalid data format");
1148109313Sobrien		}
1149109313Sobrien		break;
1150109313Sobrien	case ELFCLASS64:
1151118680Smarcel		base = (char *)base + elf64_offsets[member];
1152109313Sobrien		switch (e->e_ident[EI_DATA]) {
1153109313Sobrien		case ELFDATA2MSB:
1154118680Smarcel			val = be32dec(base);
1155109313Sobrien			break;
1156109313Sobrien		case ELFDATA2LSB:
1157118680Smarcel			val = le32dec(base);
1158109313Sobrien			break;
1159109313Sobrien		case ELFDATANONE:
1160109313Sobrien			errx(1, "invalid data format");
1161109313Sobrien		}
1162109313Sobrien		break;
1163109313Sobrien	case ELFCLASSNONE:
1164109313Sobrien		errx(1, "invalid class");
1165109313Sobrien	}
1166109313Sobrien
1167109313Sobrien	return val;
1168109313Sobrien}
1169109313Sobrien
1170241737Sedstatic u_int64_t
1171109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1172109313Sobrien{
1173109313Sobrien	u_int64_t val;
1174109313Sobrien
1175109313Sobrien	val = 0;
1176109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1177109313Sobrien	case ELFCLASS32:
1178118680Smarcel		base = (char *)base + elf32_offsets[member];
1179109313Sobrien		switch (e->e_ident[EI_DATA]) {
1180109313Sobrien		case ELFDATA2MSB:
1181118680Smarcel			val = be32dec(base);
1182109313Sobrien			break;
1183109313Sobrien		case ELFDATA2LSB:
1184118680Smarcel			val = le32dec(base);
1185109313Sobrien			break;
1186109313Sobrien		case ELFDATANONE:
1187109313Sobrien			errx(1, "invalid data format");
1188109313Sobrien		}
1189109313Sobrien		break;
1190109313Sobrien	case ELFCLASS64:
1191118680Smarcel		base = (char *)base + elf64_offsets[member];
1192109313Sobrien		switch (e->e_ident[EI_DATA]) {
1193109313Sobrien		case ELFDATA2MSB:
1194118680Smarcel			val = be64dec(base);
1195109313Sobrien			break;
1196109313Sobrien		case ELFDATA2LSB:
1197118680Smarcel			val = le64dec(base);
1198109313Sobrien			break;
1199109313Sobrien		case ELFDATANONE:
1200109313Sobrien			errx(1, "invalid data format");
1201109313Sobrien		}
1202109313Sobrien		break;
1203109313Sobrien	case ELFCLASSNONE:
1204109313Sobrien		errx(1, "invalid class");
1205109313Sobrien	}
1206109313Sobrien
1207109313Sobrien	return val;
1208109313Sobrien}
1209109313Sobrien
1210241737Sedstatic void
1211109313Sobrienusage(void)
1212109313Sobrien{
1213117009Sru	fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n");
1214109313Sobrien	exit(1);
1215109313Sobrien}
1216