elfdump.c revision 109332
1109313Sobrien/*-
2109313Sobrien * Copyright (c) 2001 Jake Burkholder
3109313Sobrien * All rights reserved.
4109313Sobrien *
5109313Sobrien * Redistribution and use in source and binary forms, with or without
6109313Sobrien * modification, are permitted provided that the following conditions
7109313Sobrien * are met:
8109313Sobrien * 1. Redistributions of source code must retain the above copyright
9109313Sobrien *    notice, this list of conditions and the following disclaimer.
10109313Sobrien * 2. Redistributions in binary form must reproduce the above copyright
11109313Sobrien *    notice, this list of conditions and the following disclaimer in the
12109313Sobrien *    documentation and/or other materials provided with the distribution.
13109313Sobrien *
14109313Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15109313Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16109313Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17109313Sobrien * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18109313Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19109313Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20109313Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21109313Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22109313Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23109313Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24109313Sobrien * SUCH DAMAGE.
25109313Sobrien */
26109313Sobrien
27109313Sobrien#include <sys/cdefs.h>
28109313Sobrien__FBSDID("$FreeBSD: head/usr.bin/elfdump/elfdump.c 109332 2003-01-15 21:24:05Z obrien $");
29109313Sobrien
30109313Sobrien#include <sys/types.h>
31109313Sobrien#include <sys/elf32.h>
32109313Sobrien#include <sys/elf64.h>
33109313Sobrien#include <sys/mman.h>
34109313Sobrien#include <sys/stat.h>
35109313Sobrien#include <err.h>
36109313Sobrien#include <fcntl.h>
37109313Sobrien#include <stddef.h>
38109313Sobrien#include <stdio.h>
39109313Sobrien#include <stdlib.h>
40109313Sobrien#include <string.h>
41109313Sobrien#include <unistd.h>
42109313Sobrien
43109313Sobrien#define	ED_DYN		(1<<0)
44109313Sobrien#define	ED_EHDR		(1<<1)
45109313Sobrien#define	ED_GOT		(1<<2)
46109313Sobrien#define	ED_HASH		(1<<3)
47109313Sobrien#define	ED_INTERP	(1<<4)
48109313Sobrien#define	ED_NOTE		(1<<5)
49109313Sobrien#define	ED_PHDR		(1<<6)
50109313Sobrien#define	ED_REL		(1<<7)
51109313Sobrien#define	ED_SHDR		(1<<8)
52109313Sobrien#define	ED_SYMTAB	(1<<9)
53109313Sobrien#define	ED_ALL		((1<<10)-1)
54109313Sobrien
55109313Sobrien#define	elf_get_addr	elf_get_quad
56109313Sobrien#define	elf_get_off	elf_get_quad
57109313Sobrien#define	elf_get_size	elf_get_quad
58109313Sobrien
59109313Sobrienenum elf_member {
60109313Sobrien	D_TAG = 1, D_PTR, D_VAL,
61109313Sobrien
62109313Sobrien	E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY,
63109313Sobrien	E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE,
64109313Sobrien	E_SHNUM, E_SHSTRNDX,
65109313Sobrien
66109313Sobrien	N_NAMESZ, N_DESCSZ, N_TYPE,
67109313Sobrien
68109313Sobrien	P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS,
69109313Sobrien	P_ALIGN,
70109313Sobrien
71109313Sobrien	SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK,
72109313Sobrien	SH_INFO, SH_ADDRALIGN, SH_ENTSIZE,
73109313Sobrien
74109313Sobrien	ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX,
75109313Sobrien
76109313Sobrien	R_OFFSET, R_INFO,
77109313Sobrien
78109313Sobrien	RA_OFFSET, RA_INFO, RA_ADDEND
79109313Sobrien};
80109313Sobrien
81109313Sobrientypedef enum elf_member elf_member_t;
82109313Sobrien
83109313Sobrienint elf32_offsets[] = {
84109313Sobrien	0,
85109313Sobrien
86109313Sobrien	offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr),
87109313Sobrien	offsetof(Elf32_Dyn, d_un.d_val),
88109313Sobrien
89109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
90109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
91109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
92109313Sobrien	offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine),
93109313Sobrien	offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry),
94109313Sobrien	offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff),
95109313Sobrien	offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize),
96109313Sobrien	offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum),
97109313Sobrien	offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum),
98109313Sobrien	offsetof(Elf32_Ehdr, e_shstrndx),
99109313Sobrien
100109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
101109313Sobrien	offsetof(Elf_Note, n_type),
102109313Sobrien
103109313Sobrien	offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset),
104109313Sobrien	offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr),
105109313Sobrien	offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz),
106109313Sobrien	offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align),
107109313Sobrien
108109313Sobrien	offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type),
109109313Sobrien	offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr),
110109313Sobrien	offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size),
111109313Sobrien	offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info),
112109313Sobrien	offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize),
113109313Sobrien
114109313Sobrien	offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value),
115109313Sobrien	offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info),
116109313Sobrien	offsetof(Elf32_Sym, st_shndx),
117109313Sobrien
118109313Sobrien	offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info),
119109313Sobrien
120109313Sobrien	offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info),
121109313Sobrien	offsetof(Elf32_Rela, r_addend)
122109313Sobrien};
123109313Sobrien
124109313Sobrienint elf64_offsets[] = {
125109313Sobrien	0,
126109313Sobrien
127109313Sobrien	offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr),
128109313Sobrien	offsetof(Elf64_Dyn, d_un.d_val),
129109313Sobrien
130109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_CLASS]),
131109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_DATA]),
132109313Sobrien	offsetof(Elf32_Ehdr, e_ident[EI_OSABI]),
133109313Sobrien	offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine),
134109313Sobrien	offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry),
135109313Sobrien	offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff),
136109313Sobrien	offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize),
137109313Sobrien	offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum),
138109313Sobrien	offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum),
139109313Sobrien	offsetof(Elf64_Ehdr, e_shstrndx),
140109313Sobrien
141109313Sobrien	offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz),
142109313Sobrien	offsetof(Elf_Note, n_type),
143109313Sobrien
144109313Sobrien	offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset),
145109313Sobrien	offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr),
146109313Sobrien	offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz),
147109313Sobrien	offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align),
148109313Sobrien
149109313Sobrien	offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type),
150109313Sobrien	offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr),
151109313Sobrien	offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size),
152109313Sobrien	offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info),
153109313Sobrien	offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize),
154109313Sobrien
155109313Sobrien	offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value),
156109313Sobrien	offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info),
157109313Sobrien	offsetof(Elf64_Sym, st_shndx),
158109313Sobrien
159109313Sobrien	offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info),
160109313Sobrien
161109313Sobrien	offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info),
162109313Sobrien	offsetof(Elf64_Rela, r_addend)
163109313Sobrien};
164109313Sobrien
165109332Sobrien/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */
166109332Sobrienconst char *
167109332Sobriend_tags(u_int64_t tag) {
168109332Sobrien	switch (tag) {
169109332Sobrien	case 0: return "DT_NULL";
170109332Sobrien	case 1: return "DT_NEEDED";
171109332Sobrien	case 2: return "DT_PLTRELSZ";
172109332Sobrien	case 3: return "DT_PLTGOT";
173109332Sobrien	case 4: return "DT_HASH";
174109332Sobrien	case 5: return "DT_STRTAB";
175109332Sobrien	case 6: return "DT_SYMTAB";
176109332Sobrien	case 7: return "DT_RELA";
177109332Sobrien	case 8: return "DT_RELASZ";
178109332Sobrien	case 9: return "DT_RELAENT";
179109332Sobrien	case 10: return "DT_STRSZ";
180109332Sobrien	case 11: return "DT_SYMENT";
181109332Sobrien	case 12: return "DT_INIT";
182109332Sobrien	case 13: return "DT_FINI";
183109332Sobrien	case 14: return "DT_SONAME";
184109332Sobrien	case 15: return "DT_RPATH";
185109332Sobrien	case 16: return "DT_SYMBOLIC";
186109332Sobrien	case 17: return "DT_REL";
187109332Sobrien	case 18: return "DT_RELSZ";
188109332Sobrien	case 19: return "DT_RELENT";
189109332Sobrien	case 20: return "DT_PLTREL";
190109332Sobrien	case 21: return "DT_DEBUG";
191109332Sobrien	case 22: return "DT_TEXTREL";
192109332Sobrien	case 23: return "DT_JMPREL";
193109332Sobrien	case 24: return "DT_BIND_NOW";
194109332Sobrien	case 25: return "DT_INIT_ARRAY";
195109332Sobrien	case 26: return "DT_FINI_ARRAY";
196109332Sobrien	case 27: return "DT_INIT_ARRAYSZ";
197109332Sobrien	case 28: return "DT_FINI_ARRAYSZ";
198109332Sobrien	case 29: return "DT_RUNPATH";
199109332Sobrien	case 30: return "DT_FLAGS";
200109332Sobrien	case 32: return "DT_PREINIT_ARRAY"; /* XXX: DT_ENCODING */
201109332Sobrien	case 33: return "DT_PREINIT_ARRAYSZ";
202109332Sobrien	/* 0x6000000D - 0x6ffff000 operating system-specific semantics */
203109332Sobrien	case 0x6ffffdf5: return "DT_GNU_PRELINKED";
204109332Sobrien	case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ";
205109332Sobrien	case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ";
206109332Sobrien	case 0x6ffffdf8: return "DT_SUNW_CHECKSUM";
207109332Sobrien	case 0x6ffffdf9: return "DT_PLTPADSZ";
208109332Sobrien	case 0x6ffffdfa: return "DT_MOVEENT";
209109332Sobrien	case 0x6ffffdfb: return "DT_MOVESZ";
210109332Sobrien	case 0x6ffffdfc: return "DT_FEATURE";
211109332Sobrien	case 0x6ffffdfd: return "DT_POSFLAG_1";
212109332Sobrien	case 0x6ffffdfe: return "DT_SYMINSZ";
213109332Sobrien	case 0x6ffffdff: return "DT_SYMINENT (DT_VALRNGHI)";
214109332Sobrien	case 0x6ffffe00: return "DT_ADDRRNGLO";
215109332Sobrien	case 0x6ffffef8: return "DT_GNU_CONFLICT";
216109332Sobrien	case 0x6ffffef9: return "DT_GNU_LIBLIST";
217109332Sobrien	case 0x6ffffefa: return "DT_SUNW_CONFIG";
218109332Sobrien	case 0x6ffffefb: return "DT_SUNW_DEPAUDIT";
219109332Sobrien	case 0x6ffffefc: return "DT_SUNW_AUDIT";
220109332Sobrien	case 0x6ffffefd: return "DT_SUNW_PLTPAD";
221109332Sobrien	case 0x6ffffefe: return "DT_SUNW_MOVETAB";
222109332Sobrien	case 0x6ffffeff: return "DT_SYMINFO (DT_ADDRRNGHI)";
223109332Sobrien	case 0x6ffffff9: return "DT_RELACOUNT";
224109332Sobrien	case 0x6ffffffa: return "DT_RELCOUNT";
225109332Sobrien	case 0x6ffffffb: return "DT_FLAGS_1";
226109332Sobrien	case 0x6ffffffc: return "DT_VERDEF";
227109332Sobrien	case 0x6ffffffd: return "DT_VERDEFNUM";
228109332Sobrien	case 0x6ffffffe: return "DT_VERNEED";
229109332Sobrien	case 0x6fffffff: return "DT_VERNEEDNUM";
230109332Sobrien	case 0x6ffffff0: return "DT_GNU_VERSYM";
231109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
232109332Sobrien	case 0x7ffffffd: return "DT_SUNW_AUXILIARY";
233109332Sobrien	case 0x7ffffffe: return "DT_SUNW_USED";
234109332Sobrien	case 0x7fffffff: return "DT_SUNW_FILTER";
235109332Sobrien	default: return "ERROR: TAG NOT DEFINED";
236109332Sobrien	}
237109313Sobrien};
238109313Sobrien
239109313Sobrienchar *e_machines[] = {
240109313Sobrien	"EM_NONE", "EM_M32", "EM_SPARC", "EM_386", "EM_68K", "EM_88K",
241109313Sobrien	"EM_486", "EM_860", "EM_MIPS"
242109313Sobrien};
243109313Sobrien
244109313Sobrienchar *e_types[] = {
245109313Sobrien	"ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE"
246109313Sobrien};
247109313Sobrien
248109313Sobrienchar *ei_versions[] = {
249109313Sobrien	"EV_NONE", "EV_CURRENT"
250109313Sobrien};
251109313Sobrien
252109313Sobrienchar *ei_classes[] = {
253109313Sobrien	"ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64"
254109313Sobrien};
255109313Sobrien
256109313Sobrienchar *ei_data[] = {
257109313Sobrien	"ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB"
258109313Sobrien};
259109313Sobrien
260109313Sobrienchar *ei_abis[] = {
261109313Sobrien	"ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX",
262109313Sobrien	"ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS",
263109313Sobrien	"ELFOSABI_MONTEREY", "ELFOSABI_IRIX", "ELFOSABI_FREEBSD",
264109313Sobrien	"ELFOSABI_TRU64", "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD"
265109313Sobrien};
266109313Sobrien
267109313Sobrienchar *p_types[] = {
268109313Sobrien	"PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE",
269109313Sobrien	"PT_SHLIB", "PT_PHDR"
270109313Sobrien};
271109313Sobrien
272109313Sobrienchar *p_flags[] = {
273109313Sobrien	"", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R",
274109313Sobrien	"PF_X|PF_W|PF_R"
275109313Sobrien};
276109313Sobrien
277109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */
278109332Sobrienconst char *
279109332Sobriensh_types(u_int64_t sht) {
280109329Sobrien	switch (sht) {
281109329Sobrien	case 0:	return "SHT_NULL";
282109329Sobrien	case 1: return "SHT_PROGBITS";
283109329Sobrien	case 2: return "SHT_SYMTAB";
284109329Sobrien	case 3: return "SHT_STRTAB";
285109329Sobrien	case 4: return "SHT_RELA";
286109329Sobrien	case 5: return "SHT_HASH";
287109329Sobrien	case 6: return "SHT_DYNAMIC";
288109329Sobrien	case 7: return "SHT_NOTE";
289109329Sobrien	case 8: return "SHT_NOBITS";
290109329Sobrien	case 9: return "SHT_REL";
291109329Sobrien	case 10: return "SHT_SHLIB";
292109329Sobrien	case 11: return "SHT_DYNSYM";
293109329Sobrien	case 14: return "SHT_INIT_ARRAY";
294109329Sobrien	case 15: return "SHT_FINI_ARRAY";
295109329Sobrien	case 16: return "SHT_PREINIT_ARRAY";
296109329Sobrien	case 17: return "SHT_GROUP";
297109329Sobrien	case 18: return "SHT_SYMTAB_SHNDX";
298109332Sobrien	/* 0x60000000 - 0x6fffffff operating system-specific semantics */
299109329Sobrien	case 0x6ffffff0: return "XXX:VERSYM";
300109329Sobrien	case 0x6ffffff7: return "SHT_GNU_LIBLIST";
301109329Sobrien	case 0x6ffffffc: return "XXX:VERDEF";
302109329Sobrien	case 0x6ffffffd: return "SHT_SUNW(GNU)_verdef";
303109329Sobrien	case 0x6ffffffe: return "SHT_SUNW(GNU)_verneed";
304109329Sobrien	case 0x6fffffff: return "SHT_SUNW(GNU)_versym";
305109332Sobrien	/* 0x70000000 - 0x7fffffff processor-specific semantics */
306109329Sobrien	case 0x7ffffffd: return "XXX:AUXILIARY";
307109329Sobrien	case 0x7fffffff: return "XXX:FILTER";
308109332Sobrien	/* 0x80000000 - 0xffffffff application programs */
309109329Sobrien	default: return "ERROR: SHT NOT DEFINED";
310109329Sobrien	}
311109313Sobrien};
312109313Sobrien
313109313Sobrienchar *sh_flags[] = {
314109313Sobrien	"", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR",
315109313Sobrien	"SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR",
316109313Sobrien	"SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR"
317109313Sobrien};
318109313Sobrien
319109313Sobrienchar *st_types[] = {
320109313Sobrien	"STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE"
321109313Sobrien};
322109313Sobrien
323109313Sobrienchar *st_bindings[] = {
324109313Sobrien	"STB_LOCAL", "STB_GLOBAL", "STB_WEAK"
325109313Sobrien};
326109313Sobrien
327109313Sobrienchar *dynstr;
328109313Sobrienchar *shstrtab;
329109313Sobrienchar *strtab;
330109313SobrienFILE *out;
331109313Sobrien
332109313Sobrienu_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member);
333109313Sobrienu_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member);
334109313Sobrienu_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member);
335109313Sobrienu_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member);
336109313Sobrienu_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member);
337109313Sobrien
338109313Sobrienvoid elf_print_ehdr(void *e);
339109313Sobrienvoid elf_print_phdr(void *e, void *p);
340109313Sobrienvoid elf_print_shdr(void *e, void *sh);
341109313Sobrienvoid elf_print_symtab(void *e, void *sh, char *str);
342109313Sobrienvoid elf_print_dynamic(void *e, void *sh);
343109313Sobrienvoid elf_print_rel(void *e, void *r);
344109313Sobrienvoid elf_print_rela(void *e, void *ra);
345109313Sobrienvoid elf_print_interp(void *e, void *p);
346109313Sobrienvoid elf_print_got(void *e, void *sh);
347109313Sobrienvoid elf_print_hash(void *e, void *sh);
348109313Sobrienvoid elf_print_note(void *e, void *sh);
349109313Sobrien
350109313Sobrienvoid usage(void);
351109313Sobrien
352109313Sobrienint
353109313Sobrienmain(int ac, char **av)
354109313Sobrien{
355109313Sobrien	u_int64_t phoff;
356109313Sobrien	u_int64_t shoff;
357109313Sobrien	u_int64_t phentsize;
358109313Sobrien	u_int64_t phnum;
359109313Sobrien	u_int64_t shentsize;
360109313Sobrien	u_int64_t shnum;
361109313Sobrien	u_int64_t shstrndx;
362109313Sobrien	u_int64_t offset;
363109313Sobrien	u_int64_t name;
364109313Sobrien	u_int64_t type;
365109313Sobrien	struct stat sb;
366109313Sobrien	u_int flags;
367109313Sobrien	void *e;
368109313Sobrien	void *p;
369109313Sobrien	void *sh;
370109313Sobrien	void *v;
371109313Sobrien	int fd;
372109313Sobrien	int ch;
373109313Sobrien	int i;
374109313Sobrien
375109313Sobrien	out = stdout;
376109313Sobrien	flags = 0;
377109313Sobrien	while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1)
378109313Sobrien		switch (ch) {
379109313Sobrien		case 'a':
380109313Sobrien			flags = ED_ALL;
381109313Sobrien			break;
382109313Sobrien		case 'c':
383109313Sobrien			flags |= ED_SHDR;
384109313Sobrien			break;
385109313Sobrien		case 'd':
386109313Sobrien			flags |= ED_DYN;
387109313Sobrien			break;
388109313Sobrien		case 'e':
389109313Sobrien			flags |= ED_EHDR;
390109313Sobrien			break;
391109313Sobrien		case 'i':
392109313Sobrien			flags |= ED_INTERP;
393109313Sobrien			break;
394109313Sobrien		case 'G':
395109313Sobrien			flags |= ED_GOT;
396109313Sobrien			break;
397109313Sobrien		case 'h':
398109313Sobrien			flags |= ED_HASH;
399109313Sobrien			break;
400109313Sobrien		case 'n':
401109313Sobrien			flags |= ED_NOTE;
402109313Sobrien			break;
403109313Sobrien		case 'p':
404109313Sobrien			flags |= ED_PHDR;
405109313Sobrien			break;
406109313Sobrien		case 'r':
407109313Sobrien			flags |= ED_REL;
408109313Sobrien			break;
409109313Sobrien		case 's':
410109313Sobrien			flags |= ED_SYMTAB;
411109313Sobrien			break;
412109313Sobrien		case 'w':
413109313Sobrien			if ((out = fopen(optarg, "w")) == NULL)
414109313Sobrien				err(1, "%s", optarg);
415109313Sobrien			break;
416109313Sobrien		case '?':
417109313Sobrien		default:
418109313Sobrien			usage();
419109313Sobrien		}
420109313Sobrien	ac -= optind;
421109313Sobrien	av += optind;
422109313Sobrien	if (ac == 0 || flags == 0)
423109313Sobrien		usage();
424109313Sobrien	if ((fd = open(*av, O_RDONLY)) < 0 ||
425109313Sobrien	    fstat(fd, &sb) < 0)
426109313Sobrien		err(1, NULL);
427109313Sobrien	e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0);
428109313Sobrien	if (e == MAP_FAILED)
429109313Sobrien		err(1, NULL);
430109313Sobrien	if (!IS_ELF(*(Elf32_Ehdr *)e))
431109313Sobrien		errx(1, "not an elf file");
432109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
433109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
434109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
435109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
436109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
437109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
438109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
439109313Sobrien	p = e + phoff;
440109313Sobrien	sh = e + shoff;
441109313Sobrien	offset = elf_get_off(e, sh + shstrndx * shentsize, SH_OFFSET);
442109313Sobrien	shstrtab = e + offset;
443109313Sobrien	for (i = 0; i < shnum; i++) {
444109313Sobrien		name = elf_get_word(e, sh + i * shentsize, SH_NAME);
445109313Sobrien		offset = elf_get_off(e, sh + i * shentsize, SH_OFFSET);
446109313Sobrien		if (strcmp(shstrtab + name, ".strtab") == 0)
447109313Sobrien			strtab = e + offset;
448109313Sobrien		if (strcmp(shstrtab + name, ".dynstr") == 0)
449109313Sobrien			dynstr = e + offset;
450109313Sobrien	}
451109313Sobrien	if (flags & ED_EHDR)
452109313Sobrien		elf_print_ehdr(e);
453109313Sobrien	if (flags & ED_PHDR)
454109313Sobrien		elf_print_phdr(e, p);
455109313Sobrien	if (flags & ED_SHDR)
456109313Sobrien		elf_print_shdr(e, sh);
457109313Sobrien	for (i = 0; i < phnum; i++) {
458109313Sobrien		v = p + i * phentsize;
459109313Sobrien		type = elf_get_word(e, v, P_TYPE);
460109313Sobrien		switch (type) {
461109313Sobrien		case PT_INTERP:
462109313Sobrien			if (flags & ED_INTERP)
463109313Sobrien				elf_print_interp(e, v);
464109313Sobrien			break;
465109313Sobrien		case PT_NULL:
466109313Sobrien		case PT_LOAD:
467109313Sobrien		case PT_DYNAMIC:
468109313Sobrien		case PT_NOTE:
469109313Sobrien		case PT_SHLIB:
470109313Sobrien		case PT_PHDR:
471109313Sobrien			break;
472109313Sobrien		}
473109313Sobrien	}
474109313Sobrien	for (i = 0; i < shnum; i++) {
475109313Sobrien		v = sh + i * shentsize;
476109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
477109313Sobrien		switch (type) {
478109313Sobrien		case SHT_SYMTAB:
479109313Sobrien			if (flags & ED_SYMTAB)
480109313Sobrien				elf_print_symtab(e, v, strtab);
481109313Sobrien			break;
482109313Sobrien		case SHT_DYNAMIC:
483109313Sobrien			if (flags & ED_DYN)
484109313Sobrien				elf_print_dynamic(e, v);
485109313Sobrien			break;
486109313Sobrien		case SHT_RELA:
487109313Sobrien			if (flags & ED_REL)
488109313Sobrien				elf_print_rela(e, v);
489109313Sobrien			break;
490109313Sobrien		case SHT_REL:
491109313Sobrien			if (flags & ED_REL)
492109313Sobrien				elf_print_rel(e, v);
493109313Sobrien			break;
494109313Sobrien		case SHT_NOTE:
495109313Sobrien			name = elf_get_word(e, v, SH_NAME);
496109313Sobrien			if (flags & ED_NOTE &&
497109313Sobrien			    strcmp(shstrtab + name, ".note.ABI-tag") == 0)
498109313Sobrien				elf_print_note(e, v);
499109313Sobrien			break;
500109313Sobrien		case SHT_DYNSYM:
501109313Sobrien			if (flags & ED_SYMTAB)
502109313Sobrien				elf_print_symtab(e, v, dynstr);
503109313Sobrien			break;
504109313Sobrien		case SHT_PROGBITS:
505109313Sobrien			name = elf_get_word(e, v, SH_NAME);
506109313Sobrien			if (flags & ED_GOT &&
507109313Sobrien			    strcmp(shstrtab + name, ".got") == 0)
508109313Sobrien				elf_print_got(e, v);
509109313Sobrien			break;
510109313Sobrien		case SHT_HASH:
511109313Sobrien			if (flags & ED_HASH)
512109313Sobrien				elf_print_hash(e, v);
513109313Sobrien			break;
514109313Sobrien		case SHT_NULL:
515109313Sobrien		case SHT_STRTAB:
516109313Sobrien		case SHT_NOBITS:
517109313Sobrien		case SHT_SHLIB:
518109313Sobrien			break;
519109313Sobrien		}
520109313Sobrien	}
521109313Sobrien
522109313Sobrien	return 0;
523109313Sobrien}
524109313Sobrien
525109313Sobrienvoid
526109313Sobrienelf_print_ehdr(void *e)
527109313Sobrien{
528109313Sobrien	u_int64_t class;
529109313Sobrien	u_int64_t data;
530109313Sobrien	u_int64_t osabi;
531109313Sobrien	u_int64_t type;
532109313Sobrien	u_int64_t machine;
533109313Sobrien	u_int64_t version;
534109313Sobrien	u_int64_t entry;
535109313Sobrien	u_int64_t phoff;
536109313Sobrien	u_int64_t shoff;
537109313Sobrien	u_int64_t flags;
538109313Sobrien	u_int64_t ehsize;
539109313Sobrien	u_int64_t phentsize;
540109313Sobrien	u_int64_t phnum;
541109313Sobrien	u_int64_t shentsize;
542109313Sobrien	u_int64_t shnum;
543109313Sobrien	u_int64_t shstrndx;
544109313Sobrien
545109313Sobrien	class = elf_get_byte(e, e, E_CLASS);
546109313Sobrien	data = elf_get_byte(e, e, E_DATA);
547109313Sobrien	osabi = elf_get_byte(e, e, E_OSABI);
548109313Sobrien	type = elf_get_quarter(e, e, E_TYPE);
549109313Sobrien	machine = elf_get_quarter(e, e, E_MACHINE);
550109313Sobrien	version = elf_get_word(e, e, E_VERSION);
551109313Sobrien	entry = elf_get_addr(e, e, E_ENTRY);
552109313Sobrien	phoff = elf_get_off(e, e, E_PHOFF);
553109313Sobrien	shoff = elf_get_off(e, e, E_SHOFF);
554109313Sobrien	flags = elf_get_word(e, e, E_FLAGS);
555109313Sobrien	ehsize = elf_get_quarter(e, e, E_EHSIZE);
556109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
557109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
558109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
559109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
560109313Sobrien	shstrndx = elf_get_quarter(e, e, E_SHSTRNDX);
561109313Sobrien	fprintf(out, "\nelf header:\n");
562109313Sobrien	fprintf(out, "\n");
563109313Sobrien	fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data],
564109313Sobrien	    ei_abis[osabi]);
565109313Sobrien	fprintf(out, "\te_type: %s\n", e_types[type]);
566109313Sobrien	if (machine < sizeof e_machines / sizeof *e_machines)
567109313Sobrien		fprintf(out, "\te_machine: %s\n", e_machines[machine]);
568109313Sobrien	else
569109313Sobrien		fprintf(out, "\te_machine: %lld\n", machine);
570109313Sobrien	fprintf(out, "\te_version: %s\n", ei_versions[version]);
571109313Sobrien	fprintf(out, "\te_entry: %#llx\n", entry);
572109313Sobrien	fprintf(out, "\te_phoff: %lld\n", phoff);
573109313Sobrien	fprintf(out, "\te_shoff: %lld\n", shoff);
574109313Sobrien	fprintf(out, "\te_flags: %lld\n", flags);
575109313Sobrien	fprintf(out, "\te_ehsize: %lld\n", ehsize);
576109313Sobrien	fprintf(out, "\te_phentsize: %lld\n", phentsize);
577109313Sobrien	fprintf(out, "\te_phnum: %lld\n", phnum);
578109313Sobrien	fprintf(out, "\te_shentsize: %lld\n", shentsize);
579109313Sobrien	fprintf(out, "\te_shnum: %lld\n", shnum);
580109313Sobrien	fprintf(out, "\te_shstrndx: %lld\n", shstrndx);
581109313Sobrien}
582109313Sobrien
583109313Sobrienvoid
584109313Sobrienelf_print_phdr(void *e, void *p)
585109313Sobrien{
586109313Sobrien	u_int64_t phentsize;
587109313Sobrien	u_int64_t phnum;
588109313Sobrien	u_int64_t type;
589109313Sobrien	u_int64_t offset;
590109313Sobrien	u_int64_t vaddr;
591109313Sobrien	u_int64_t paddr;
592109313Sobrien	u_int64_t filesz;
593109313Sobrien	u_int64_t memsz;
594109313Sobrien	u_int64_t flags;
595109313Sobrien	u_int64_t align;
596109313Sobrien	void *v;
597109313Sobrien	int i;
598109313Sobrien
599109313Sobrien	phentsize = elf_get_quarter(e, e, E_PHENTSIZE);
600109313Sobrien	phnum = elf_get_quarter(e, e, E_PHNUM);
601109313Sobrien	fprintf(out, "\nprogram header:\n");
602109313Sobrien	for (i = 0; i < phnum; i++) {
603109313Sobrien		v = p + i * phentsize;
604109313Sobrien		type = elf_get_word(e, v, P_TYPE);
605109313Sobrien		offset = elf_get_off(e, v, P_OFFSET);
606109313Sobrien		vaddr = elf_get_addr(e, v, P_VADDR);
607109313Sobrien		paddr = elf_get_addr(e, v, P_PADDR);
608109313Sobrien		filesz = elf_get_size(e, v, P_FILESZ);
609109313Sobrien		memsz = elf_get_size(e, v, P_MEMSZ);
610109313Sobrien		flags = elf_get_word(e, v, P_FLAGS);
611109313Sobrien		align = elf_get_size(e, v, P_ALIGN);
612109313Sobrien		fprintf(out, "\n");
613109313Sobrien		fprintf(out, "entry: %d\n", i);
614109313Sobrien		fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]);
615109313Sobrien		fprintf(out, "\tp_offset: %lld\n", offset);
616109313Sobrien		fprintf(out, "\tp_vaddr: %#llx\n", vaddr);
617109313Sobrien		fprintf(out, "\tp_paddr: %#llx\n", paddr);
618109313Sobrien		fprintf(out, "\tp_filesz: %lld\n", filesz);
619109313Sobrien		fprintf(out, "\tp_memsz: %lld\n", memsz);
620109313Sobrien		fprintf(out, "\tp_flags: %s\n", p_flags[flags]);
621109313Sobrien		fprintf(out, "\tp_align: %lld\n", align);
622109313Sobrien	}
623109313Sobrien}
624109313Sobrien
625109313Sobrienvoid
626109313Sobrienelf_print_shdr(void *e, void *sh)
627109313Sobrien{
628109313Sobrien	u_int64_t shentsize;
629109313Sobrien	u_int64_t shnum;
630109313Sobrien	u_int64_t name;
631109313Sobrien	u_int64_t type;
632109313Sobrien	u_int64_t flags;
633109313Sobrien	u_int64_t addr;
634109313Sobrien	u_int64_t offset;
635109313Sobrien	u_int64_t size;
636109313Sobrien	u_int64_t link;
637109313Sobrien	u_int64_t info;
638109313Sobrien	u_int64_t addralign;
639109313Sobrien	u_int64_t entsize;
640109313Sobrien	void *v;
641109313Sobrien	int i;
642109313Sobrien
643109313Sobrien	shentsize = elf_get_quarter(e, e, E_SHENTSIZE);
644109313Sobrien	shnum = elf_get_quarter(e, e, E_SHNUM);
645109313Sobrien	fprintf(out, "\nsection header:\n");
646109313Sobrien	for (i = 0; i < shnum; i++) {
647109313Sobrien		v = sh + i * shentsize;
648109313Sobrien		name = elf_get_word(e, v, SH_NAME);
649109313Sobrien		type = elf_get_word(e, v, SH_TYPE);
650109313Sobrien		flags = elf_get_word(e, v, SH_FLAGS);
651109313Sobrien		addr = elf_get_addr(e, v, SH_ADDR);
652109313Sobrien		offset = elf_get_off(e, v, SH_OFFSET);
653109313Sobrien		size = elf_get_size(e, v, SH_SIZE);
654109313Sobrien		link = elf_get_word(e, v, SH_LINK);
655109313Sobrien		info = elf_get_word(e, v, SH_INFO);
656109313Sobrien		addralign = elf_get_size(e, v, SH_ADDRALIGN);
657109313Sobrien		entsize = elf_get_size(e, v, SH_ENTSIZE);
658109313Sobrien		fprintf(out, "\n");
659109313Sobrien		fprintf(out, "entry: %d\n", i);
660109313Sobrien		fprintf(out, "\tsh_name: %s\n", shstrtab + name);
661109329Sobrien		fprintf(out, "\tsh_type: %s\n", sh_types(type));
662109313Sobrien		fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]);
663109313Sobrien		fprintf(out, "\tsh_addr: %#llx\n", addr);
664109313Sobrien		fprintf(out, "\tsh_offset: %lld\n", offset);
665109313Sobrien		fprintf(out, "\tsh_size: %lld\n", size);
666109313Sobrien		fprintf(out, "\tsh_link: %lld\n", link);
667109313Sobrien		fprintf(out, "\tsh_info: %lld\n", info);
668109313Sobrien		fprintf(out, "\tsh_addralign: %lld\n", addralign);
669109313Sobrien		fprintf(out, "\tsh_entsize: %lld\n", entsize);
670109313Sobrien	}
671109313Sobrien}
672109313Sobrien
673109313Sobrienvoid
674109313Sobrienelf_print_symtab(void *e, void *sh, char *str)
675109313Sobrien{
676109313Sobrien	u_int64_t offset;
677109313Sobrien	u_int64_t entsize;
678109313Sobrien	u_int64_t size;
679109313Sobrien	u_int64_t name;
680109313Sobrien	u_int64_t value;
681109313Sobrien	u_int64_t info;
682109313Sobrien	u_int64_t shndx;
683109313Sobrien	void *st;
684109313Sobrien	int len;
685109313Sobrien	int i;
686109313Sobrien
687109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
688109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
689109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
690109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
691109313Sobrien	len = size / entsize;
692109313Sobrien	fprintf(out, "\nsymbol table (%s):\n", shstrtab + name);
693109313Sobrien	for (i = 0; i < len; i++) {
694109313Sobrien		st = e + offset + i * entsize;
695109313Sobrien		name = elf_get_word(e, st, ST_NAME);
696109313Sobrien		value = elf_get_addr(e, st, ST_VALUE);
697109313Sobrien		size = elf_get_size(e, st, ST_SIZE);
698109313Sobrien		info = elf_get_byte(e, st, ST_INFO);
699109313Sobrien		shndx = elf_get_quarter(e, st, ST_SHNDX);
700109313Sobrien		fprintf(out, "\n");
701109313Sobrien		fprintf(out, "entry: %d\n", i);
702109313Sobrien		fprintf(out, "\tst_name: %s\n", str + name);
703109313Sobrien		fprintf(out, "\tst_value: %#llx\n", value);
704109313Sobrien		fprintf(out, "\tst_size: %lld\n", size);
705109313Sobrien		fprintf(out, "\tst_info: %s %s\n",
706109313Sobrien		    st_types[ELF32_ST_TYPE(info)],
707109313Sobrien		    st_bindings[ELF32_ST_BIND(info)]);
708109313Sobrien		fprintf(out, "\tst_shndx: %lld\n", shndx);
709109313Sobrien	}
710109313Sobrien}
711109313Sobrien
712109313Sobrienvoid
713109313Sobrienelf_print_dynamic(void *e, void *sh)
714109313Sobrien{
715109313Sobrien	u_int64_t offset;
716109313Sobrien	u_int64_t entsize;
717109313Sobrien	u_int64_t size;
718109313Sobrien	int64_t tag;
719109313Sobrien	u_int64_t ptr;
720109313Sobrien	u_int64_t val;
721109313Sobrien	void *d;
722109313Sobrien	int i;
723109313Sobrien
724109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
725109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
726109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
727109313Sobrien	fprintf(out, "\ndynamic:\n");
728109313Sobrien	for (i = 0; i < size / entsize; i++) {
729109313Sobrien		d = e + offset + i * entsize;
730109313Sobrien		tag = elf_get_size(e, d, D_TAG);
731109313Sobrien		ptr = elf_get_size(e, d, D_PTR);
732109313Sobrien		val = elf_get_addr(e, d, D_VAL);
733109313Sobrien		fprintf(out, "\n");
734109313Sobrien		fprintf(out, "entry: %d\n", i);
735109332Sobrien		fprintf(out, "\td_tag: %s\n", d_tags(tag));
736109313Sobrien		switch (tag) {
737109313Sobrien		case DT_NEEDED:
738109313Sobrien		case DT_SONAME:
739109313Sobrien		case DT_RPATH:
740109313Sobrien			fprintf(out, "\td_val: %s\n", dynstr + val);
741109313Sobrien			break;
742109313Sobrien		case DT_PLTRELSZ:
743109313Sobrien		case DT_RELA:
744109313Sobrien		case DT_RELASZ:
745109313Sobrien		case DT_RELAENT:
746109313Sobrien		case DT_STRSZ:
747109313Sobrien		case DT_SYMENT:
748109313Sobrien		case DT_RELSZ:
749109313Sobrien		case DT_RELENT:
750109313Sobrien		case DT_PLTREL:
751109313Sobrien			fprintf(out, "\td_val: %lld\n", val);
752109313Sobrien			break;
753109313Sobrien		case DT_PLTGOT:
754109313Sobrien		case DT_HASH:
755109313Sobrien		case DT_STRTAB:
756109313Sobrien		case DT_SYMTAB:
757109313Sobrien		case DT_INIT:
758109313Sobrien		case DT_FINI:
759109313Sobrien		case DT_REL:
760109313Sobrien		case DT_JMPREL:
761109313Sobrien			fprintf(out, "\td_ptr: %#llx\n", ptr);
762109313Sobrien			break;
763109313Sobrien		case DT_NULL:
764109313Sobrien		case DT_SYMBOLIC:
765109313Sobrien		case DT_DEBUG:
766109313Sobrien		case DT_TEXTREL:
767109313Sobrien			break;
768109313Sobrien		}
769109313Sobrien	}
770109313Sobrien}
771109313Sobrien
772109313Sobrienvoid
773109313Sobrienelf_print_rela(void *e, void *sh)
774109313Sobrien{
775109313Sobrien	u_int64_t offset;
776109313Sobrien	u_int64_t entsize;
777109313Sobrien	u_int64_t size;
778109313Sobrien	u_int64_t name;
779109313Sobrien	u_int64_t info;
780109313Sobrien	int64_t addend;
781109313Sobrien	void *ra;
782109313Sobrien	void *v;
783109313Sobrien	int i;
784109313Sobrien
785109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
786109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
787109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
788109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
789109313Sobrien	v = e + offset;
790109313Sobrien	fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name);
791109313Sobrien	for (i = 0; i < size / entsize; i++) {
792109313Sobrien		ra = v + i * entsize;
793109313Sobrien		offset = elf_get_addr(e, ra, RA_OFFSET);
794109313Sobrien		info = elf_get_word(e, ra, RA_INFO);
795109313Sobrien		addend = elf_get_off(e, ra, RA_ADDEND);
796109313Sobrien		fprintf(out, "\n");
797109313Sobrien		fprintf(out, "entry: %d\n", i);
798109313Sobrien		fprintf(out, "\tr_offset: %#llx\n", offset);
799109313Sobrien		fprintf(out, "\tr_info: %lld\n", info);
800109313Sobrien		fprintf(out, "\tr_addend: %lld\n", addend);
801109313Sobrien	}
802109313Sobrien}
803109313Sobrien
804109313Sobrienvoid
805109313Sobrienelf_print_rel(void *e, void *sh)
806109313Sobrien{
807109313Sobrien	u_int64_t offset;
808109313Sobrien	u_int64_t entsize;
809109313Sobrien	u_int64_t size;
810109313Sobrien	u_int64_t name;
811109313Sobrien	u_int64_t info;
812109313Sobrien	void *r;
813109313Sobrien	void *v;
814109313Sobrien	int i;
815109313Sobrien
816109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
817109313Sobrien	entsize = elf_get_size(e, sh, SH_ENTSIZE);
818109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
819109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
820109313Sobrien	v = e + offset;
821109313Sobrien	fprintf(out, "\nrelocation (%s):\n", shstrtab + name);
822109313Sobrien	for (i = 0; i < size / entsize; i++) {
823109313Sobrien		r = v + i * entsize;
824109313Sobrien		offset = elf_get_addr(e, r, R_OFFSET);
825109313Sobrien		info = elf_get_word(e, r, R_INFO);
826109313Sobrien		fprintf(out, "\n");
827109313Sobrien		fprintf(out, "entry: %d\n", i);
828109313Sobrien		fprintf(out, "\tr_offset: %#llx\n", offset);
829109313Sobrien		fprintf(out, "\tr_info: %lld\n", info);
830109313Sobrien	}
831109313Sobrien}
832109313Sobrien
833109313Sobrienvoid
834109313Sobrienelf_print_interp(void *e, void *p)
835109313Sobrien{
836109313Sobrien	u_int64_t offset;
837109313Sobrien	char *s;
838109313Sobrien
839109313Sobrien	offset = elf_get_off(e, p, P_OFFSET);
840109313Sobrien	s = e + offset;
841109313Sobrien	fprintf(out, "\ninterp:\n");
842109313Sobrien	fprintf(out, "\t%s\n", s);
843109313Sobrien}
844109313Sobrien
845109313Sobrienvoid
846109313Sobrienelf_print_got(void *e, void *sh)
847109313Sobrien{
848109313Sobrien	u_int64_t offset;
849109313Sobrien	u_int64_t addralign;
850109313Sobrien	u_int64_t size;
851109313Sobrien	u_int64_t addr;
852109313Sobrien	void *v;
853109313Sobrien	int i;
854109313Sobrien
855109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
856109313Sobrien	addralign = elf_get_size(e, sh, SH_ADDRALIGN);
857109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
858109313Sobrien	v = e + offset;
859109313Sobrien	fprintf(out, "\nglobal offset table:\n");
860109313Sobrien	for (i = 0; i < size / addralign; i++) {
861109313Sobrien		addr = elf_get_addr(e, v + i * addralign, 0);
862109313Sobrien		fprintf(out, "\n");
863109313Sobrien		fprintf(out, "entry: %d\n", i);
864109313Sobrien		fprintf(out, "\t%#llx\n", addr);
865109313Sobrien	}
866109313Sobrien}
867109313Sobrien
868109313Sobrienvoid
869109313Sobrienelf_print_hash(void *e, void *sh)
870109313Sobrien{
871109313Sobrien}
872109313Sobrien
873109313Sobrienvoid
874109313Sobrienelf_print_note(void *e, void *sh)
875109313Sobrien{
876109313Sobrien	u_int64_t offset;
877109313Sobrien	u_int64_t size;
878109313Sobrien	u_int64_t name;
879109313Sobrien	u_int32_t namesz;
880109313Sobrien	u_int32_t descsz;
881109313Sobrien	u_int32_t type;
882109313Sobrien	u_int32_t desc;
883109313Sobrien	char *s;
884109313Sobrien	void *n;
885109313Sobrien
886109313Sobrien	offset = elf_get_off(e, sh, SH_OFFSET);
887109313Sobrien	size = elf_get_size(e, sh, SH_SIZE);
888109313Sobrien	name = elf_get_word(e, sh, SH_NAME);
889109313Sobrien	n = e + offset;
890109313Sobrien	fprintf(out, "\nnote (%s):\n", shstrtab + name);
891109313Sobrien	while (n < e + offset + size) {
892109313Sobrien		namesz = elf_get_word(e, n, N_NAMESZ);
893109313Sobrien		descsz = elf_get_word(e, n, N_DESCSZ);
894109313Sobrien		type = elf_get_word(e, n, N_TYPE);
895109313Sobrien		s = n + sizeof(Elf_Note);
896109313Sobrien		desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0);
897109313Sobrien		fprintf(out, "\t%s %d\n", s, desc);
898109313Sobrien		n += sizeof(Elf_Note) + namesz + descsz;
899109313Sobrien	}
900109313Sobrien}
901109313Sobrien
902109313Sobrienu_int64_t
903109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member)
904109313Sobrien{
905109313Sobrien	u_int64_t val;
906109313Sobrien	u_char *p;
907109313Sobrien
908109313Sobrien	val = 0;
909109313Sobrien	switch (e->e_ident[EI_CLASS]) {
910109313Sobrien	case ELFCLASS32:
911109313Sobrien		p = base + elf32_offsets[member];
912109313Sobrien		val = *p;
913109313Sobrien		break;
914109313Sobrien	case ELFCLASS64:
915109313Sobrien		p = base + elf64_offsets[member];
916109313Sobrien		val = *p;
917109313Sobrien		break;
918109313Sobrien	case ELFCLASSNONE:
919109313Sobrien		errx(1, "invalid class");
920109313Sobrien	}
921109313Sobrien
922109313Sobrien	return val;
923109313Sobrien}
924109313Sobrien
925109313Sobrienu_int64_t
926109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member)
927109313Sobrien{
928109313Sobrien	u_int64_t val;
929109313Sobrien	u_char *p;
930109313Sobrien
931109313Sobrien	val = 0;
932109313Sobrien	switch (e->e_ident[EI_CLASS]) {
933109313Sobrien	case ELFCLASS32:
934109313Sobrien		p = base + elf32_offsets[member];
935109313Sobrien		switch (e->e_ident[EI_DATA]) {
936109313Sobrien		case ELFDATA2MSB:
937109313Sobrien			val = p[0] << 8 | p[1];
938109313Sobrien			break;
939109313Sobrien		case ELFDATA2LSB:
940109313Sobrien			val = p[1] << 8 | p[0];
941109313Sobrien			break;
942109313Sobrien		case ELFDATANONE:
943109313Sobrien			errx(1, "invalid data format");
944109313Sobrien		}
945109313Sobrien		break;
946109313Sobrien	case ELFCLASS64:
947109313Sobrien		p = base + elf64_offsets[member];
948109313Sobrien		switch (e->e_ident[EI_DATA]) {
949109313Sobrien		case ELFDATA2MSB:
950109313Sobrien			val = p[0] << 8 | p[1];
951109313Sobrien			break;
952109313Sobrien		case ELFDATA2LSB:
953109313Sobrien			val = p[1] << 8 | p[0];
954109313Sobrien			break;
955109313Sobrien		case ELFDATANONE:
956109313Sobrien			errx(1, "invalid data format");
957109313Sobrien		}
958109313Sobrien		break;
959109313Sobrien	case ELFCLASSNONE:
960109313Sobrien		errx(1, "invalid class");
961109313Sobrien	}
962109313Sobrien
963109313Sobrien	return val;
964109313Sobrien}
965109313Sobrien
966109313Sobrienu_int64_t
967109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member)
968109313Sobrien{
969109313Sobrien	u_int64_t val;
970109313Sobrien	u_char *p;
971109313Sobrien
972109313Sobrien	val = 0;
973109313Sobrien	switch (e->e_ident[EI_CLASS]) {
974109313Sobrien	case ELFCLASS32:
975109313Sobrien		p = base + elf32_offsets[member];
976109313Sobrien		switch (e->e_ident[EI_DATA]) {
977109313Sobrien		case ELFDATA2MSB:
978109313Sobrien			val = p[0] << 8 | p[1];
979109313Sobrien			break;
980109313Sobrien		case ELFDATA2LSB:
981109313Sobrien			val = p[1] << 8 | p[0];
982109313Sobrien			break;
983109313Sobrien		case ELFDATANONE:
984109313Sobrien			errx(1, "invalid data format");
985109313Sobrien		}
986109313Sobrien		break;
987109313Sobrien	case ELFCLASS64:
988109313Sobrien		p = base + elf64_offsets[member];
989109313Sobrien		switch (e->e_ident[EI_DATA]) {
990109313Sobrien		case ELFDATA2MSB:
991109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
992109313Sobrien			break;
993109313Sobrien		case ELFDATA2LSB:
994109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
995109313Sobrien			break;
996109313Sobrien		case ELFDATANONE:
997109313Sobrien			errx(1, "invalid data format");
998109313Sobrien		}
999109313Sobrien		break;
1000109313Sobrien	case ELFCLASSNONE:
1001109313Sobrien		errx(1, "invalid class");
1002109313Sobrien	}
1003109313Sobrien
1004109313Sobrien	return val;
1005109313Sobrien}
1006109313Sobrien
1007109313Sobrienu_int64_t
1008109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member)
1009109313Sobrien{
1010109313Sobrien	u_int64_t val;
1011109313Sobrien	u_char *p;
1012109313Sobrien
1013109313Sobrien	val = 0;
1014109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1015109313Sobrien	case ELFCLASS32:
1016109313Sobrien		p = base + elf32_offsets[member];
1017109313Sobrien		switch (e->e_ident[EI_DATA]) {
1018109313Sobrien		case ELFDATA2MSB:
1019109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1020109313Sobrien			break;
1021109313Sobrien		case ELFDATA2LSB:
1022109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1023109313Sobrien			break;
1024109313Sobrien		case ELFDATANONE:
1025109313Sobrien			errx(1, "invalid data format");
1026109313Sobrien		}
1027109313Sobrien		break;
1028109313Sobrien	case ELFCLASS64:
1029109313Sobrien		p = base + elf64_offsets[member];
1030109313Sobrien		switch (e->e_ident[EI_DATA]) {
1031109313Sobrien		case ELFDATA2MSB:
1032109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1033109313Sobrien			break;
1034109313Sobrien		case ELFDATA2LSB:
1035109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1036109313Sobrien			break;
1037109313Sobrien		case ELFDATANONE:
1038109313Sobrien			errx(1, "invalid data format");
1039109313Sobrien		}
1040109313Sobrien		break;
1041109313Sobrien	case ELFCLASSNONE:
1042109313Sobrien		errx(1, "invalid class");
1043109313Sobrien	}
1044109313Sobrien
1045109313Sobrien	return val;
1046109313Sobrien}
1047109313Sobrien
1048109313Sobrienu_int64_t
1049109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member)
1050109313Sobrien{
1051109313Sobrien	u_int64_t high;
1052109313Sobrien	u_int64_t low;
1053109313Sobrien	u_int64_t val;
1054109313Sobrien	u_char *p;
1055109313Sobrien
1056109313Sobrien	val = 0;
1057109313Sobrien	switch (e->e_ident[EI_CLASS]) {
1058109313Sobrien	case ELFCLASS32:
1059109313Sobrien		p = base + elf32_offsets[member];
1060109313Sobrien		switch (e->e_ident[EI_DATA]) {
1061109313Sobrien		case ELFDATA2MSB:
1062109313Sobrien			val = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1063109313Sobrien			break;
1064109313Sobrien		case ELFDATA2LSB:
1065109313Sobrien			val = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1066109313Sobrien			break;
1067109313Sobrien		case ELFDATANONE:
1068109313Sobrien			errx(1, "invalid data format");
1069109313Sobrien		}
1070109313Sobrien		break;
1071109313Sobrien	case ELFCLASS64:
1072109313Sobrien		p = base + elf64_offsets[member];
1073109313Sobrien		switch (e->e_ident[EI_DATA]) {
1074109313Sobrien		case ELFDATA2MSB:
1075109313Sobrien			high = p[0] << 24 | p[1] << 16 | p[2] << 8 | p[3];
1076109313Sobrien			low = p[4] << 24 | p[5] << 16 | p[6] << 8 | p[7];
1077109313Sobrien			val = high << 32 | low;
1078109313Sobrien			break;
1079109313Sobrien		case ELFDATA2LSB:
1080109313Sobrien			high = p[7] << 24 | p[6] << 16 | p[5] << 8 | p[4];
1081109313Sobrien			low = p[3] << 24 | p[2] << 16 | p[1] << 8 | p[0];
1082109313Sobrien			val = high << 32 | low;
1083109313Sobrien			break;
1084109313Sobrien		case ELFDATANONE:
1085109313Sobrien			errx(1, "invalid data format");
1086109313Sobrien		}
1087109313Sobrien		break;
1088109313Sobrien	case ELFCLASSNONE:
1089109313Sobrien		errx(1, "invalid class");
1090109313Sobrien	}
1091109313Sobrien
1092109313Sobrien	return val;
1093109313Sobrien}
1094109313Sobrien
1095109313Sobrienvoid
1096109313Sobrienusage(void)
1097109313Sobrien{
1098109313Sobrien	fprintf(stderr, "usage: elfdump [-acdeiGhnprs] [-w file] filename\n");
1099109313Sobrien	exit(1);
1100109313Sobrien}
1101