elfdump.c revision 110257
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 110257 2003-02-03 01:30:47Z obrien $");
30109313Sobrien
31109313Sobrien#include <sys/types.h>
32109313Sobrien#include <sys/elf32.h>
33109313Sobrien#include <sys/elf64.h>
34109313Sobrien#include <sys/mman.h>
35109313Sobrien#include <sys/stat.h>
36109313Sobrien#include <err.h>
37109313Sobrien#include <fcntl.h>
38110257Sobrien#include <inttypes.h>
39109313Sobrien#include <stddef.h>
40109313Sobrien#include <stdio.h>
41109313Sobrien#include <stdlib.h>
42109313Sobrien#include <string.h>
43109313Sobrien#include <unistd.h>
44109313Sobrien
45109313Sobrien#define	ED_DYN		(1<<0)
46109313Sobrien#define	ED_EHDR		(1<<1)
47109313Sobrien#define	ED_GOT		(1<<2)
48109313Sobrien#define	ED_HASH		(1<<3)
49109313Sobrien#define	ED_INTERP	(1<<4)
50109313Sobrien#define	ED_NOTE		(1<<5)
51109313Sobrien#define	ED_PHDR		(1<<6)
52109313Sobrien#define	ED_REL		(1<<7)
53109313Sobrien#define	ED_SHDR		(1<<8)
54109313Sobrien#define	ED_SYMTAB	(1<<9)
55109313Sobrien#define	ED_ALL		((1<<10)-1)
56109313Sobrien
57109313Sobrien#define	elf_get_addr	elf_get_quad
58109313Sobrien#define	elf_get_off	elf_get_quad
59109313Sobrien#define	elf_get_size	elf_get_quad
60109313Sobrien
61109313Sobrienenum elf_member {
62109313Sobrien	D_TAG = 1, D_PTR, D_VAL,
63109313Sobrien
64109313Sobrien	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
65109313Sobrien	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
66109313Sobrien	E_SHNUM, E_SHSTRNDX,
67109313Sobrien
68109313Sobrien	N_NAMESZ, N_DESCSZ, N_TYPE,
69109313Sobrien
70109313Sobrien	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
71109313Sobrien	P_ALIGN,
72109313Sobrien
73109313Sobrien	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
74109313Sobrien	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
75109313Sobrien
76109313Sobrien	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
77109313Sobrien
78109313Sobrien	R_OFFSET, R_INFO,
79109313Sobrien
80109313Sobrien	RA_OFFSET, RA_INFO, RA_ADDEND
81109313Sobrien};
82109313Sobrien
83109313Sobrientypedef enum elf_member elf_member_t;
84109313Sobrien
85109313Sobrienint elf32_offsets[] = {
86109313Sobrien	0,
87109313Sobrien
88109313Sobrien	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
89109313Sobrien	offsetof(Elf32_Dyn, d_un.d_val),
90109313Sobrien
91109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
92109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
93109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
94109313Sobrien	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
95109313Sobrien	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
96109313Sobrien	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
97109313Sobrien	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
98109313Sobrien	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
99109313Sobrien	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
100109313Sobrien	offsetof(Elf32_Ehdr, e_shstrndx),
101109313Sobrien
102109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
103109313Sobrien	offsetof(Elf_Note, n_type),
104109313Sobrien
105109313Sobrien	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
106109313Sobrien	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
107109313Sobrien	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
108109313Sobrien	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
109109313Sobrien
110109313Sobrien	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
111109313Sobrien	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
112109313Sobrien	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
113109313Sobrien	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
114109313Sobrien	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
115109313Sobrien
116109313Sobrien	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
117109313Sobrien	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
118109313Sobrien	offsetof(Elf32_Sym, st_shndx),
119109313Sobrien
120109313Sobrien	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
121109313Sobrien
122109313Sobrien	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
123109313Sobrien	offsetof(Elf32_Rela, r_addend)
124109313Sobrien};
125109313Sobrien
126109313Sobrienint elf64_offsets[] = {
127109313Sobrien	0,
128109313Sobrien
129109313Sobrien	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
130109313Sobrien	offsetof(Elf64_Dyn, d_un.d_val),
131109313Sobrien
132109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
133109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
134109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
135109313Sobrien	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
136109313Sobrien	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
137109313Sobrien	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
138109313Sobrien	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
139109313Sobrien	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
140109313Sobrien	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
141109313Sobrien	offsetof(Elf64_Ehdr, e_shstrndx),
142109313Sobrien
143109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
144109313Sobrien	offsetof(Elf_Note, n_type),
145109313Sobrien
146109313Sobrien	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
147109313Sobrien	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
148109313Sobrien	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
149109313Sobrien	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
150109313Sobrien
151109313Sobrien	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
152109313Sobrien	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
153109313Sobrien	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
154109313Sobrien	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
155109313Sobrien	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
156109313Sobrien
157109313Sobrien	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
158109313Sobrien	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
159109313Sobrien	offsetof(Elf64_Sym, st_shndx),
160109313Sobrien
161109313Sobrien	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
162109313Sobrien
163109313Sobrien	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
164109313Sobrien	offsetof(Elf64_Rela, r_addend)
165109313Sobrien};
166109313Sobrien
167109332Sobrien/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
168110256Sobrienstatic const char *
169109332Sobriend_tags(u_int64_t tag) {
170109332Sobrien	switch (tag) {
171109332Sobrien	case 0: return "DT_NULL";
172109332Sobrien	case 1: return "DT_NEEDED";
173109332Sobrien	case 2: return "DT_PLTRELSZ";
174109332Sobrien	case 3: return "DT_PLTGOT";
175109332Sobrien	case 4: return "DT_HASH";
176109332Sobrien	case 5: return "DT_STRTAB";
177109332Sobrien	case 6: return "DT_SYMTAB";
178109332Sobrien	case 7: return "DT_RELA";
179109332Sobrien	case 8: return "DT_RELASZ";
180109332Sobrien	case 9: return "DT_RELAENT";
181109332Sobrien	case 10: return "DT_STRSZ";
182109332Sobrien	case 11: return "DT_SYMENT";
183109332Sobrien	case 12: return "DT_INIT";
184109332Sobrien	case 13: return "DT_FINI";
185109332Sobrien	case 14: return "DT_SONAME";
186109332Sobrien	case 15: return "DT_RPATH";
187109332Sobrien	case 16: return "DT_SYMBOLIC";
188109332Sobrien	case 17: return "DT_REL";
189109332Sobrien	case 18: return "DT_RELSZ";
190109332Sobrien	case 19: return "DT_RELENT";
191109332Sobrien	case 20: return "DT_PLTREL";
192109332Sobrien	case 21: return "DT_DEBUG";
193109332Sobrien	case 22: return "DT_TEXTREL";
194109332Sobrien	case 23: return "DT_JMPREL";
195109332Sobrien	case 24: return "DT_BIND_NOW";
196109332Sobrien	case 25: return "DT_INIT_ARRAY";
197109332Sobrien	case 26: return "DT_FINI_ARRAY";
198109332Sobrien	case 27: return "DT_INIT_ARRAYSZ";
199109332Sobrien	case 28: return "DT_FINI_ARRAYSZ";
200109332Sobrien	case 29: return "DT_RUNPATH";
201109332Sobrien	case 30: return "DT_FLAGS";
202109332Sobrien	case 32: return "DT_PREINIT_ARRAY"; /* XXX: DT_ENCODING */
203109332Sobrien	case 33: return "DT_PREINIT_ARRAYSZ";
204109332Sobrien	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
205109332Sobrien	case 0x6ffffdf5: return "DT_GNU_PRELINKED";
206109332Sobrien	case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ";
207109332Sobrien	case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ";
208109332Sobrien	case 0x6ffffdf8: return "DT_SUNW_CHECKSUM";
209109332Sobrien	case 0x6ffffdf9: return "DT_PLTPADSZ";
210109332Sobrien	case 0x6ffffdfa: return "DT_MOVEENT";
211109332Sobrien	case 0x6ffffdfb: return "DT_MOVESZ";
212109332Sobrien	case 0x6ffffdfc: return "DT_FEATURE";
213109332Sobrien	case 0x6ffffdfd: return "DT_POSFLAG_1";
214109332Sobrien	case 0x6ffffdfe: return "DT_SYMINSZ";
215109332Sobrien	case 0x6ffffdff: return "DT_SYMINENT (DT_VALRNGHI)";
216109332Sobrien	case 0x6ffffe00: return "DT_ADDRRNGLO";
217109332Sobrien	case 0x6ffffef8: return "DT_GNU_CONFLICT";
218109332Sobrien	case 0x6ffffef9: return "DT_GNU_LIBLIST";
219109332Sobrien	case 0x6ffffefa: return "DT_SUNW_CONFIG";
220109332Sobrien	case 0x6ffffefb: return "DT_SUNW_DEPAUDIT";
221109332Sobrien	case 0x6ffffefc: return "DT_SUNW_AUDIT";
222109332Sobrien	case 0x6ffffefd: return "DT_SUNW_PLTPAD";
223109332Sobrien	case 0x6ffffefe: return "DT_SUNW_MOVETAB";
224109332Sobrien	case 0x6ffffeff: return "DT_SYMINFO (DT_ADDRRNGHI)";
225109332Sobrien	case 0x6ffffff9: return "DT_RELACOUNT";
226109332Sobrien	case 0x6ffffffa: return "DT_RELCOUNT";
227109332Sobrien	case 0x6ffffffb: return "DT_FLAGS_1";
228109332Sobrien	case 0x6ffffffc: return "DT_VERDEF";
229109332Sobrien	case 0x6ffffffd: return "DT_VERDEFNUM";
230109332Sobrien	case 0x6ffffffe: return "DT_VERNEED";
231109332Sobrien	case 0x6fffffff: return "DT_VERNEEDNUM";
232109332Sobrien	case 0x6ffffff0: return "DT_GNU_VERSYM";
233109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
234109457Smarcel	case 0x70000000: return "DT_IA64_PLT_RESERVE";
235109332Sobrien	case 0x7ffffffd: return "DT_SUNW_AUXILIARY";
236109332Sobrien	case 0x7ffffffe: return "DT_SUNW_USED";
237109332Sobrien	case 0x7fffffff: return "DT_SUNW_FILTER";
238109332Sobrien	default: return "ERROR: TAG NOT DEFINED";
239109332Sobrien	}
240109313Sobrien};
241109313Sobrien
242110256Sobrienstatic const char *
243109457Smarcele_machines(u_int mach)
244109457Smarcel{
245109457Smarcel	switch (mach) {
246109457Smarcel	case EM_NONE:	return "EM_NONE";
247109457Smarcel	case EM_M32:	return "EM_M32";
248109457Smarcel	case EM_SPARC:	return "EM_SPARC";
249109457Smarcel	case EM_386:	return "EM_386";
250109457Smarcel	case EM_68K:	return "EM_68K";
251109457Smarcel	case EM_88K:	return "EM_88K";
252109457Smarcel	case EM_486:	return "EM_486";
253109457Smarcel	case EM_860:	return "EM_860";
254109457Smarcel	case EM_MIPS:	return "EM_MIPS";
255109457Smarcel	case EM_IA_64:	return "EM_IA_64";
256109457Smarcel	}
257109457Smarcel	return "(unknown machine)";
258109313Sobrien};
259109313Sobrien
260110256Sobrienconst char *e_types[] = {
261109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
262109313Sobrien};
263109313Sobrien
264110256Sobrienconst char *ei_versions[] = {
265109313Sobrien	"EV_NONE", "EV_CURRENT"
266109313Sobrien};
267109313Sobrien
268110256Sobrienconst char *ei_classes[] = {
269109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
270109313Sobrien};
271109313Sobrien
272110256Sobrienconst char *ei_data[] = {
273109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
274109313Sobrien};
275109313Sobrien
276110256Sobrienconst char *ei_abis[] = {
277109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
278109313Sobrien	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS",
279109313Sobrien	"ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD",
280109313Sobrien	"ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD"
281109313Sobrien};
282109313Sobrien
283110256Sobrienconst char *p_types[] = {
284109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
285109313Sobrien	"PT_SHLIB", "PT_PHDR"
286109313Sobrien};
287109313Sobrien
288110256Sobrienconst char *p_flags[] = {
289109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
290109313Sobrien	"PF_X|PF_W|PF_R"
291109313Sobrien};
292109313Sobrien
293109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
294110256Sobrienstatic const char *
295109332Sobriensh_types(u_int64_t sht) {
296109329Sobrien	switch (sht) {
297109329Sobrien	case 0:	return "SHT_NULL";
298109329Sobrien	case 1: return "SHT_PROGBITS";
299109329Sobrien	case 2: return "SHT_SYMTAB";
300109329Sobrien	case 3: return "SHT_STRTAB";
301109329Sobrien	case 4: return "SHT_RELA";
302109329Sobrien	case 5: return "SHT_HASH";
303109329Sobrien	case 6: return "SHT_DYNAMIC";
304109329Sobrien	case 7: return "SHT_NOTE";
305109329Sobrien	case 8: return "SHT_NOBITS";
306109329Sobrien	case 9: return "SHT_REL";
307109329Sobrien	case 10: return "SHT_SHLIB";
308109329Sobrien	case 11: return "SHT_DYNSYM";
309109329Sobrien	case 14: return "SHT_INIT_ARRAY";
310109329Sobrien	case 15: return "SHT_FINI_ARRAY";
311109329Sobrien	case 16: return "SHT_PREINIT_ARRAY";
312109329Sobrien	case 17: return "SHT_GROUP";
313109329Sobrien	case 18: return "SHT_SYMTAB_SHNDX";
314109332Sobrien	/* 0x60000000 - 0x6fffffff operating system-specific semantics */
315109329Sobrien	case 0x6ffffff0: return "XXX:VERSYM";
316109329Sobrien	case 0x6ffffff7: return "SHT_GNU_LIBLIST";
317109329Sobrien	case 0x6ffffffc: return "XXX:VERDEF";
318109329Sobrien	case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef";
319109329Sobrien	case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed";
320109329Sobrien	case 0x6fffffff: return "SHT_SUNW(GNU)_versym";
321109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
322109457Smarcel	case 0x70000000: return "SHT_IA_64_EXT";
323109457Smarcel	case 0x70000001: return "SHT_IA_64_UNWIND";
324109329Sobrien	case 0x7ffffffd: return "XXX:AUXILIARY";
325109329Sobrien	case 0x7fffffff: return "XXX:FILTER";
326109332Sobrien	/* 0x80000000 - 0xffffffff application programs */
327109329Sobrien	default: return "ERROR: SHT NOT DEFINED";
328109329Sobrien	}
329109313Sobrien};
330109313Sobrien
331110256Sobrienconst char *sh_flags[] = {
332109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
333109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
334109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
335109313Sobrien};
336109313Sobrien
337110256Sobrienconst char *st_types[] = {
338109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
339109313Sobrien};
340109313Sobrien
341110256Sobrienconst char *st_bindings[] = {
342109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
343109313Sobrien};
344109313Sobrien
345109313Sobrienchar *dynstr;
346109313Sobrienchar *shstrtab;
347109313Sobrienchar *strtab;
348109313SobrienFILE *out;
349109313Sobrien
350109313Sobrienu_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
351109313Sobrienu_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member);
352109313Sobrienu_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
353109313Sobrienu_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
354109313Sobrienu_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
355109313Sobrien
356110252Sobrienvoid elf_print_ehdr(Elf32_Ehdr *e);
357110252Sobrienvoid elf_print_phdr(Elf32_Ehdr *e, void *p);
358110252Sobrienvoid elf_print_shdr(Elf32_Ehdr *e, void *sh);
359110252Sobrienvoid elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str);
360110252Sobrienvoid elf_print_dynamic(Elf32_Ehdr *e, void *sh);
361110252Sobrienvoid elf_print_rel(Elf32_Ehdr *e, void *r);
362110252Sobrienvoid elf_print_rela(Elf32_Ehdr *e, void *ra);
363110252Sobrienvoid elf_print_interp(Elf32_Ehdr *e, void *p);
364110252Sobrienvoid elf_print_got(Elf32_Ehdr *e, void *sh);
365110252Sobrienvoid elf_print_hash(Elf32_Ehdr *e, void *sh);
366110252Sobrienvoid elf_print_note(Elf32_Ehdr *e, void *sh);
367109313Sobrien
368109313Sobrienvoid usage(void);
369109313Sobrien
370109313Sobrienint
371109313Sobrienmain(int ac, char **av)
372109313Sobrien{
373109313Sobrien	u_int64_t phoff;
374109313Sobrien	u_int64_t shoff;
375109313Sobrien	u_int64_t phentsize;
376109313Sobrien	u_int64_t phnum;
377109313Sobrien	u_int64_t shentsize;
378109313Sobrien	u_int64_t shnum;
379109313Sobrien	u_int64_t shstrndx;
380109313Sobrien	u_int64_t offset;
381109313Sobrien	u_int64_t name;
382109313Sobrien	u_int64_t type;
383109313Sobrien	struct stat sb;
384109313Sobrien	u_int flags;
385110252Sobrien	Elf32_Ehdr *e;
386109313Sobrien	void *p;
387109313Sobrien	void *sh;
388109313Sobrien	void *v;
389109313Sobrien	int fd;
390109313Sobrien	int ch;
391109313Sobrien	int i;
392109313Sobrien
393109313Sobrien	out = stdout;
394109313Sobrien	flags = 0;
395109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
396109313Sobrien		switch (ch) {
397109313Sobrien		case 'a':
398109313Sobrien			flags = ED_ALL;
399109313Sobrien			break;
400109313Sobrien		case 'c':
401109313Sobrien			flags |= ED_SHDR;
402109313Sobrien			break;
403109313Sobrien		case 'd':
404109313Sobrien			flags |= ED_DYN;
405109313Sobrien			break;
406109313Sobrien		case 'e':
407109313Sobrien			flags |= ED_EHDR;
408109313Sobrien			break;
409109313Sobrien		case 'i':
410109313Sobrien			flags |= ED_INTERP;
411109313Sobrien			break;
412109313Sobrien		case 'G':
413109313Sobrien			flags |= ED_GOT;
414109313Sobrien			break;
415109313Sobrien		case 'h':
416109313Sobrien			flags |= ED_HASH;
417109313Sobrien			break;
418109313Sobrien		case 'n':
419109313Sobrien			flags |= ED_NOTE;
420109313Sobrien			break;
421109313Sobrien		case 'p':
422109313Sobrien			flags |= ED_PHDR;
423109313Sobrien			break;
424109313Sobrien		case 'r':
425109313Sobrien			flags |= ED_REL;
426109313Sobrien			break;
427109313Sobrien		case 's':
428109313Sobrien			flags |= ED_SYMTAB;
429109313Sobrien			break;
430109313Sobrien		case 'w':
431109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
432109313Sobrien				err(1, "%s", optarg);
433109313Sobrien			break;
434109313Sobrien		case '?':
435109313Sobrien		default:
436109313Sobrien			usage();
437109313Sobrien		}
438109313Sobrien	ac -= optind;
439109313Sobrien	av += optind;
440109313Sobrien	if (ac == 0 || flags == 0)
441109313Sobrien		usage();
442109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
443109313Sobrien	    fstat(fd, &sb) < 0)
444109313Sobrien		err(1, NULL);
445109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
446109313Sobrien	if (e == MAP_FAILED)
447109313Sobrien		err(1, NULL);
448109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
449109313Sobrien		errx(1, "not an elf file");
450109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
451109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
452109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
453109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
454109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
455109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
456109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
457110256Sobrien	p = (char *)e + phoff;
458110256Sobrien	sh = (char *)e + shoff;
459110256Sobrien	offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, SH_OFFSET);
460110252Sobrien	shstrtab = (char *)e + offset;
461110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
462110256Sobrien		name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME);
463110256Sobrien		offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET);
464109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
465110252Sobrien			strtab = (char *)e + offset;
466109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
467110252Sobrien			dynstr = (char *)e + offset;
468109313Sobrien	}
469109313Sobrien	if (flags & ED_EHDR)
470109313Sobrien		elf_print_ehdr(e);
471109313Sobrien	if (flags & ED_PHDR)
472109313Sobrien		elf_print_phdr(e, p);
473109313Sobrien	if (flags & ED_SHDR)
474109313Sobrien		elf_print_shdr(e, sh);
475110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
476110256Sobrien		v = (char *)p + i * phentsize;
477109313Sobrien		type = elf_get_word(e, v, P_TYPE);
478109313Sobrien		switch (type) {
479109313Sobrien		case PT_INTERP:
480109313Sobrien			if (flags & ED_INTERP)
481109313Sobrien				elf_print_interp(e, v);
482109313Sobrien			break;
483109313Sobrien		case PT_NULL:
484109313Sobrien		case PT_LOAD:
485109313Sobrien		case PT_DYNAMIC:
486109313Sobrien		case PT_NOTE:
487109313Sobrien		case PT_SHLIB:
488109313Sobrien		case PT_PHDR:
489109313Sobrien			break;
490109313Sobrien		}
491109313Sobrien	}
492110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
493110256Sobrien		v = (char *)sh + i * shentsize;
494109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
495109313Sobrien		switch (type) {
496109313Sobrien		case SHT_SYMTAB:
497109313Sobrien			if (flags & ED_SYMTAB)
498109313Sobrien				elf_print_symtab(e, v, strtab);
499109313Sobrien			break;
500109313Sobrien		case SHT_DYNAMIC:
501109313Sobrien			if (flags & ED_DYN)
502109313Sobrien				elf_print_dynamic(e, v);
503109313Sobrien			break;
504109313Sobrien		case SHT_RELA:
505109313Sobrien			if (flags & ED_REL)
506109313Sobrien				elf_print_rela(e, v);
507109313Sobrien			break;
508109313Sobrien		case SHT_REL:
509109313Sobrien			if (flags & ED_REL)
510109313Sobrien				elf_print_rel(e, v);
511109313Sobrien			break;
512109313Sobrien		case SHT_NOTE:
513109313Sobrien			name = elf_get_word(e, v, SH_NAME);
514109313Sobrien			if (flags & ED_NOTE &&
515109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
516109313Sobrien				elf_print_note(e, v);
517109313Sobrien			break;
518109313Sobrien		case SHT_DYNSYM:
519109313Sobrien			if (flags & ED_SYMTAB)
520109313Sobrien				elf_print_symtab(e, v, dynstr);
521109313Sobrien			break;
522109313Sobrien		case SHT_PROGBITS:
523109313Sobrien			name = elf_get_word(e, v, SH_NAME);
524109313Sobrien			if (flags & ED_GOT &&
525109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
526109313Sobrien				elf_print_got(e, v);
527109313Sobrien			break;
528109313Sobrien		case SHT_HASH:
529109313Sobrien			if (flags & ED_HASH)
530109313Sobrien				elf_print_hash(e, v);
531109313Sobrien			break;
532109313Sobrien		case SHT_NULL:
533109313Sobrien		case SHT_STRTAB:
534109313Sobrien		case SHT_NOBITS:
535109313Sobrien		case SHT_SHLIB:
536109313Sobrien			break;
537109313Sobrien		}
538109313Sobrien	}
539109313Sobrien
540109313Sobrien	return 0;
541109313Sobrien}
542109313Sobrien
543109313Sobrienvoid
544110252Sobrienelf_print_ehdr(Elf32_Ehdr *e)
545109313Sobrien{
546109313Sobrien	u_int64_t class;
547109313Sobrien	u_int64_t data;
548109313Sobrien	u_int64_t osabi;
549109313Sobrien	u_int64_t type;
550109313Sobrien	u_int64_t machine;
551109313Sobrien	u_int64_t version;
552109313Sobrien	u_int64_t entry;
553109313Sobrien	u_int64_t phoff;
554109313Sobrien	u_int64_t shoff;
555109313Sobrien	u_int64_t flags;
556109313Sobrien	u_int64_t ehsize;
557109313Sobrien	u_int64_t phentsize;
558109313Sobrien	u_int64_t phnum;
559109313Sobrien	u_int64_t shentsize;
560109313Sobrien	u_int64_t shnum;
561109313Sobrien	u_int64_t shstrndx;
562109313Sobrien
563109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
564109313Sobrien	data = elf_get_byte(e, e, E_DATA);
565109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
566109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
567109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
568109313Sobrien	version = elf_get_word(e, e, E_VERSION);
569109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
570109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
571109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
572109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
573109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
574109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
575109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
576109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
577109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
578109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
579109313Sobrien	fprintf(out, "\nelf header:\n");
580109313Sobrien	fprintf(out, "\n");
581109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
582109313Sobrien	    ei_abis[osabi]);
583109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
584109457Smarcel	fprintf(out, "\te_machine: %s\n", e_machines(machine));
585109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
586110257Sobrien	fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry);
587110257Sobrien	fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff);
588110257Sobrien	fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff);
589110257Sobrien	fprintf(out, "\te_flags: %jd\n", (intmax_t)flags);
590110257Sobrien	fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize);
591110257Sobrien	fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize);
592110257Sobrien	fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum);
593110257Sobrien	fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize);
594110257Sobrien	fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum);
595110257Sobrien	fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx);
596109313Sobrien}
597109313Sobrien
598109313Sobrienvoid
599110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p)
600109313Sobrien{
601109313Sobrien	u_int64_t phentsize;
602109313Sobrien	u_int64_t phnum;
603109313Sobrien	u_int64_t type;
604109313Sobrien	u_int64_t offset;
605109313Sobrien	u_int64_t vaddr;
606109313Sobrien	u_int64_t paddr;
607109313Sobrien	u_int64_t filesz;
608109313Sobrien	u_int64_t memsz;
609109313Sobrien	u_int64_t flags;
610109313Sobrien	u_int64_t align;
611109313Sobrien	void *v;
612109313Sobrien	int i;
613109313Sobrien
614109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
615109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
616109313Sobrien	fprintf(out, "\nprogram header:\n");
617110256Sobrien	for (i = 0; (u_int64_t)i < phnum; i++) {
618110256Sobrien		v = (char *)p + i * phentsize;
619109313Sobrien		type = elf_get_word(e, v, P_TYPE);
620109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
621109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
622109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
623109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
624109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
625109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
626109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
627109313Sobrien		fprintf(out, "\n");
628109313Sobrien		fprintf(out, "entry: %d\n", i);
629109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
630110257Sobrien		fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset);
631110257Sobrien		fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr);
632110257Sobrien		fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr);
633110257Sobrien		fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz);
634110257Sobrien		fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz);
635109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
636110257Sobrien		fprintf(out, "\tp_align: %jd\n", (intmax_t)align);
637109313Sobrien	}
638109313Sobrien}
639109313Sobrien
640109313Sobrienvoid
641110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh)
642109313Sobrien{
643109313Sobrien	u_int64_t shentsize;
644109313Sobrien	u_int64_t shnum;
645109313Sobrien	u_int64_t name;
646109313Sobrien	u_int64_t type;
647109313Sobrien	u_int64_t flags;
648109313Sobrien	u_int64_t addr;
649109313Sobrien	u_int64_t offset;
650109313Sobrien	u_int64_t size;
651110256Sobrien	u_int64_t shlink;
652109313Sobrien	u_int64_t info;
653109313Sobrien	u_int64_t addralign;
654109313Sobrien	u_int64_t entsize;
655109313Sobrien	void *v;
656109313Sobrien	int i;
657109313Sobrien
658109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
659109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
660109313Sobrien	fprintf(out, "\nsection header:\n");
661110256Sobrien	for (i = 0; (u_int64_t)i < shnum; i++) {
662110256Sobrien		v = (char *)sh + i * shentsize;
663109313Sobrien		name = elf_get_word(e, v, SH_NAME);
664109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
665109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
666109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
667109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
668109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
669110256Sobrien		shlink = elf_get_word(e, v, SH_LINK);
670109313Sobrien		info = elf_get_word(e, v, SH_INFO);
671109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
672109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
673109313Sobrien		fprintf(out, "\n");
674109313Sobrien		fprintf(out, "entry: %d\n", i);
675109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
676109329Sobrien		fprintf(out, "\tsh_type: %s\n", sh_types(type));
677109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
678110257Sobrien		fprintf(out, "\tsh_addr: %#jx\n", addr);
679110257Sobrien		fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset);
680110257Sobrien		fprintf(out, "\tsh_size: %jd\n", (intmax_t)size);
681110257Sobrien		fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink);
682110257Sobrien		fprintf(out, "\tsh_info: %jd\n", (intmax_t)info);
683110257Sobrien		fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign);
684110257Sobrien		fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize);
685109313Sobrien	}
686109313Sobrien}
687109313Sobrien
688109313Sobrienvoid
689110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str)
690109313Sobrien{
691109313Sobrien	u_int64_t offset;
692109313Sobrien	u_int64_t entsize;
693109313Sobrien	u_int64_t size;
694109313Sobrien	u_int64_t name;
695109313Sobrien	u_int64_t value;
696109313Sobrien	u_int64_t info;
697109313Sobrien	u_int64_t shndx;
698109313Sobrien	void *st;
699109313Sobrien	int len;
700109313Sobrien	int i;
701109313Sobrien
702109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
703109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
704109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
705109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
706109313Sobrien	len = size / entsize;
707109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
708109313Sobrien	for (i = 0; i < len; i++) {
709110256Sobrien		st = (char *)e + offset + i * entsize;
710109313Sobrien		name = elf_get_word(e, st, ST_NAME);
711109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
712109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
713109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
714109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
715109313Sobrien		fprintf(out, "\n");
716109313Sobrien		fprintf(out, "entry: %d\n", i);
717109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
718110257Sobrien		fprintf(out, "\tst_value: %#jx\n", value);
719110257Sobrien		fprintf(out, "\tst_size: %jd\n", (intmax_t)size);
720109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
721109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
722109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
723110257Sobrien		fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx);
724109313Sobrien	}
725109313Sobrien}
726109313Sobrien
727109313Sobrienvoid
728110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh)
729109313Sobrien{
730109313Sobrien	u_int64_t offset;
731109313Sobrien	u_int64_t entsize;
732109313Sobrien	u_int64_t size;
733109313Sobrien	int64_t tag;
734109313Sobrien	u_int64_t ptr;
735109313Sobrien	u_int64_t val;
736109313Sobrien	void *d;
737109313Sobrien	int i;
738109313Sobrien
739109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
740109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
741109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
742109313Sobrien	fprintf(out, "\ndynamic:\n");
743110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
744110256Sobrien		d = (char *)e + offset + i * entsize;
745109313Sobrien		tag = elf_get_size(e, d, D_TAG);
746109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
747109313Sobrien		val = elf_get_addr(e, d, D_VAL);
748109313Sobrien		fprintf(out, "\n");
749109313Sobrien		fprintf(out, "entry: %d\n", i);
750109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
751109313Sobrien		switch (tag) {
752109313Sobrien		case DT_NEEDED:
753109313Sobrien		case DT_SONAME:
754109313Sobrien		case DT_RPATH:
755109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
756109313Sobrien			break;
757109313Sobrien		case DT_PLTRELSZ:
758109313Sobrien		case DT_RELA:
759109313Sobrien		case DT_RELASZ:
760109313Sobrien		case DT_RELAENT:
761109313Sobrien		case DT_STRSZ:
762109313Sobrien		case DT_SYMENT:
763109313Sobrien		case DT_RELSZ:
764109313Sobrien		case DT_RELENT:
765109313Sobrien		case DT_PLTREL:
766110257Sobrien			fprintf(out, "\td_val: %jd\n", (intmax_t)val);
767109313Sobrien			break;
768109313Sobrien		case DT_PLTGOT:
769109313Sobrien		case DT_HASH:
770109313Sobrien		case DT_STRTAB:
771109313Sobrien		case DT_SYMTAB:
772109313Sobrien		case DT_INIT:
773109313Sobrien		case DT_FINI:
774109313Sobrien		case DT_REL:
775109313Sobrien		case DT_JMPREL:
776110257Sobrien			fprintf(out, "\td_ptr: %#jx\n", ptr);
777109313Sobrien			break;
778109313Sobrien		case DT_NULL:
779109313Sobrien		case DT_SYMBOLIC:
780109313Sobrien		case DT_DEBUG:
781109313Sobrien		case DT_TEXTREL:
782109313Sobrien			break;
783109313Sobrien		}
784109313Sobrien	}
785109313Sobrien}
786109313Sobrien
787109313Sobrienvoid
788110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh)
789109313Sobrien{
790109313Sobrien	u_int64_t offset;
791109313Sobrien	u_int64_t entsize;
792109313Sobrien	u_int64_t size;
793109313Sobrien	u_int64_t name;
794109313Sobrien	u_int64_t info;
795109313Sobrien	int64_t addend;
796109313Sobrien	void *ra;
797109313Sobrien	void *v;
798109313Sobrien	int i;
799109313Sobrien
800109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
801109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
802109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
803109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
804110256Sobrien	v = (char *)e + offset;
805109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
806110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
807110256Sobrien		ra = (char *)v + i * entsize;
808109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
809109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
810109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
811109313Sobrien		fprintf(out, "\n");
812109313Sobrien		fprintf(out, "entry: %d\n", i);
813110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
814110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
815110257Sobrien		fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend);
816109313Sobrien	}
817109313Sobrien}
818109313Sobrien
819109313Sobrienvoid
820110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh)
821109313Sobrien{
822109313Sobrien	u_int64_t offset;
823109313Sobrien	u_int64_t entsize;
824109313Sobrien	u_int64_t size;
825109313Sobrien	u_int64_t name;
826109313Sobrien	u_int64_t info;
827109313Sobrien	void *r;
828109313Sobrien	void *v;
829109313Sobrien	int i;
830109313Sobrien
831109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
832109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
833109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
834109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
835110256Sobrien	v = (char *)e + offset;
836109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
837110256Sobrien	for (i = 0; (u_int64_t)i < size / entsize; i++) {
838110256Sobrien		r = (char *)v + i * entsize;
839109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
840109313Sobrien		info = elf_get_word(e, r, R_INFO);
841109313Sobrien		fprintf(out, "\n");
842109313Sobrien		fprintf(out, "entry: %d\n", i);
843110257Sobrien		fprintf(out, "\tr_offset: %#jx\n", offset);
844110257Sobrien		fprintf(out, "\tr_info: %jd\n", (intmax_t)info);
845109313Sobrien	}
846109313Sobrien}
847109313Sobrien
848109313Sobrienvoid
849110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p)
850109313Sobrien{
851109313Sobrien	u_int64_t offset;
852109313Sobrien	char *s;
853109313Sobrien
854109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
855110252Sobrien	s = (char *)e + offset;
856109313Sobrien	fprintf(out, "\ninterp:\n");
857109313Sobrien	fprintf(out, "\t%s\n", s);
858109313Sobrien}
859109313Sobrien
860109313Sobrienvoid
861110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh)
862109313Sobrien{
863109313Sobrien	u_int64_t offset;
864109313Sobrien	u_int64_t addralign;
865109313Sobrien	u_int64_t size;
866109313Sobrien	u_int64_t addr;
867109313Sobrien	void *v;
868109313Sobrien	int i;
869109313Sobrien
870109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
871109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
872109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
873110256Sobrien	v = (char *)e + offset;
874109313Sobrien	fprintf(out, "\nglobal offset table:\n");
875110256Sobrien	for (i = 0; (u_int64_t)i < size / addralign; i++) {
876110256Sobrien		addr = elf_get_addr(e, (char *)v + i * addralign, 0);
877109313Sobrien		fprintf(out, "\n");
878109313Sobrien		fprintf(out, "entry: %d\n", i);
879110257Sobrien		fprintf(out, "\t%#jx\n", addr);
880109313Sobrien	}
881109313Sobrien}
882109313Sobrien
883109313Sobrienvoid
884110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused)
885109313Sobrien{
886109313Sobrien}
887109313Sobrien
888109313Sobrienvoid
889110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh)
890109313Sobrien{
891109313Sobrien	u_int64_t offset;
892109313Sobrien	u_int64_t size;
893109313Sobrien	u_int64_t name;
894109313Sobrien	u_int32_t namesz;
895109313Sobrien	u_int32_t descsz;
896109313Sobrien	u_int32_t type;
897109313Sobrien	u_int32_t desc;
898110256Sobrien	char *n, *s;
899109313Sobrien
900109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
901109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
902109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
903110256Sobrien	n = (char *)e + offset;
904109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
905110256Sobrien 	while (n < ((char *)e + offset + size)) {
906109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
907109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
908109313Sobrien		type = elf_get_word(e, n, N_TYPE);
909110256Sobrien 		s = n + sizeof(Elf_Note);
910110256Sobrien 		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
911109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
912109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
913109313Sobrien	}
914109313Sobrien}
915109313Sobrien
916109313Sobrienu_int64_t
917109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
918109313Sobrien{
919109313Sobrien	u_int64_t val;
920109313Sobrien	u_char *p;
921109313Sobrien
922109313Sobrien	val = 0;
923109313Sobrien	switch (e->e_ident[EI_CLASS]) {
924109313Sobrien	case ELFCLASS32:
925110256Sobrien		p = (char *)base + elf32_offsets[member];
926109313Sobrien		val = *p;
927109313Sobrien		break;
928109313Sobrien	case ELFCLASS64:
929110256Sobrien		p = (char *)base + elf64_offsets[member];
930109313Sobrien		val = *p;
931109313Sobrien		break;
932109313Sobrien	case ELFCLASSNONE:
933109313Sobrien		errx(1, "invalid class");
934109313Sobrien	}
935109313Sobrien
936109313Sobrien	return val;
937109313Sobrien}
938109313Sobrien
939109313Sobrienu_int64_t
940109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
941109313Sobrien{
942109313Sobrien	u_int64_t val;
943109313Sobrien	u_char *p;
944109313Sobrien
945109313Sobrien	val = 0;
946109313Sobrien	switch (e->e_ident[EI_CLASS]) {
947109313Sobrien	case ELFCLASS32:
948110256Sobrien		p = (char *)base + elf32_offsets[member];
949109313Sobrien		switch (e->e_ident[EI_DATA]) {
950109313Sobrien		case ELFDATA2MSB:
951109313Sobrien			val = p[0] << 8 | p[1];
952109313Sobrien			break;
953109313Sobrien		case ELFDATA2LSB:
954109313Sobrien			val = p[1] << 8 | p[0];
955109313Sobrien			break;
956109313Sobrien		case ELFDATANONE:
957109313Sobrien			errx(1, "invalid data format");
958109313Sobrien		}
959109313Sobrien		break;
960109313Sobrien	case ELFCLASS64:
961110256Sobrien		p = (char *)base + elf64_offsets[member];
962109313Sobrien		switch (e->e_ident[EI_DATA]) {
963109313Sobrien		case ELFDATA2MSB:
964109313Sobrien			val = p[0] << 8 | p[1];
965109313Sobrien			break;
966109313Sobrien		case ELFDATA2LSB:
967109313Sobrien			val = p[1] << 8 | p[0];
968109313Sobrien			break;
969109313Sobrien		case ELFDATANONE:
970109313Sobrien			errx(1, "invalid data format");
971109313Sobrien		}
972109313Sobrien		break;
973109313Sobrien	case ELFCLASSNONE:
974109313Sobrien		errx(1, "invalid class");
975109313Sobrien	}
976109313Sobrien
977109313Sobrien	return val;
978109313Sobrien}
979109313Sobrien
980109313Sobrienu_int64_t
981109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
982109313Sobrien{
983109313Sobrien	u_int64_t val;
984109313Sobrien	u_char *p;
985109313Sobrien
986109313Sobrien	val = 0;
987109313Sobrien	switch (e->e_ident[EI_CLASS]) {
988109313Sobrien	case ELFCLASS32:
989110256Sobrien		p = (char *)base + elf32_offsets[member];
990109313Sobrien		switch (e->e_ident[EI_DATA]) {
991109313Sobrien		case ELFDATA2MSB:
992109313Sobrien			val = p[0] << 8 | p[1];
993109313Sobrien			break;
994109313Sobrien		case ELFDATA2LSB:
995109313Sobrien			val = p[1] << 8 | p[0];
996109313Sobrien			break;
997109313Sobrien		case ELFDATANONE:
998109313Sobrien			errx(1, "invalid data format");
999109313Sobrien		}
1000109313Sobrien		break;
1001109313Sobrien	case ELFCLASS64:
1002110256Sobrien		p = (char *)base + elf64_offsets[member];
1003109313Sobrien		switch (e->e_ident[EI_DATA]) {
1004109313Sobrien		case ELFDATA2MSB:
1005109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1006109313Sobrien			break;
1007109313Sobrien		case ELFDATA2LSB:
1008109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1009109313Sobrien			break;
1010109313Sobrien		case ELFDATANONE:
1011109313Sobrien			errx(1, "invalid data format");
1012109313Sobrien		}
1013109313Sobrien		break;
1014109313Sobrien	case ELFCLASSNONE:
1015109313Sobrien		errx(1, "invalid class");
1016109313Sobrien	}
1017109313Sobrien
1018109313Sobrien	return val;
1019109313Sobrien}
1020109313Sobrien
1021109313Sobrienu_int64_t
1022109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1023109313Sobrien{
1024109313Sobrien	u_int64_t val;
1025109313Sobrien	u_char *p;
1026109313Sobrien
1027109313Sobrien	val = 0;
1028109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1029109313Sobrien	case ELFCLASS32:
1030110256Sobrien		p = (char *)base + elf32_offsets[member];
1031109313Sobrien		switch (e->e_ident[EI_DATA]) {
1032109313Sobrien		case ELFDATA2MSB:
1033109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1034109313Sobrien			break;
1035109313Sobrien		case ELFDATA2LSB:
1036109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1037109313Sobrien			break;
1038109313Sobrien		case ELFDATANONE:
1039109313Sobrien			errx(1, "invalid data format");
1040109313Sobrien		}
1041109313Sobrien		break;
1042109313Sobrien	case ELFCLASS64:
1043110256Sobrien		p = (char *)base + elf64_offsets[member];
1044109313Sobrien		switch (e->e_ident[EI_DATA]) {
1045109313Sobrien		case ELFDATA2MSB:
1046109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1047109313Sobrien			break;
1048109313Sobrien		case ELFDATA2LSB:
1049109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1050109313Sobrien			break;
1051109313Sobrien		case ELFDATANONE:
1052109313Sobrien			errx(1, "invalid data format");
1053109313Sobrien		}
1054109313Sobrien		break;
1055109313Sobrien	case ELFCLASSNONE:
1056109313Sobrien		errx(1, "invalid class");
1057109313Sobrien	}
1058109313Sobrien
1059109313Sobrien	return val;
1060109313Sobrien}
1061109313Sobrien
1062109313Sobrienu_int64_t
1063109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1064109313Sobrien{
1065109313Sobrien	u_int64_t high;
1066109313Sobrien	u_int64_t low;
1067109313Sobrien	u_int64_t val;
1068109313Sobrien	u_char *p;
1069109313Sobrien
1070109313Sobrien	val = 0;
1071109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1072109313Sobrien	case ELFCLASS32:
1073110256Sobrien		p = (char *)base + elf32_offsets[member];
1074109313Sobrien		switch (e->e_ident[EI_DATA]) {
1075109313Sobrien		case ELFDATA2MSB:
1076109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1077109313Sobrien			break;
1078109313Sobrien		case ELFDATA2LSB:
1079109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1080109313Sobrien			break;
1081109313Sobrien		case ELFDATANONE:
1082109313Sobrien			errx(1, "invalid data format");
1083109313Sobrien		}
1084109313Sobrien		break;
1085109313Sobrien	case ELFCLASS64:
1086110256Sobrien		p = (char *)base + elf64_offsets[member];
1087109313Sobrien		switch (e->e_ident[EI_DATA]) {
1088109313Sobrien		case ELFDATA2MSB:
1089109313Sobrien			high = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1090109313Sobrien			low = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
1091109313Sobrien			val = high << 32 | low;
1092109313Sobrien			break;
1093109313Sobrien		case ELFDATA2LSB:
1094109313Sobrien			high = p[7] << 24 | p[6] << 16 | p[5] << 8 | p[4];
1095109313Sobrien			low = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1096109313Sobrien			val = high << 32 | low;
1097109313Sobrien			break;
1098109313Sobrien		case ELFDATANONE:
1099109313Sobrien			errx(1, "invalid data format");
1100109313Sobrien		}
1101109313Sobrien		break;
1102109313Sobrien	case ELFCLASSNONE:
1103109313Sobrien		errx(1, "invalid class");
1104109313Sobrien	}
1105109313Sobrien
1106109313Sobrien	return val;
1107109313Sobrien}
1108109313Sobrien
1109109313Sobrienvoid
1110109313Sobrienusage(void)
1111109313Sobrien{
1112109313Sobrien	fprintf(stderr, "usage: elfdump [-acdeiGhnprs] [-w file] filename\n");
1113109313Sobrien	exit(1);
1114109313Sobrien}
1115