elfdump.c revision 119795
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: head/usr.bin/elfdump/elfdump.c 119795 2003-09-06 11:55:05Z schweikh $");
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
86109313Sobrienint 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
127109313Sobrienint 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 */
235109457Smarcel	case 0x70000000: return "DT_IA64_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{
246109457Smarcel	switch (mach) {
247109457Smarcel	case EM_NONE:	return "EM_NONE";
248109457Smarcel	case EM_M32:	return "EM_M32";
249109457Smarcel	case EM_SPARC:	return "EM_SPARC";
250109457Smarcel	case EM_386:	return "EM_386";
251109457Smarcel	case EM_68K:	return "EM_68K";
252109457Smarcel	case EM_88K:	return "EM_88K";
253109457Smarcel	case EM_486:	return "EM_486";
254109457Smarcel	case EM_860:	return "EM_860";
255109457Smarcel	case EM_MIPS:	return "EM_MIPS";
256109457Smarcel	case EM_IA_64:	return "EM_IA_64";
257109457Smarcel	}
258109457Smarcel	return "(unknown machine)";
259119794Sschweikh}
260109313Sobrien
261110256Sobrienconst char *e_types[] = {
262109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
263109313Sobrien};
264109313Sobrien
265110256Sobrienconst char *ei_versions[] = {
266109313Sobrien	"EV_NONE", "EV_CURRENT"
267109313Sobrien};
268109313Sobrien
269110256Sobrienconst char *ei_classes[] = {
270109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
271109313Sobrien};
272109313Sobrien
273110256Sobrienconst char *ei_data[] = {
274109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
275109313Sobrien};
276109313Sobrien
277110256Sobrienconst char *ei_abis[] = {
278109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
279109313Sobrien	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS",
280109313Sobrien	"ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD",
281109313Sobrien	"ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD"
282109313Sobrien};
283109313Sobrien
284110256Sobrienconst char *p_types[] = {
285109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
286109313Sobrien	"PT_SHLIB", "PT_PHDR"
287109313Sobrien};
288109313Sobrien
289110256Sobrienconst char *p_flags[] = {
290109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
291109313Sobrien	"PF_X|PF_W|PF_R"
292109313Sobrien};
293109313Sobrien
294109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
295110256Sobrienstatic const char *
296109332Sobriensh_types(u_int64_t sht) {
297109329Sobrien	switch (sht) {
298109329Sobrien	case 0:	return "SHT_NULL";
299109329Sobrien	case 1: return "SHT_PROGBITS";
300109329Sobrien	case 2: return "SHT_SYMTAB";
301109329Sobrien	case 3: return "SHT_STRTAB";
302109329Sobrien	case 4: return "SHT_RELA";
303109329Sobrien	case 5: return "SHT_HASH";
304109329Sobrien	case 6: return "SHT_DYNAMIC";
305109329Sobrien	case 7: return "SHT_NOTE";
306109329Sobrien	case 8: return "SHT_NOBITS";
307109329Sobrien	case 9: return "SHT_REL";
308109329Sobrien	case 10: return "SHT_SHLIB";
309109329Sobrien	case 11: return "SHT_DYNSYM";
310109329Sobrien	case 14: return "SHT_INIT_ARRAY";
311109329Sobrien	case 15: return "SHT_FINI_ARRAY";
312109329Sobrien	case 16: return "SHT_PREINIT_ARRAY";
313109329Sobrien	case 17: return "SHT_GROUP";
314109329Sobrien	case 18: return "SHT_SYMTAB_SHNDX";
315109332Sobrien	/* 0x60000000 - 0x6fffffff operating system-specific semantics */
316109329Sobrien	case 0x6ffffff0: return "XXX:VERSYM";
317109329Sobrien	case 0x6ffffff7: return "SHT_GNU_LIBLIST";
318109329Sobrien	case 0x6ffffffc: return "XXX:VERDEF";
319109329Sobrien	case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef";
320109329Sobrien	case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed";
321109329Sobrien	case 0x6fffffff: return "SHT_SUNW(GNU)_versym";
322109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
323109457Smarcel	case 0x70000000: return "SHT_IA_64_EXT";
324109457Smarcel	case 0x70000001: return "SHT_IA_64_UNWIND";
325109329Sobrien	case 0x7ffffffd: return "XXX:AUXILIARY";
326109329Sobrien	case 0x7fffffff: return "XXX:FILTER";
327109332Sobrien	/* 0x80000000 - 0xffffffff application programs */
328109329Sobrien	default: return "ERROR: SHT NOT DEFINED";
329109329Sobrien	}
330119795Sschweikh}
331109313Sobrien
332110256Sobrienconst char *sh_flags[] = {
333109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
334109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
335109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
336109313Sobrien};
337109313Sobrien
338110256Sobrienconst char *st_types[] = {
339109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
340109313Sobrien};
341109313Sobrien
342110256Sobrienconst char *st_bindings[] = {
343109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
344109313Sobrien};
345109313Sobrien
346109313Sobrienchar *dynstr;
347109313Sobrienchar *shstrtab;
348109313Sobrienchar *strtab;
349109313SobrienFILE *out;
350109313Sobrien
351109313Sobrienu_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
352109313Sobrienu_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member);
353109313Sobrienu_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
354109313Sobrienu_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
355109313Sobrienu_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
356109313Sobrien
357110252Sobrienvoid elf_print_ehdr(Elf32_Ehdr *e);
358110252Sobrienvoid elf_print_phdr(Elf32_Ehdr *e, void *p);
359110252Sobrienvoid elf_print_shdr(Elf32_Ehdr *e, void *sh);
360110252Sobrienvoid elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
361110252Sobrienvoid elf_print_dynamic(Elf32_Ehdr *e, void *sh);
362110252Sobrienvoid elf_print_rel(Elf32_Ehdr *e, void *r);
363110252Sobrienvoid elf_print_rela(Elf32_Ehdr *e, void *ra);
364110252Sobrienvoid elf_print_interp(Elf32_Ehdr *e, void *p);
365110252Sobrienvoid elf_print_got(Elf32_Ehdr *e, void *sh);
366110252Sobrienvoid elf_print_hash(Elf32_Ehdr *e, void *sh);
367110252Sobrienvoid elf_print_note(Elf32_Ehdr *e, void *sh);
368109313Sobrien
369109313Sobrienvoid usage(void);
370109313Sobrien
371109313Sobrienint
372109313Sobrienmain(int ac, char **av)
373109313Sobrien{
374109313Sobrien	u_int64_t phoff;
375109313Sobrien	u_int64_t shoff;
376109313Sobrien	u_int64_t phentsize;
377109313Sobrien	u_int64_t phnum;
378109313Sobrien	u_int64_t shentsize;
379109313Sobrien	u_int64_t shnum;
380109313Sobrien	u_int64_t shstrndx;
381109313Sobrien	u_int64_t offset;
382109313Sobrien	u_int64_t name;
383109313Sobrien	u_int64_t type;
384109313Sobrien	struct stat sb;
385109313Sobrien	u_int flags;
386110252Sobrien	Elf32_Ehdr *e;
387109313Sobrien	void *p;
388109313Sobrien	void *sh;
389109313Sobrien	void *v;
390109313Sobrien	int fd;
391109313Sobrien	int ch;
392109313Sobrien	int i;
393109313Sobrien
394109313Sobrien	out = stdout;
395109313Sobrien	flags = 0;
396109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
397109313Sobrien		switch (ch) {
398109313Sobrien		case 'a':
399109313Sobrien			flags = ED_ALL;
400109313Sobrien			break;
401109313Sobrien		case 'c':
402109313Sobrien			flags |= ED_SHDR;
403109313Sobrien			break;
404109313Sobrien		case 'd':
405109313Sobrien			flags |= ED_DYN;
406109313Sobrien			break;
407109313Sobrien		case 'e':
408109313Sobrien			flags |= ED_EHDR;
409109313Sobrien			break;
410109313Sobrien		case 'i':
411109313Sobrien			flags |= ED_INTERP;
412109313Sobrien			break;
413109313Sobrien		case 'G':
414109313Sobrien			flags |= ED_GOT;
415109313Sobrien			break;
416109313Sobrien		case 'h':
417109313Sobrien			flags |= ED_HASH;
418109313Sobrien			break;
419109313Sobrien		case 'n':
420109313Sobrien			flags |= ED_NOTE;
421109313Sobrien			break;
422109313Sobrien		case 'p':
423109313Sobrien			flags |= ED_PHDR;
424109313Sobrien			break;
425109313Sobrien		case 'r':
426109313Sobrien			flags |= ED_REL;
427109313Sobrien			break;
428109313Sobrien		case 's':
429109313Sobrien			flags |= ED_SYMTAB;
430109313Sobrien			break;
431109313Sobrien		case 'w':
432109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
433109313Sobrien				err(1, "%s", optarg);
434109313Sobrien			break;
435109313Sobrien		case '?':
436109313Sobrien		default:
437109313Sobrien			usage();
438109313Sobrien		}
439109313Sobrien	ac -= optind;
440109313Sobrien	av += optind;
441109313Sobrien	if (ac == 0 || flags == 0)
442109313Sobrien		usage();
443109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
444109313Sobrien	    fstat(fd, &sb) < 0)
445117009Sru		err(1, "%s", *av);
446109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
447109313Sobrien	if (e == MAP_FAILED)
448109313Sobrien		err(1, NULL);
449109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
450109313Sobrien		errx(1, "not an elf file");
451109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
452109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
453109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
454109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
455109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
456109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
457109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
458110256Sobrien	p = (char *)e + phoff;
459110256Sobrien	sh = (char *)e + shoff;
460110256Sobrien	offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET);
461110252Sobrien	shstrtab = (char *)e + offset;
462110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
463110256Sobrien		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
464110256Sobrien		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
465109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
466110252Sobrien			strtab = (char *)e + offset;
467109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
468110252Sobrien			dynstr = (char *)e + offset;
469109313Sobrien	}
470109313Sobrien	if (flags & ED_EHDR)
471109313Sobrien		elf_print_ehdr(e);
472109313Sobrien	if (flags & ED_PHDR)
473109313Sobrien		elf_print_phdr(e, p);
474109313Sobrien	if (flags & ED_SHDR)
475109313Sobrien		elf_print_shdr(e, sh);
476110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
477110256Sobrien		v = (char *)p + i * phentsize;
478109313Sobrien		type = elf_get_word(e, v, P_TYPE);
479109313Sobrien		switch (type) {
480109313Sobrien		case PT_INTERP:
481109313Sobrien			if (flags & ED_INTERP)
482109313Sobrien				elf_print_interp(e, v);
483109313Sobrien			break;
484109313Sobrien		case PT_NULL:
485109313Sobrien		case PT_LOAD:
486109313Sobrien		case PT_DYNAMIC:
487109313Sobrien		case PT_NOTE:
488109313Sobrien		case PT_SHLIB:
489109313Sobrien		case PT_PHDR:
490109313Sobrien			break;
491109313Sobrien		}
492109313Sobrien	}
493110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
494110256Sobrien		v = (char *)sh + i * shentsize;
495109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
496109313Sobrien		switch (type) {
497109313Sobrien		case SHT_SYMTAB:
498109313Sobrien			if (flags & ED_SYMTAB)
499109313Sobrien				elf_print_symtab(e, v, strtab);
500109313Sobrien			break;
501109313Sobrien		case SHT_DYNAMIC:
502109313Sobrien			if (flags & ED_DYN)
503109313Sobrien				elf_print_dynamic(e, v);
504109313Sobrien			break;
505109313Sobrien		case SHT_RELA:
506109313Sobrien			if (flags & ED_REL)
507109313Sobrien				elf_print_rela(e, v);
508109313Sobrien			break;
509109313Sobrien		case SHT_REL:
510109313Sobrien			if (flags & ED_REL)
511109313Sobrien				elf_print_rel(e, v);
512109313Sobrien			break;
513109313Sobrien		case SHT_NOTE:
514109313Sobrien			name = elf_get_word(e, v, SH_NAME);
515109313Sobrien			if (flags & ED_NOTE &&
516109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
517109313Sobrien				elf_print_note(e, v);
518109313Sobrien			break;
519109313Sobrien		case SHT_DYNSYM:
520109313Sobrien			if (flags & ED_SYMTAB)
521109313Sobrien				elf_print_symtab(e, v, dynstr);
522109313Sobrien			break;
523109313Sobrien		case SHT_PROGBITS:
524109313Sobrien			name = elf_get_word(e, v, SH_NAME);
525109313Sobrien			if (flags & ED_GOT &&
526109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
527109313Sobrien				elf_print_got(e, v);
528109313Sobrien			break;
529109313Sobrien		case SHT_HASH:
530109313Sobrien			if (flags & ED_HASH)
531109313Sobrien				elf_print_hash(e, v);
532109313Sobrien			break;
533109313Sobrien		case SHT_NULL:
534109313Sobrien		case SHT_STRTAB:
535109313Sobrien		case SHT_NOBITS:
536109313Sobrien		case SHT_SHLIB:
537109313Sobrien			break;
538109313Sobrien		}
539109313Sobrien	}
540109313Sobrien
541109313Sobrien	return 0;
542109313Sobrien}
543109313Sobrien
544109313Sobrienvoid
545110252Sobrienelf_print_ehdr(Elf32_Ehdr *e)
546109313Sobrien{
547109313Sobrien	u_int64_t class;
548109313Sobrien	u_int64_t data;
549109313Sobrien	u_int64_t osabi;
550109313Sobrien	u_int64_t type;
551109313Sobrien	u_int64_t machine;
552109313Sobrien	u_int64_t version;
553109313Sobrien	u_int64_t entry;
554109313Sobrien	u_int64_t phoff;
555109313Sobrien	u_int64_t shoff;
556109313Sobrien	u_int64_t flags;
557109313Sobrien	u_int64_t ehsize;
558109313Sobrien	u_int64_t phentsize;
559109313Sobrien	u_int64_t phnum;
560109313Sobrien	u_int64_t shentsize;
561109313Sobrien	u_int64_t shnum;
562109313Sobrien	u_int64_t shstrndx;
563109313Sobrien
564109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
565109313Sobrien	data = elf_get_byte(e, e, E_DATA);
566109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
567109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
568109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
569109313Sobrien	version = elf_get_word(e, e, E_VERSION);
570109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
571109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
572109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
573109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
574109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
575109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
576109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
577109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
578109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
579109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
580109313Sobrien	fprintf(out, "\nelf header:\n");
581109313Sobrien	fprintf(out, "\n");
582109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
583109313Sobrien	    ei_abis[osabi]);
584109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
585109457Smarcel	fprintf(out, "\te_machine: %s\n", e_machines(machine));
586109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
587110257Sobrien	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
588110257Sobrien	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
589110257Sobrien	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
590110257Sobrien	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
591110257Sobrien	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
592110257Sobrien	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
593110257Sobrien	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
594110257Sobrien	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
595110257Sobrien	fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
596110257Sobrien	fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
597109313Sobrien}
598109313Sobrien
599109313Sobrienvoid
600110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p)
601109313Sobrien{
602109313Sobrien	u_int64_t phentsize;
603109313Sobrien	u_int64_t phnum;
604109313Sobrien	u_int64_t type;
605109313Sobrien	u_int64_t offset;
606109313Sobrien	u_int64_t vaddr;
607109313Sobrien	u_int64_t paddr;
608109313Sobrien	u_int64_t filesz;
609109313Sobrien	u_int64_t memsz;
610109313Sobrien	u_int64_t flags;
611109313Sobrien	u_int64_t align;
612109313Sobrien	void *v;
613109313Sobrien	int i;
614109313Sobrien
615109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
616109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
617109313Sobrien	fprintf(out, "\nprogram header:\n");
618110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
619110256Sobrien		v = (char *)p + i * phentsize;
620109313Sobrien		type = elf_get_word(e, v, P_TYPE);
621109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
622109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
623109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
624109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
625109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
626109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
627109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
628109313Sobrien		fprintf(out, "\n");
629109313Sobrien		fprintf(out, "entry: %d\n", i);
630109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
631110257Sobrien		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
632110257Sobrien		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
633110257Sobrien		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
634110257Sobrien		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
635110257Sobrien		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
636109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
637110257Sobrien		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
638109313Sobrien	}
639109313Sobrien}
640109313Sobrien
641109313Sobrienvoid
642110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh)
643109313Sobrien{
644109313Sobrien	u_int64_t shentsize;
645109313Sobrien	u_int64_t shnum;
646109313Sobrien	u_int64_t name;
647109313Sobrien	u_int64_t type;
648109313Sobrien	u_int64_t flags;
649109313Sobrien	u_int64_t addr;
650109313Sobrien	u_int64_t offset;
651109313Sobrien	u_int64_t size;
652110256Sobrien	u_int64_t shlink;
653109313Sobrien	u_int64_t info;
654109313Sobrien	u_int64_t addralign;
655109313Sobrien	u_int64_t entsize;
656109313Sobrien	void *v;
657109313Sobrien	int i;
658109313Sobrien
659109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
660109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
661109313Sobrien	fprintf(out, "\nsection header:\n");
662110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
663110256Sobrien		v = (char *)sh + i * shentsize;
664109313Sobrien		name = elf_get_word(e, v, SH_NAME);
665109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
666109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
667109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
668109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
669109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
670110256Sobrien		shlink = elf_get_word(e, v, SH_LINK);
671109313Sobrien		info = elf_get_word(e, v, SH_INFO);
672109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
673109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
674109313Sobrien		fprintf(out, "\n");
675109313Sobrien		fprintf(out, "entry: %d\n", i);
676109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
677109329Sobrien		fprintf(out, "\tsh_type: %s\n", sh_types(type));
678109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
679110257Sobrien		fprintf(out, "\tsh_addr: %#jx\n", addr);
680110257Sobrien		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
681110257Sobrien		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
682110257Sobrien		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
683110257Sobrien		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
684110257Sobrien		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
685110257Sobrien		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
686109313Sobrien	}
687109313Sobrien}
688109313Sobrien
689109313Sobrienvoid
690110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
691109313Sobrien{
692109313Sobrien	u_int64_t offset;
693109313Sobrien	u_int64_t entsize;
694109313Sobrien	u_int64_t size;
695109313Sobrien	u_int64_t name;
696109313Sobrien	u_int64_t value;
697109313Sobrien	u_int64_t info;
698109313Sobrien	u_int64_t shndx;
699109313Sobrien	void *st;
700109313Sobrien	int len;
701109313Sobrien	int i;
702109313Sobrien
703109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
704109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
705109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
706109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
707109313Sobrien	len = size / entsize;
708109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
709109313Sobrien	for (i = 0; i < len; i++) {
710110256Sobrien		st = (char *)e + offset + i * entsize;
711109313Sobrien		name = elf_get_word(e, st, ST_NAME);
712109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
713109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
714109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
715109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
716109313Sobrien		fprintf(out, "\n");
717109313Sobrien		fprintf(out, "entry: %d\n", i);
718109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
719110257Sobrien		fprintf(out, "\tst_value: %#jx\n", value);
720110257Sobrien		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
721109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
722109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
723109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
724110257Sobrien		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
725109313Sobrien	}
726109313Sobrien}
727109313Sobrien
728109313Sobrienvoid
729110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh)
730109313Sobrien{
731109313Sobrien	u_int64_t offset;
732109313Sobrien	u_int64_t entsize;
733109313Sobrien	u_int64_t size;
734109313Sobrien	int64_t tag;
735109313Sobrien	u_int64_t ptr;
736109313Sobrien	u_int64_t val;
737109313Sobrien	void *d;
738109313Sobrien	int i;
739109313Sobrien
740109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
741109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
742109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
743109313Sobrien	fprintf(out, "\ndynamic:\n");
744110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
745110256Sobrien		d = (char *)e + offset + i * entsize;
746109313Sobrien		tag = elf_get_size(e, d, D_TAG);
747109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
748109313Sobrien		val = elf_get_addr(e, d, D_VAL);
749109313Sobrien		fprintf(out, "\n");
750109313Sobrien		fprintf(out, "entry: %d\n", i);
751109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
752109313Sobrien		switch (tag) {
753109313Sobrien		case DT_NEEDED:
754109313Sobrien		case DT_SONAME:
755109313Sobrien		case DT_RPATH:
756109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
757109313Sobrien			break;
758109313Sobrien		case DT_PLTRELSZ:
759109313Sobrien		case DT_RELA:
760109313Sobrien		case DT_RELASZ:
761109313Sobrien		case DT_RELAENT:
762109313Sobrien		case DT_STRSZ:
763109313Sobrien		case DT_SYMENT:
764109313Sobrien		case DT_RELSZ:
765109313Sobrien		case DT_RELENT:
766109313Sobrien		case DT_PLTREL:
767110257Sobrien			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
768109313Sobrien			break;
769109313Sobrien		case DT_PLTGOT:
770109313Sobrien		case DT_HASH:
771109313Sobrien		case DT_STRTAB:
772109313Sobrien		case DT_SYMTAB:
773109313Sobrien		case DT_INIT:
774109313Sobrien		case DT_FINI:
775109313Sobrien		case DT_REL:
776109313Sobrien		case DT_JMPREL:
777110257Sobrien			fprintf(out, "\td_ptr: %#jx\n", ptr);
778109313Sobrien			break;
779109313Sobrien		case DT_NULL:
780109313Sobrien		case DT_SYMBOLIC:
781109313Sobrien		case DT_DEBUG:
782109313Sobrien		case DT_TEXTREL:
783109313Sobrien			break;
784109313Sobrien		}
785109313Sobrien	}
786109313Sobrien}
787109313Sobrien
788109313Sobrienvoid
789110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh)
790109313Sobrien{
791109313Sobrien	u_int64_t offset;
792109313Sobrien	u_int64_t entsize;
793109313Sobrien	u_int64_t size;
794109313Sobrien	u_int64_t name;
795109313Sobrien	u_int64_t info;
796109313Sobrien	int64_t addend;
797109313Sobrien	void *ra;
798109313Sobrien	void *v;
799109313Sobrien	int i;
800109313Sobrien
801109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
802109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
803109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
804109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
805110256Sobrien	v = (char *)e + offset;
806109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
807110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
808110256Sobrien		ra = (char *)v + i * entsize;
809109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
810109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
811109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
812109313Sobrien		fprintf(out, "\n");
813109313Sobrien		fprintf(out, "entry: %d\n", i);
814110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
815110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
816110257Sobrien		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
817109313Sobrien	}
818109313Sobrien}
819109313Sobrien
820109313Sobrienvoid
821110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh)
822109313Sobrien{
823109313Sobrien	u_int64_t offset;
824109313Sobrien	u_int64_t entsize;
825109313Sobrien	u_int64_t size;
826109313Sobrien	u_int64_t name;
827109313Sobrien	u_int64_t info;
828109313Sobrien	void *r;
829109313Sobrien	void *v;
830109313Sobrien	int i;
831109313Sobrien
832109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
833109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
834109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
835109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
836110256Sobrien	v = (char *)e + offset;
837109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
838110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
839110256Sobrien		r = (char *)v + i * entsize;
840109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
841109313Sobrien		info = elf_get_word(e, r, R_INFO);
842109313Sobrien		fprintf(out, "\n");
843109313Sobrien		fprintf(out, "entry: %d\n", i);
844110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
845110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
846109313Sobrien	}
847109313Sobrien}
848109313Sobrien
849109313Sobrienvoid
850110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p)
851109313Sobrien{
852109313Sobrien	u_int64_t offset;
853109313Sobrien	char *s;
854109313Sobrien
855109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
856110252Sobrien	s = (char *)e + offset;
857109313Sobrien	fprintf(out, "\ninterp:\n");
858109313Sobrien	fprintf(out, "\t%s\n", s);
859109313Sobrien}
860109313Sobrien
861109313Sobrienvoid
862110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh)
863109313Sobrien{
864109313Sobrien	u_int64_t offset;
865109313Sobrien	u_int64_t addralign;
866109313Sobrien	u_int64_t size;
867109313Sobrien	u_int64_t addr;
868109313Sobrien	void *v;
869109313Sobrien	int i;
870109313Sobrien
871109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
872109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
873109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
874110256Sobrien	v = (char *)e + offset;
875109313Sobrien	fprintf(out, "\nglobal offset table:\n");
876110256Sobrien	for (i = 0; (u_int64_t)i < size / addralign; i++) {
877110256Sobrien		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
878109313Sobrien		fprintf(out, "\n");
879109313Sobrien		fprintf(out, "entry: %d\n", i);
880110257Sobrien		fprintf(out, "\t%#jx\n", addr);
881109313Sobrien	}
882109313Sobrien}
883109313Sobrien
884109313Sobrienvoid
885110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
886109313Sobrien{
887109313Sobrien}
888109313Sobrien
889109313Sobrienvoid
890110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh)
891109313Sobrien{
892109313Sobrien	u_int64_t offset;
893109313Sobrien	u_int64_t size;
894109313Sobrien	u_int64_t name;
895109313Sobrien	u_int32_t namesz;
896109313Sobrien	u_int32_t descsz;
897109313Sobrien	u_int32_t type;
898109313Sobrien	u_int32_t desc;
899110256Sobrien	char *n, *s;
900109313Sobrien
901109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
902109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
903109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
904110256Sobrien	n = (char *)e + offset;
905109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
906110256Sobrien 	while (n < ((char *)e + offset + size)) {
907109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
908109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
909109313Sobrien		type = elf_get_word(e, n, N_TYPE);
910110256Sobrien 		s = n + sizeof(Elf_Note);
911110256Sobrien 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
912109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
913109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
914109313Sobrien	}
915109313Sobrien}
916109313Sobrien
917109313Sobrienu_int64_t
918109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
919109313Sobrien{
920109313Sobrien	u_int64_t val;
921109313Sobrien
922109313Sobrien	val = 0;
923109313Sobrien	switch (e->e_ident[EI_CLASS]) {
924109313Sobrien	case ELFCLASS32:
925118680Smarcel		val = ((char *)base)[elf32_offsets[member]];
926109313Sobrien		break;
927109313Sobrien	case ELFCLASS64:
928118680Smarcel		val = ((char *)base)[elf64_offsets[member]];
929109313Sobrien		break;
930109313Sobrien	case ELFCLASSNONE:
931109313Sobrien		errx(1, "invalid class");
932109313Sobrien	}
933109313Sobrien
934109313Sobrien	return val;
935109313Sobrien}
936109313Sobrien
937109313Sobrienu_int64_t
938109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
939109313Sobrien{
940109313Sobrien	u_int64_t val;
941109313Sobrien
942109313Sobrien	val = 0;
943109313Sobrien	switch (e->e_ident[EI_CLASS]) {
944109313Sobrien	case ELFCLASS32:
945118680Smarcel		base = (char *)base + elf32_offsets[member];
946109313Sobrien		switch (e->e_ident[EI_DATA]) {
947109313Sobrien		case ELFDATA2MSB:
948118680Smarcel			val = be16dec(base);
949109313Sobrien			break;
950109313Sobrien		case ELFDATA2LSB:
951118680Smarcel			val = le16dec(base);
952109313Sobrien			break;
953109313Sobrien		case ELFDATANONE:
954109313Sobrien			errx(1, "invalid data format");
955109313Sobrien		}
956109313Sobrien		break;
957109313Sobrien	case ELFCLASS64:
958118680Smarcel		base = (char *)base + elf64_offsets[member];
959109313Sobrien		switch (e->e_ident[EI_DATA]) {
960109313Sobrien		case ELFDATA2MSB:
961118680Smarcel			val = be16dec(base);
962109313Sobrien			break;
963109313Sobrien		case ELFDATA2LSB:
964118680Smarcel			val = le16dec(base);
965109313Sobrien			break;
966109313Sobrien		case ELFDATANONE:
967109313Sobrien			errx(1, "invalid data format");
968109313Sobrien		}
969109313Sobrien		break;
970109313Sobrien	case ELFCLASSNONE:
971109313Sobrien		errx(1, "invalid class");
972109313Sobrien	}
973109313Sobrien
974109313Sobrien	return val;
975109313Sobrien}
976109313Sobrien
977109313Sobrienu_int64_t
978109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
979109313Sobrien{
980109313Sobrien	u_int64_t val;
981109313Sobrien
982109313Sobrien	val = 0;
983109313Sobrien	switch (e->e_ident[EI_CLASS]) {
984109313Sobrien	case ELFCLASS32:
985118680Smarcel		base = (char *)base + elf32_offsets[member];
986109313Sobrien		switch (e->e_ident[EI_DATA]) {
987109313Sobrien		case ELFDATA2MSB:
988118680Smarcel			val = be16dec(base);
989109313Sobrien			break;
990109313Sobrien		case ELFDATA2LSB:
991118680Smarcel			val = le16dec(base);
992109313Sobrien			break;
993109313Sobrien		case ELFDATANONE:
994109313Sobrien			errx(1, "invalid data format");
995109313Sobrien		}
996109313Sobrien		break;
997109313Sobrien	case ELFCLASS64:
998118680Smarcel		base = (char *)base + elf64_offsets[member];
999109313Sobrien		switch (e->e_ident[EI_DATA]) {
1000109313Sobrien		case ELFDATA2MSB:
1001118680Smarcel			val = be32dec(base);
1002109313Sobrien			break;
1003109313Sobrien		case ELFDATA2LSB:
1004118680Smarcel			val = le32dec(base);
1005109313Sobrien			break;
1006109313Sobrien		case ELFDATANONE:
1007109313Sobrien			errx(1, "invalid data format");
1008109313Sobrien		}
1009109313Sobrien		break;
1010109313Sobrien	case ELFCLASSNONE:
1011109313Sobrien		errx(1, "invalid class");
1012109313Sobrien	}
1013109313Sobrien
1014109313Sobrien	return val;
1015109313Sobrien}
1016109313Sobrien
1017109313Sobrienu_int64_t
1018109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1019109313Sobrien{
1020109313Sobrien	u_int64_t val;
1021109313Sobrien
1022109313Sobrien	val = 0;
1023109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1024109313Sobrien	case ELFCLASS32:
1025118680Smarcel		base = (char *)base + elf32_offsets[member];
1026109313Sobrien		switch (e->e_ident[EI_DATA]) {
1027109313Sobrien		case ELFDATA2MSB:
1028118680Smarcel			val = be32dec(base);
1029109313Sobrien			break;
1030109313Sobrien		case ELFDATA2LSB:
1031118680Smarcel			val = le32dec(base);
1032109313Sobrien			break;
1033109313Sobrien		case ELFDATANONE:
1034109313Sobrien			errx(1, "invalid data format");
1035109313Sobrien		}
1036109313Sobrien		break;
1037109313Sobrien	case ELFCLASS64:
1038118680Smarcel		base = (char *)base + elf64_offsets[member];
1039109313Sobrien		switch (e->e_ident[EI_DATA]) {
1040109313Sobrien		case ELFDATA2MSB:
1041118680Smarcel			val = be32dec(base);
1042109313Sobrien			break;
1043109313Sobrien		case ELFDATA2LSB:
1044118680Smarcel			val = le32dec(base);
1045109313Sobrien			break;
1046109313Sobrien		case ELFDATANONE:
1047109313Sobrien			errx(1, "invalid data format");
1048109313Sobrien		}
1049109313Sobrien		break;
1050109313Sobrien	case ELFCLASSNONE:
1051109313Sobrien		errx(1, "invalid class");
1052109313Sobrien	}
1053109313Sobrien
1054109313Sobrien	return val;
1055109313Sobrien}
1056109313Sobrien
1057109313Sobrienu_int64_t
1058109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1059109313Sobrien{
1060109313Sobrien	u_int64_t val;
1061109313Sobrien
1062109313Sobrien	val = 0;
1063109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1064109313Sobrien	case ELFCLASS32:
1065118680Smarcel		base = (char *)base + elf32_offsets[member];
1066109313Sobrien		switch (e->e_ident[EI_DATA]) {
1067109313Sobrien		case ELFDATA2MSB:
1068118680Smarcel			val = be32dec(base);
1069109313Sobrien			break;
1070109313Sobrien		case ELFDATA2LSB:
1071118680Smarcel			val = le32dec(base);
1072109313Sobrien			break;
1073109313Sobrien		case ELFDATANONE:
1074109313Sobrien			errx(1, "invalid data format");
1075109313Sobrien		}
1076109313Sobrien		break;
1077109313Sobrien	case ELFCLASS64:
1078118680Smarcel		base = (char *)base + elf64_offsets[member];
1079109313Sobrien		switch (e->e_ident[EI_DATA]) {
1080109313Sobrien		case ELFDATA2MSB:
1081118680Smarcel			val = be64dec(base);
1082109313Sobrien			break;
1083109313Sobrien		case ELFDATA2LSB:
1084118680Smarcel			val = le64dec(base);
1085109313Sobrien			break;
1086109313Sobrien		case ELFDATANONE:
1087109313Sobrien			errx(1, "invalid data format");
1088109313Sobrien		}
1089109313Sobrien		break;
1090109313Sobrien	case ELFCLASSNONE:
1091109313Sobrien		errx(1, "invalid class");
1092109313Sobrien	}
1093109313Sobrien
1094109313Sobrien	return val;
1095109313Sobrien}
1096109313Sobrien
1097109313Sobrienvoid
1098109313Sobrienusage(void)
1099109313Sobrien{
1100117009Sru	fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n");
1101109313Sobrien	exit(1);
1102109313Sobrien}
1103