elfdump.c revision 267958
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 267958 2014-06-27 14:42:13Z emaste $");
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 *
170109332Sobriend_tags(u_int64_t tag) {
171109332Sobrien	switch (tag) {
172109332Sobrien	case 0: return "DT_NULL";
173109332Sobrien	case 1: return "DT_NEEDED";
174109332Sobrien	case 2: return "DT_PLTRELSZ";
175109332Sobrien	case 3: return "DT_PLTGOT";
176109332Sobrien	case 4: return "DT_HASH";
177109332Sobrien	case 5: return "DT_STRTAB";
178109332Sobrien	case 6: return "DT_SYMTAB";
179109332Sobrien	case 7: return "DT_RELA";
180109332Sobrien	case 8: return "DT_RELASZ";
181109332Sobrien	case 9: return "DT_RELAENT";
182109332Sobrien	case 10: return "DT_STRSZ";
183109332Sobrien	case 11: return "DT_SYMENT";
184109332Sobrien	case 12: return "DT_INIT";
185109332Sobrien	case 13: return "DT_FINI";
186109332Sobrien	case 14: return "DT_SONAME";
187109332Sobrien	case 15: return "DT_RPATH";
188109332Sobrien	case 16: return "DT_SYMBOLIC";
189109332Sobrien	case 17: return "DT_REL";
190109332Sobrien	case 18: return "DT_RELSZ";
191109332Sobrien	case 19: return "DT_RELENT";
192109332Sobrien	case 20: return "DT_PLTREL";
193109332Sobrien	case 21: return "DT_DEBUG";
194109332Sobrien	case 22: return "DT_TEXTREL";
195109332Sobrien	case 23: return "DT_JMPREL";
196109332Sobrien	case 24: return "DT_BIND_NOW";
197109332Sobrien	case 25: return "DT_INIT_ARRAY";
198109332Sobrien	case 26: return "DT_FINI_ARRAY";
199109332Sobrien	case 27: return "DT_INIT_ARRAYSZ";
200109332Sobrien	case 28: return "DT_FINI_ARRAYSZ";
201109332Sobrien	case 29: return "DT_RUNPATH";
202109332Sobrien	case 30: return "DT_FLAGS";
203109332Sobrien	case 32: return "DT_PREINIT_ARRAY"; /* XXX: DT_ENCODING */
204109332Sobrien	case 33: return "DT_PREINIT_ARRAYSZ";
205109332Sobrien	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
206109332Sobrien	case 0x6ffffdf5: return "DT_GNU_PRELINKED";
207109332Sobrien	case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ";
208109332Sobrien	case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ";
209109332Sobrien	case 0x6ffffdf8: return "DT_SUNW_CHECKSUM";
210109332Sobrien	case 0x6ffffdf9: return "DT_PLTPADSZ";
211109332Sobrien	case 0x6ffffdfa: return "DT_MOVEENT";
212109332Sobrien	case 0x6ffffdfb: return "DT_MOVESZ";
213109332Sobrien	case 0x6ffffdfc: return "DT_FEATURE";
214109332Sobrien	case 0x6ffffdfd: return "DT_POSFLAG_1";
215109332Sobrien	case 0x6ffffdfe: return "DT_SYMINSZ";
216109332Sobrien	case 0x6ffffdff: return "DT_SYMINENT (DT_VALRNGHI)";
217109332Sobrien	case 0x6ffffe00: return "DT_ADDRRNGLO";
218109332Sobrien	case 0x6ffffef8: return "DT_GNU_CONFLICT";
219109332Sobrien	case 0x6ffffef9: return "DT_GNU_LIBLIST";
220109332Sobrien	case 0x6ffffefa: return "DT_SUNW_CONFIG";
221109332Sobrien	case 0x6ffffefb: return "DT_SUNW_DEPAUDIT";
222109332Sobrien	case 0x6ffffefc: return "DT_SUNW_AUDIT";
223109332Sobrien	case 0x6ffffefd: return "DT_SUNW_PLTPAD";
224109332Sobrien	case 0x6ffffefe: return "DT_SUNW_MOVETAB";
225109332Sobrien	case 0x6ffffeff: return "DT_SYMINFO (DT_ADDRRNGHI)";
226109332Sobrien	case 0x6ffffff9: return "DT_RELACOUNT";
227109332Sobrien	case 0x6ffffffa: return "DT_RELCOUNT";
228109332Sobrien	case 0x6ffffffb: return "DT_FLAGS_1";
229109332Sobrien	case 0x6ffffffc: return "DT_VERDEF";
230109332Sobrien	case 0x6ffffffd: return "DT_VERDEFNUM";
231109332Sobrien	case 0x6ffffffe: return "DT_VERNEED";
232109332Sobrien	case 0x6fffffff: return "DT_VERNEEDNUM";
233109332Sobrien	case 0x6ffffff0: return "DT_GNU_VERSYM";
234109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
235154958Smarcel	case 0x70000000: return "DT_IA_64_PLT_RESERVE";
236109332Sobrien	case 0x7ffffffd: return "DT_SUNW_AUXILIARY";
237109332Sobrien	case 0x7ffffffe: return "DT_SUNW_USED";
238109332Sobrien	case 0x7fffffff: return "DT_SUNW_FILTER";
239109332Sobrien	default: return "ERROR: TAG NOT DEFINED";
240109332Sobrien	}
241119794Sschweikh}
242109313Sobrien
243110256Sobrienstatic const char *
244109457Smarcele_machines(u_int mach)
245109457Smarcel{
246153500Smarcel	static char machdesc[64];
247153500Smarcel
248109457Smarcel	switch (mach) {
249109457Smarcel	case EM_NONE:	return "EM_NONE";
250109457Smarcel	case EM_M32:	return "EM_M32";
251109457Smarcel	case EM_SPARC:	return "EM_SPARC";
252109457Smarcel	case EM_386:	return "EM_386";
253109457Smarcel	case EM_68K:	return "EM_68K";
254109457Smarcel	case EM_88K:	return "EM_88K";
255109457Smarcel	case EM_860:	return "EM_860";
256109457Smarcel	case EM_MIPS:	return "EM_MIPS";
257153500Smarcel	case EM_PPC:	return "EM_PPC";
258261002Sjhibbits	case EM_PPC64:	return "EM_PPC64";
259153500Smarcel	case EM_ARM:	return "EM_ARM";
260153500Smarcel	case EM_ALPHA:	return "EM_ALPHA (legacy)";
261153500Smarcel	case EM_SPARCV9:return "EM_SPARCV9";
262109457Smarcel	case EM_IA_64:	return "EM_IA_64";
263153500Smarcel	case EM_X86_64:	return "EM_X86_64";
264109457Smarcel	}
265153500Smarcel	snprintf(machdesc, sizeof(machdesc),
266153500Smarcel	    "(unknown machine) -- type 0x%x", mach);
267153500Smarcel	return (machdesc);
268119794Sschweikh}
269109313Sobrien
270241737Sedstatic const char *e_types[] = {
271109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
272109313Sobrien};
273109313Sobrien
274241737Sedstatic const char *ei_versions[] = {
275109313Sobrien	"EV_NONE", "EV_CURRENT"
276109313Sobrien};
277109313Sobrien
278241737Sedstatic const char *ei_classes[] = {
279109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
280109313Sobrien};
281109313Sobrien
282241737Sedstatic const char *ei_data[] = {
283109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
284109313Sobrien};
285109313Sobrien
286241737Sedstatic const char *ei_abis[256] = {
287109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
288226434Smarcel	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX",
289226434Smarcel	"ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64",
290226434Smarcel	"ELFOSABI_MODESTO", "ELFOSABI_OPENBSD",
291226434Smarcel	[255] = "ELFOSABI_STANDALONE"
292109313Sobrien};
293109313Sobrien
294241737Sedstatic const char *p_types[] = {
295109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
296126484Sjake	"PT_SHLIB", "PT_PHDR", "PT_TLS"
297109313Sobrien};
298109313Sobrien
299241737Sedstatic const char *p_flags[] = {
300109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
301109313Sobrien	"PF_X|PF_W|PF_R"
302109313Sobrien};
303109313Sobrien
304109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
305110256Sobrienstatic const char *
306109332Sobriensh_types(u_int64_t sht) {
307109329Sobrien	switch (sht) {
308109329Sobrien	case 0:	return "SHT_NULL";
309109329Sobrien	case 1: return "SHT_PROGBITS";
310109329Sobrien	case 2: return "SHT_SYMTAB";
311109329Sobrien	case 3: return "SHT_STRTAB";
312109329Sobrien	case 4: return "SHT_RELA";
313109329Sobrien	case 5: return "SHT_HASH";
314109329Sobrien	case 6: return "SHT_DYNAMIC";
315109329Sobrien	case 7: return "SHT_NOTE";
316109329Sobrien	case 8: return "SHT_NOBITS";
317109329Sobrien	case 9: return "SHT_REL";
318109329Sobrien	case 10: return "SHT_SHLIB";
319109329Sobrien	case 11: return "SHT_DYNSYM";
320109329Sobrien	case 14: return "SHT_INIT_ARRAY";
321109329Sobrien	case 15: return "SHT_FINI_ARRAY";
322109329Sobrien	case 16: return "SHT_PREINIT_ARRAY";
323109329Sobrien	case 17: return "SHT_GROUP";
324109329Sobrien	case 18: return "SHT_SYMTAB_SHNDX";
325109332Sobrien	/* 0x60000000 - 0x6fffffff operating system-specific semantics */
326109329Sobrien	case 0x6ffffff0: return "XXX:VERSYM";
327211188Srpaulo	case 0x6ffffff4: return "SHT_SUNW_dof";
328109329Sobrien	case 0x6ffffff7: return "SHT_GNU_LIBLIST";
329109329Sobrien	case 0x6ffffffc: return "XXX:VERDEF";
330109329Sobrien	case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef";
331109329Sobrien	case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed";
332109329Sobrien	case 0x6fffffff: return "SHT_SUNW(GNU)_versym";
333109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
334109457Smarcel	case 0x70000000: return "SHT_IA_64_EXT";
335109457Smarcel	case 0x70000001: return "SHT_IA_64_UNWIND";
336109329Sobrien	case 0x7ffffffd: return "XXX:AUXILIARY";
337109329Sobrien	case 0x7fffffff: return "XXX:FILTER";
338109332Sobrien	/* 0x80000000 - 0xffffffff application programs */
339109329Sobrien	default: return "ERROR: SHT NOT DEFINED";
340109329Sobrien	}
341119795Sschweikh}
342109313Sobrien
343241737Sedstatic const char *sh_flags[] = {
344109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
345109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
346109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
347109313Sobrien};
348109313Sobrien
349241737Sedstatic const char *st_types[] = {
350109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
351109313Sobrien};
352109313Sobrien
353241737Sedstatic const char *st_bindings[] = {
354109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
355109313Sobrien};
356109313Sobrien
357241737Sedstatic char *dynstr;
358241737Sedstatic char *shstrtab;
359241737Sedstatic char *strtab;
360241737Sedstatic FILE *out;
361109313Sobrien
362241737Sedstatic u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
363241737Sedstatic u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base,
364241737Sed    elf_member_t member);
365241737Sed#if 0
366241737Sedstatic u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
367241737Sed#endif
368241737Sedstatic u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
369241737Sedstatic u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
370109313Sobrien
371267958Semastestatic void elf_print_ehdr(Elf32_Ehdr *e, void *sh);
372241737Sedstatic void elf_print_phdr(Elf32_Ehdr *e, void *p);
373241737Sedstatic void elf_print_shdr(Elf32_Ehdr *e, void *sh);
374241737Sedstatic void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
375241737Sedstatic void elf_print_dynamic(Elf32_Ehdr *e, void *sh);
376241737Sedstatic void elf_print_rel(Elf32_Ehdr *e, void *r);
377241737Sedstatic void elf_print_rela(Elf32_Ehdr *e, void *ra);
378241737Sedstatic void elf_print_interp(Elf32_Ehdr *e, void *p);
379241737Sedstatic void elf_print_got(Elf32_Ehdr *e, void *sh);
380241737Sedstatic void elf_print_hash(Elf32_Ehdr *e, void *sh);
381241737Sedstatic void elf_print_note(Elf32_Ehdr *e, void *sh);
382109313Sobrien
383241737Sedstatic void usage(void);
384109313Sobrien
385267958Semaste/*
386267958Semaste * Helpers for ELF files with shnum or shstrndx values that don't fit in the
387267958Semaste * ELF header.  If the values are too large then an escape value is used to
388267958Semaste * indicate that the actual value is found in one of section 0's fields.
389267958Semaste */
390267958Semastestatic uint64_t
391267958Semasteelf_get_shnum(Elf32_Ehdr *e, void *sh)
392267958Semaste{
393267958Semaste	uint64_t shnum;
394267958Semaste
395267958Semaste	shnum = elf_get_quarter(e, e, E_SHNUM);
396267958Semaste	if (shnum == 0)
397267958Semaste		shnum = elf_get_word(e, (char *)sh, SH_SIZE);
398267958Semaste	return shnum;
399267958Semaste}
400267958Semaste
401267958Semastestatic uint64_t
402267958Semasteelf_get_shstrndx(Elf32_Ehdr *e, void *sh)
403267958Semaste{
404267958Semaste	uint64_t shstrndx;
405267958Semaste
406267958Semaste	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
407267958Semaste	if (shstrndx == SHN_XINDEX)
408267958Semaste		shstrndx = elf_get_word(e, (char *)sh, SH_LINK);
409267958Semaste	return shstrndx;
410267958Semaste}
411267958Semaste
412109313Sobrienint
413109313Sobrienmain(int ac, char **av)
414109313Sobrien{
415109313Sobrien	u_int64_t phoff;
416109313Sobrien	u_int64_t shoff;
417109313Sobrien	u_int64_t phentsize;
418109313Sobrien	u_int64_t phnum;
419109313Sobrien	u_int64_t shentsize;
420109313Sobrien	u_int64_t shnum;
421109313Sobrien	u_int64_t shstrndx;
422109313Sobrien	u_int64_t offset;
423109313Sobrien	u_int64_t name;
424109313Sobrien	u_int64_t type;
425109313Sobrien	struct stat sb;
426109313Sobrien	u_int flags;
427110252Sobrien	Elf32_Ehdr *e;
428109313Sobrien	void *p;
429109313Sobrien	void *sh;
430109313Sobrien	void *v;
431109313Sobrien	int fd;
432109313Sobrien	int ch;
433109313Sobrien	int i;
434109313Sobrien
435109313Sobrien	out = stdout;
436109313Sobrien	flags = 0;
437109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
438109313Sobrien		switch (ch) {
439109313Sobrien		case 'a':
440109313Sobrien			flags = ED_ALL;
441109313Sobrien			break;
442109313Sobrien		case 'c':
443109313Sobrien			flags |= ED_SHDR;
444109313Sobrien			break;
445109313Sobrien		case 'd':
446109313Sobrien			flags |= ED_DYN;
447109313Sobrien			break;
448109313Sobrien		case 'e':
449109313Sobrien			flags |= ED_EHDR;
450109313Sobrien			break;
451109313Sobrien		case 'i':
452109313Sobrien			flags |= ED_INTERP;
453109313Sobrien			break;
454109313Sobrien		case 'G':
455109313Sobrien			flags |= ED_GOT;
456109313Sobrien			break;
457109313Sobrien		case 'h':
458109313Sobrien			flags |= ED_HASH;
459109313Sobrien			break;
460109313Sobrien		case 'n':
461109313Sobrien			flags |= ED_NOTE;
462109313Sobrien			break;
463109313Sobrien		case 'p':
464109313Sobrien			flags |= ED_PHDR;
465109313Sobrien			break;
466109313Sobrien		case 'r':
467109313Sobrien			flags |= ED_REL;
468109313Sobrien			break;
469109313Sobrien		case 's':
470109313Sobrien			flags |= ED_SYMTAB;
471109313Sobrien			break;
472109313Sobrien		case 'w':
473109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
474109313Sobrien				err(1, "%s", optarg);
475109313Sobrien			break;
476109313Sobrien		case '?':
477109313Sobrien		default:
478109313Sobrien			usage();
479109313Sobrien		}
480109313Sobrien	ac -= optind;
481109313Sobrien	av += optind;
482109313Sobrien	if (ac == 0 || flags == 0)
483109313Sobrien		usage();
484109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
485109313Sobrien	    fstat(fd, &sb) < 0)
486117009Sru		err(1, "%s", *av);
487109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
488109313Sobrien	if (e == MAP_FAILED)
489109313Sobrien		err(1, NULL);
490109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
491109313Sobrien		errx(1, "not an elf file");
492109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
493109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
494109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
495109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
496109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
497110256Sobrien	p = (char *)e + phoff;
498267958Semaste	if (shoff > 0) {
499267958Semaste		sh = (char *)e + shoff;
500267958Semaste		shnum = elf_get_shnum(e, sh);
501267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
502267958Semaste		offset = elf_get_off(e, (char *)sh + shstrndx * shentsize,
503267958Semaste		    SH_OFFSET);
504267958Semaste		shstrtab = (char *)e + offset;
505267958Semaste	} else {
506267958Semaste		sh = NULL;
507267958Semaste		shnum = 0;
508267958Semaste		shstrndx = 0;
509267958Semaste		shstrtab = NULL;
510267958Semaste	}
511110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
512110256Sobrien		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
513110256Sobrien		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
514109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
515110252Sobrien			strtab = (char *)e + offset;
516109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
517110252Sobrien			dynstr = (char *)e + offset;
518109313Sobrien	}
519109313Sobrien	if (flags & ED_EHDR)
520267958Semaste		elf_print_ehdr(e, sh);
521109313Sobrien	if (flags & ED_PHDR)
522109313Sobrien		elf_print_phdr(e, p);
523109313Sobrien	if (flags & ED_SHDR)
524109313Sobrien		elf_print_shdr(e, sh);
525110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
526110256Sobrien		v = (char *)p + i * phentsize;
527109313Sobrien		type = elf_get_word(e, v, P_TYPE);
528109313Sobrien		switch (type) {
529109313Sobrien		case PT_INTERP:
530109313Sobrien			if (flags & ED_INTERP)
531109313Sobrien				elf_print_interp(e, v);
532109313Sobrien			break;
533109313Sobrien		case PT_NULL:
534109313Sobrien		case PT_LOAD:
535109313Sobrien		case PT_DYNAMIC:
536109313Sobrien		case PT_NOTE:
537109313Sobrien		case PT_SHLIB:
538109313Sobrien		case PT_PHDR:
539109313Sobrien			break;
540109313Sobrien		}
541109313Sobrien	}
542110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
543110256Sobrien		v = (char *)sh + i * shentsize;
544109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
545109313Sobrien		switch (type) {
546109313Sobrien		case SHT_SYMTAB:
547109313Sobrien			if (flags & ED_SYMTAB)
548109313Sobrien				elf_print_symtab(e, v, strtab);
549109313Sobrien			break;
550109313Sobrien		case SHT_DYNAMIC:
551109313Sobrien			if (flags & ED_DYN)
552109313Sobrien				elf_print_dynamic(e, v);
553109313Sobrien			break;
554109313Sobrien		case SHT_RELA:
555109313Sobrien			if (flags & ED_REL)
556109313Sobrien				elf_print_rela(e, v);
557109313Sobrien			break;
558109313Sobrien		case SHT_REL:
559109313Sobrien			if (flags & ED_REL)
560109313Sobrien				elf_print_rel(e, v);
561109313Sobrien			break;
562109313Sobrien		case SHT_NOTE:
563109313Sobrien			name = elf_get_word(e, v, SH_NAME);
564109313Sobrien			if (flags & ED_NOTE &&
565109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
566109313Sobrien				elf_print_note(e, v);
567109313Sobrien			break;
568109313Sobrien		case SHT_DYNSYM:
569109313Sobrien			if (flags & ED_SYMTAB)
570109313Sobrien				elf_print_symtab(e, v, dynstr);
571109313Sobrien			break;
572109313Sobrien		case SHT_PROGBITS:
573109313Sobrien			name = elf_get_word(e, v, SH_NAME);
574109313Sobrien			if (flags & ED_GOT &&
575109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
576109313Sobrien				elf_print_got(e, v);
577109313Sobrien			break;
578109313Sobrien		case SHT_HASH:
579109313Sobrien			if (flags & ED_HASH)
580109313Sobrien				elf_print_hash(e, v);
581109313Sobrien			break;
582109313Sobrien		case SHT_NULL:
583109313Sobrien		case SHT_STRTAB:
584109313Sobrien		case SHT_NOBITS:
585109313Sobrien		case SHT_SHLIB:
586109313Sobrien			break;
587109313Sobrien		}
588109313Sobrien	}
589109313Sobrien
590109313Sobrien	return 0;
591109313Sobrien}
592109313Sobrien
593241737Sedstatic void
594267958Semasteelf_print_ehdr(Elf32_Ehdr *e, void *sh)
595109313Sobrien{
596109313Sobrien	u_int64_t class;
597109313Sobrien	u_int64_t data;
598109313Sobrien	u_int64_t osabi;
599109313Sobrien	u_int64_t type;
600109313Sobrien	u_int64_t machine;
601109313Sobrien	u_int64_t version;
602109313Sobrien	u_int64_t entry;
603109313Sobrien	u_int64_t phoff;
604109313Sobrien	u_int64_t shoff;
605109313Sobrien	u_int64_t flags;
606109313Sobrien	u_int64_t ehsize;
607109313Sobrien	u_int64_t phentsize;
608109313Sobrien	u_int64_t phnum;
609109313Sobrien	u_int64_t shentsize;
610109313Sobrien	u_int64_t shnum;
611109313Sobrien	u_int64_t shstrndx;
612109313Sobrien
613109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
614109313Sobrien	data = elf_get_byte(e, e, E_DATA);
615109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
616109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
617109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
618109313Sobrien	version = elf_get_word(e, e, E_VERSION);
619109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
620109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
621109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
622109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
623109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
624109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
625109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
626109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
627109313Sobrien	fprintf(out, "\nelf header:\n");
628109313Sobrien	fprintf(out, "\n");
629109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
630109313Sobrien	    ei_abis[osabi]);
631109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
632109457Smarcel	fprintf(out, "\te_machine: %s\n", e_machines(machine));
633109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
634110257Sobrien	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
635110257Sobrien	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
636110257Sobrien	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
637110257Sobrien	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
638110257Sobrien	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
639110257Sobrien	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
640110257Sobrien	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
641110257Sobrien	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
642267958Semaste	if (sh != NULL) {
643267958Semaste		shnum = elf_get_shnum(e, sh);
644267958Semaste		shstrndx = elf_get_shstrndx(e, sh);
645267958Semaste		fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
646267958Semaste		fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
647267958Semaste	}
648109313Sobrien}
649109313Sobrien
650241737Sedstatic void
651110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p)
652109313Sobrien{
653109313Sobrien	u_int64_t phentsize;
654109313Sobrien	u_int64_t phnum;
655109313Sobrien	u_int64_t type;
656109313Sobrien	u_int64_t offset;
657109313Sobrien	u_int64_t vaddr;
658109313Sobrien	u_int64_t paddr;
659109313Sobrien	u_int64_t filesz;
660109313Sobrien	u_int64_t memsz;
661109313Sobrien	u_int64_t flags;
662109313Sobrien	u_int64_t align;
663109313Sobrien	void *v;
664109313Sobrien	int i;
665109313Sobrien
666109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
667109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
668109313Sobrien	fprintf(out, "\nprogram header:\n");
669110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
670110256Sobrien		v = (char *)p + i * phentsize;
671109313Sobrien		type = elf_get_word(e, v, P_TYPE);
672109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
673109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
674109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
675109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
676109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
677109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
678109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
679109313Sobrien		fprintf(out, "\n");
680109313Sobrien		fprintf(out, "entry: %d\n", i);
681109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
682110257Sobrien		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
683110257Sobrien		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
684110257Sobrien		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
685110257Sobrien		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
686110257Sobrien		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
687109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
688110257Sobrien		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
689109313Sobrien	}
690109313Sobrien}
691109313Sobrien
692241737Sedstatic void
693110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh)
694109313Sobrien{
695109313Sobrien	u_int64_t shentsize;
696109313Sobrien	u_int64_t shnum;
697109313Sobrien	u_int64_t name;
698109313Sobrien	u_int64_t type;
699109313Sobrien	u_int64_t flags;
700109313Sobrien	u_int64_t addr;
701109313Sobrien	u_int64_t offset;
702109313Sobrien	u_int64_t size;
703110256Sobrien	u_int64_t shlink;
704109313Sobrien	u_int64_t info;
705109313Sobrien	u_int64_t addralign;
706109313Sobrien	u_int64_t entsize;
707109313Sobrien	void *v;
708109313Sobrien	int i;
709109313Sobrien
710267958Semaste	if (sh == NULL) {
711267958Semaste		fprintf(out, "\nNo section headers\n");
712267958Semaste		return;
713267958Semaste	}
714267958Semaste
715109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
716267958Semaste	shnum = elf_get_shnum(e, sh);
717109313Sobrien	fprintf(out, "\nsection header:\n");
718110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
719110256Sobrien		v = (char *)sh + i * shentsize;
720109313Sobrien		name = elf_get_word(e, v, SH_NAME);
721109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
722109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
723109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
724109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
725109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
726110256Sobrien		shlink = elf_get_word(e, v, SH_LINK);
727109313Sobrien		info = elf_get_word(e, v, SH_INFO);
728109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
729109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
730109313Sobrien		fprintf(out, "\n");
731109313Sobrien		fprintf(out, "entry: %d\n", i);
732109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
733109329Sobrien		fprintf(out, "\tsh_type: %s\n", sh_types(type));
734109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
735110257Sobrien		fprintf(out, "\tsh_addr: %#jx\n", addr);
736110257Sobrien		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
737110257Sobrien		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
738110257Sobrien		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
739110257Sobrien		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
740110257Sobrien		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
741110257Sobrien		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
742109313Sobrien	}
743109313Sobrien}
744109313Sobrien
745241737Sedstatic void
746110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
747109313Sobrien{
748109313Sobrien	u_int64_t offset;
749109313Sobrien	u_int64_t entsize;
750109313Sobrien	u_int64_t size;
751109313Sobrien	u_int64_t name;
752109313Sobrien	u_int64_t value;
753109313Sobrien	u_int64_t info;
754109313Sobrien	u_int64_t shndx;
755109313Sobrien	void *st;
756109313Sobrien	int len;
757109313Sobrien	int i;
758109313Sobrien
759109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
760109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
761109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
762109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
763109313Sobrien	len = size / entsize;
764109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
765109313Sobrien	for (i = 0; i < len; i++) {
766110256Sobrien		st = (char *)e + offset + i * entsize;
767109313Sobrien		name = elf_get_word(e, st, ST_NAME);
768109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
769109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
770109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
771109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
772109313Sobrien		fprintf(out, "\n");
773109313Sobrien		fprintf(out, "entry: %d\n", i);
774109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
775110257Sobrien		fprintf(out, "\tst_value: %#jx\n", value);
776110257Sobrien		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
777109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
778109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
779109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
780110257Sobrien		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
781109313Sobrien	}
782109313Sobrien}
783109313Sobrien
784241737Sedstatic void
785110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh)
786109313Sobrien{
787109313Sobrien	u_int64_t offset;
788109313Sobrien	u_int64_t entsize;
789109313Sobrien	u_int64_t size;
790109313Sobrien	int64_t tag;
791109313Sobrien	u_int64_t ptr;
792109313Sobrien	u_int64_t val;
793109313Sobrien	void *d;
794109313Sobrien	int i;
795109313Sobrien
796109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
797109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
798109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
799109313Sobrien	fprintf(out, "\ndynamic:\n");
800110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
801110256Sobrien		d = (char *)e + offset + i * entsize;
802109313Sobrien		tag = elf_get_size(e, d, D_TAG);
803109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
804109313Sobrien		val = elf_get_addr(e, d, D_VAL);
805109313Sobrien		fprintf(out, "\n");
806109313Sobrien		fprintf(out, "entry: %d\n", i);
807109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
808109313Sobrien		switch (tag) {
809109313Sobrien		case DT_NEEDED:
810109313Sobrien		case DT_SONAME:
811109313Sobrien		case DT_RPATH:
812109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
813109313Sobrien			break;
814109313Sobrien		case DT_PLTRELSZ:
815109313Sobrien		case DT_RELA:
816109313Sobrien		case DT_RELASZ:
817109313Sobrien		case DT_RELAENT:
818109313Sobrien		case DT_STRSZ:
819109313Sobrien		case DT_SYMENT:
820109313Sobrien		case DT_RELSZ:
821109313Sobrien		case DT_RELENT:
822109313Sobrien		case DT_PLTREL:
823110257Sobrien			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
824109313Sobrien			break;
825109313Sobrien		case DT_PLTGOT:
826109313Sobrien		case DT_HASH:
827109313Sobrien		case DT_STRTAB:
828109313Sobrien		case DT_SYMTAB:
829109313Sobrien		case DT_INIT:
830109313Sobrien		case DT_FINI:
831109313Sobrien		case DT_REL:
832109313Sobrien		case DT_JMPREL:
833110257Sobrien			fprintf(out, "\td_ptr: %#jx\n", ptr);
834109313Sobrien			break;
835109313Sobrien		case DT_NULL:
836109313Sobrien		case DT_SYMBOLIC:
837109313Sobrien		case DT_DEBUG:
838109313Sobrien		case DT_TEXTREL:
839109313Sobrien			break;
840109313Sobrien		}
841109313Sobrien	}
842109313Sobrien}
843109313Sobrien
844241737Sedstatic void
845110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh)
846109313Sobrien{
847109313Sobrien	u_int64_t offset;
848109313Sobrien	u_int64_t entsize;
849109313Sobrien	u_int64_t size;
850109313Sobrien	u_int64_t name;
851109313Sobrien	u_int64_t info;
852109313Sobrien	int64_t addend;
853109313Sobrien	void *ra;
854109313Sobrien	void *v;
855109313Sobrien	int i;
856109313Sobrien
857109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
858109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
859109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
860109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
861110256Sobrien	v = (char *)e + offset;
862109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
863110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
864110256Sobrien		ra = (char *)v + i * entsize;
865109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
866109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
867109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
868109313Sobrien		fprintf(out, "\n");
869109313Sobrien		fprintf(out, "entry: %d\n", i);
870110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
871110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
872110257Sobrien		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
873109313Sobrien	}
874109313Sobrien}
875109313Sobrien
876241737Sedstatic void
877110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh)
878109313Sobrien{
879109313Sobrien	u_int64_t offset;
880109313Sobrien	u_int64_t entsize;
881109313Sobrien	u_int64_t size;
882109313Sobrien	u_int64_t name;
883109313Sobrien	u_int64_t info;
884109313Sobrien	void *r;
885109313Sobrien	void *v;
886109313Sobrien	int i;
887109313Sobrien
888109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
889109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
890109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
891109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
892110256Sobrien	v = (char *)e + offset;
893109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
894110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
895110256Sobrien		r = (char *)v + i * entsize;
896109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
897109313Sobrien		info = elf_get_word(e, r, R_INFO);
898109313Sobrien		fprintf(out, "\n");
899109313Sobrien		fprintf(out, "entry: %d\n", i);
900110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
901110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
902109313Sobrien	}
903109313Sobrien}
904109313Sobrien
905241737Sedstatic void
906110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p)
907109313Sobrien{
908109313Sobrien	u_int64_t offset;
909109313Sobrien	char *s;
910109313Sobrien
911109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
912110252Sobrien	s = (char *)e + offset;
913109313Sobrien	fprintf(out, "\ninterp:\n");
914109313Sobrien	fprintf(out, "\t%s\n", s);
915109313Sobrien}
916109313Sobrien
917241737Sedstatic void
918110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh)
919109313Sobrien{
920109313Sobrien	u_int64_t offset;
921109313Sobrien	u_int64_t addralign;
922109313Sobrien	u_int64_t size;
923109313Sobrien	u_int64_t addr;
924109313Sobrien	void *v;
925109313Sobrien	int i;
926109313Sobrien
927109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
928109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
929109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
930110256Sobrien	v = (char *)e + offset;
931109313Sobrien	fprintf(out, "\nglobal offset table:\n");
932110256Sobrien	for (i = 0; (u_int64_t)i < size / addralign; i++) {
933110256Sobrien		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
934109313Sobrien		fprintf(out, "\n");
935109313Sobrien		fprintf(out, "entry: %d\n", i);
936110257Sobrien		fprintf(out, "\t%#jx\n", addr);
937109313Sobrien	}
938109313Sobrien}
939109313Sobrien
940241737Sedstatic void
941110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
942109313Sobrien{
943109313Sobrien}
944109313Sobrien
945241737Sedstatic void
946110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh)
947109313Sobrien{
948109313Sobrien	u_int64_t offset;
949109313Sobrien	u_int64_t size;
950109313Sobrien	u_int64_t name;
951109313Sobrien	u_int32_t namesz;
952109313Sobrien	u_int32_t descsz;
953109313Sobrien	u_int32_t desc;
954110256Sobrien	char *n, *s;
955109313Sobrien
956109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
957109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
958109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
959110256Sobrien	n = (char *)e + offset;
960109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
961110256Sobrien 	while (n < ((char *)e + offset + size)) {
962109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
963109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
964110256Sobrien 		s = n + sizeof(Elf_Note);
965110256Sobrien 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
966109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
967109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
968109313Sobrien	}
969109313Sobrien}
970109313Sobrien
971241737Sedstatic u_int64_t
972109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
973109313Sobrien{
974109313Sobrien	u_int64_t val;
975109313Sobrien
976109313Sobrien	val = 0;
977109313Sobrien	switch (e->e_ident[EI_CLASS]) {
978109313Sobrien	case ELFCLASS32:
979226434Smarcel		val = ((uint8_t *)base)[elf32_offsets[member]];
980109313Sobrien		break;
981109313Sobrien	case ELFCLASS64:
982226434Smarcel		val = ((uint8_t *)base)[elf64_offsets[member]];
983109313Sobrien		break;
984109313Sobrien	case ELFCLASSNONE:
985109313Sobrien		errx(1, "invalid class");
986109313Sobrien	}
987109313Sobrien
988109313Sobrien	return val;
989109313Sobrien}
990109313Sobrien
991241737Sedstatic u_int64_t
992109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
993109313Sobrien{
994109313Sobrien	u_int64_t val;
995109313Sobrien
996109313Sobrien	val = 0;
997109313Sobrien	switch (e->e_ident[EI_CLASS]) {
998109313Sobrien	case ELFCLASS32:
999118680Smarcel		base = (char *)base + elf32_offsets[member];
1000109313Sobrien		switch (e->e_ident[EI_DATA]) {
1001109313Sobrien		case ELFDATA2MSB:
1002118680Smarcel			val = be16dec(base);
1003109313Sobrien			break;
1004109313Sobrien		case ELFDATA2LSB:
1005118680Smarcel			val = le16dec(base);
1006109313Sobrien			break;
1007109313Sobrien		case ELFDATANONE:
1008109313Sobrien			errx(1, "invalid data format");
1009109313Sobrien		}
1010109313Sobrien		break;
1011109313Sobrien	case ELFCLASS64:
1012118680Smarcel		base = (char *)base + elf64_offsets[member];
1013109313Sobrien		switch (e->e_ident[EI_DATA]) {
1014109313Sobrien		case ELFDATA2MSB:
1015118680Smarcel			val = be16dec(base);
1016109313Sobrien			break;
1017109313Sobrien		case ELFDATA2LSB:
1018118680Smarcel			val = le16dec(base);
1019109313Sobrien			break;
1020109313Sobrien		case ELFDATANONE:
1021109313Sobrien			errx(1, "invalid data format");
1022109313Sobrien		}
1023109313Sobrien		break;
1024109313Sobrien	case ELFCLASSNONE:
1025109313Sobrien		errx(1, "invalid class");
1026109313Sobrien	}
1027109313Sobrien
1028109313Sobrien	return val;
1029109313Sobrien}
1030109313Sobrien
1031241737Sed#if 0
1032241737Sedstatic u_int64_t
1033109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
1034109313Sobrien{
1035109313Sobrien	u_int64_t val;
1036109313Sobrien
1037109313Sobrien	val = 0;
1038109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1039109313Sobrien	case ELFCLASS32:
1040118680Smarcel		base = (char *)base + elf32_offsets[member];
1041109313Sobrien		switch (e->e_ident[EI_DATA]) {
1042109313Sobrien		case ELFDATA2MSB:
1043118680Smarcel			val = be16dec(base);
1044109313Sobrien			break;
1045109313Sobrien		case ELFDATA2LSB:
1046118680Smarcel			val = le16dec(base);
1047109313Sobrien			break;
1048109313Sobrien		case ELFDATANONE:
1049109313Sobrien			errx(1, "invalid data format");
1050109313Sobrien		}
1051109313Sobrien		break;
1052109313Sobrien	case ELFCLASS64:
1053118680Smarcel		base = (char *)base + elf64_offsets[member];
1054109313Sobrien		switch (e->e_ident[EI_DATA]) {
1055109313Sobrien		case ELFDATA2MSB:
1056118680Smarcel			val = be32dec(base);
1057109313Sobrien			break;
1058109313Sobrien		case ELFDATA2LSB:
1059118680Smarcel			val = le32dec(base);
1060109313Sobrien			break;
1061109313Sobrien		case ELFDATANONE:
1062109313Sobrien			errx(1, "invalid data format");
1063109313Sobrien		}
1064109313Sobrien		break;
1065109313Sobrien	case ELFCLASSNONE:
1066109313Sobrien		errx(1, "invalid class");
1067109313Sobrien	}
1068109313Sobrien
1069109313Sobrien	return val;
1070109313Sobrien}
1071241737Sed#endif
1072109313Sobrien
1073241737Sedstatic u_int64_t
1074109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1075109313Sobrien{
1076109313Sobrien	u_int64_t val;
1077109313Sobrien
1078109313Sobrien	val = 0;
1079109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1080109313Sobrien	case ELFCLASS32:
1081118680Smarcel		base = (char *)base + elf32_offsets[member];
1082109313Sobrien		switch (e->e_ident[EI_DATA]) {
1083109313Sobrien		case ELFDATA2MSB:
1084118680Smarcel			val = be32dec(base);
1085109313Sobrien			break;
1086109313Sobrien		case ELFDATA2LSB:
1087118680Smarcel			val = le32dec(base);
1088109313Sobrien			break;
1089109313Sobrien		case ELFDATANONE:
1090109313Sobrien			errx(1, "invalid data format");
1091109313Sobrien		}
1092109313Sobrien		break;
1093109313Sobrien	case ELFCLASS64:
1094118680Smarcel		base = (char *)base + elf64_offsets[member];
1095109313Sobrien		switch (e->e_ident[EI_DATA]) {
1096109313Sobrien		case ELFDATA2MSB:
1097118680Smarcel			val = be32dec(base);
1098109313Sobrien			break;
1099109313Sobrien		case ELFDATA2LSB:
1100118680Smarcel			val = le32dec(base);
1101109313Sobrien			break;
1102109313Sobrien		case ELFDATANONE:
1103109313Sobrien			errx(1, "invalid data format");
1104109313Sobrien		}
1105109313Sobrien		break;
1106109313Sobrien	case ELFCLASSNONE:
1107109313Sobrien		errx(1, "invalid class");
1108109313Sobrien	}
1109109313Sobrien
1110109313Sobrien	return val;
1111109313Sobrien}
1112109313Sobrien
1113241737Sedstatic u_int64_t
1114109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1115109313Sobrien{
1116109313Sobrien	u_int64_t val;
1117109313Sobrien
1118109313Sobrien	val = 0;
1119109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1120109313Sobrien	case ELFCLASS32:
1121118680Smarcel		base = (char *)base + elf32_offsets[member];
1122109313Sobrien		switch (e->e_ident[EI_DATA]) {
1123109313Sobrien		case ELFDATA2MSB:
1124118680Smarcel			val = be32dec(base);
1125109313Sobrien			break;
1126109313Sobrien		case ELFDATA2LSB:
1127118680Smarcel			val = le32dec(base);
1128109313Sobrien			break;
1129109313Sobrien		case ELFDATANONE:
1130109313Sobrien			errx(1, "invalid data format");
1131109313Sobrien		}
1132109313Sobrien		break;
1133109313Sobrien	case ELFCLASS64:
1134118680Smarcel		base = (char *)base + elf64_offsets[member];
1135109313Sobrien		switch (e->e_ident[EI_DATA]) {
1136109313Sobrien		case ELFDATA2MSB:
1137118680Smarcel			val = be64dec(base);
1138109313Sobrien			break;
1139109313Sobrien		case ELFDATA2LSB:
1140118680Smarcel			val = le64dec(base);
1141109313Sobrien			break;
1142109313Sobrien		case ELFDATANONE:
1143109313Sobrien			errx(1, "invalid data format");
1144109313Sobrien		}
1145109313Sobrien		break;
1146109313Sobrien	case ELFCLASSNONE:
1147109313Sobrien		errx(1, "invalid class");
1148109313Sobrien	}
1149109313Sobrien
1150109313Sobrien	return val;
1151109313Sobrien}
1152109313Sobrien
1153241737Sedstatic void
1154109313Sobrienusage(void)
1155109313Sobrien{
1156117009Sru	fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n");
1157109313Sobrien	exit(1);
1158109313Sobrien}
1159