1109313Sobrien/*- 2110252Sobrien * Copyright (c) 2003 David O'Brien. All rights reserved. 3109313Sobrien * Copyright (c) 2001 Jake Burkholder 4109313Sobrien * All rights reserved. 5109313Sobrien * 6109313Sobrien * Redistribution and use in source and binary forms, with or without 7109313Sobrien * modification, are permitted provided that the following conditions 8109313Sobrien * are met: 9109313Sobrien * 1. Redistributions of source code must retain the above copyright 10109313Sobrien * notice, this list of conditions and the following disclaimer. 11109313Sobrien * 2. Redistributions in binary form must reproduce the above copyright 12109313Sobrien * notice, this list of conditions and the following disclaimer in the 13109313Sobrien * documentation and/or other materials provided with the distribution. 14109313Sobrien * 15109313Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16109313Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17109313Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18109313Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19109313Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20109313Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21109313Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22109313Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23109313Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24109313Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25109313Sobrien * SUCH DAMAGE. 26109313Sobrien */ 27109313Sobrien 28109313Sobrien#include <sys/cdefs.h> 29109313Sobrien__FBSDID("$FreeBSD: stable/10/usr.bin/elfdump/elfdump.c 307834 2016-10-24 00:46:38Z emaste $"); 30109313Sobrien 31109313Sobrien#include <sys/types.h> 32275945Sbrueffer 33275945Sbrueffer#include <sys/capability.h> 34109313Sobrien#include <sys/elf32.h> 35109313Sobrien#include <sys/elf64.h> 36118680Smarcel#include <sys/endian.h> 37109313Sobrien#include <sys/mman.h> 38109313Sobrien#include <sys/stat.h> 39109313Sobrien#include <err.h> 40275945Sbrueffer#include <errno.h> 41109313Sobrien#include <fcntl.h> 42110257Sobrien#include <inttypes.h> 43109313Sobrien#include <stddef.h> 44109313Sobrien#include <stdio.h> 45109313Sobrien#include <stdlib.h> 46109313Sobrien#include <string.h> 47109313Sobrien#include <unistd.h> 48109313Sobrien 49109313Sobrien#define ED_DYN (1<<0) 50109313Sobrien#define ED_EHDR (1<<1) 51109313Sobrien#define ED_GOT (1<<2) 52109313Sobrien#define ED_HASH (1<<3) 53109313Sobrien#define ED_INTERP (1<<4) 54109313Sobrien#define ED_NOTE (1<<5) 55109313Sobrien#define ED_PHDR (1<<6) 56109313Sobrien#define ED_REL (1<<7) 57109313Sobrien#define ED_SHDR (1<<8) 58109313Sobrien#define ED_SYMTAB (1<<9) 59109313Sobrien#define ED_ALL ((1<<10)-1) 60109313Sobrien 61109313Sobrien#define elf_get_addr elf_get_quad 62109313Sobrien#define elf_get_off elf_get_quad 63109313Sobrien#define elf_get_size elf_get_quad 64109313Sobrien 65109313Sobrienenum elf_member { 66109313Sobrien D_TAG = 1, D_PTR, D_VAL, 67109313Sobrien 68109313Sobrien E_CLASS, E_DATA, E_OSABI, E_TYPE, E_MACHINE, E_VERSION, E_ENTRY, 69109313Sobrien E_PHOFF, E_SHOFF, E_FLAGS, E_EHSIZE, E_PHENTSIZE, E_PHNUM, E_SHENTSIZE, 70109313Sobrien E_SHNUM, E_SHSTRNDX, 71109313Sobrien 72109313Sobrien N_NAMESZ, N_DESCSZ, N_TYPE, 73109313Sobrien 74109313Sobrien P_TYPE, P_OFFSET, P_VADDR, P_PADDR, P_FILESZ, P_MEMSZ, P_FLAGS, 75109313Sobrien P_ALIGN, 76109313Sobrien 77109313Sobrien SH_NAME, SH_TYPE, SH_FLAGS, SH_ADDR, SH_OFFSET, SH_SIZE, SH_LINK, 78109313Sobrien SH_INFO, SH_ADDRALIGN, SH_ENTSIZE, 79109313Sobrien 80109313Sobrien ST_NAME, ST_VALUE, ST_SIZE, ST_INFO, ST_SHNDX, 81109313Sobrien 82109313Sobrien R_OFFSET, R_INFO, 83109313Sobrien 84109313Sobrien RA_OFFSET, RA_INFO, RA_ADDEND 85109313Sobrien}; 86109313Sobrien 87109313Sobrientypedef enum elf_member elf_member_t; 88109313Sobrien 89241737Sedstatic int elf32_offsets[] = { 90109313Sobrien 0, 91109313Sobrien 92109313Sobrien offsetof(Elf32_Dyn, d_tag), offsetof(Elf32_Dyn, d_un.d_ptr), 93109313Sobrien offsetof(Elf32_Dyn, d_un.d_val), 94109313Sobrien 95109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), 96109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_DATA]), 97109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), 98109313Sobrien offsetof(Elf32_Ehdr, e_type), offsetof(Elf32_Ehdr, e_machine), 99109313Sobrien offsetof(Elf32_Ehdr, e_version), offsetof(Elf32_Ehdr, e_entry), 100109313Sobrien offsetof(Elf32_Ehdr, e_phoff), offsetof(Elf32_Ehdr, e_shoff), 101109313Sobrien offsetof(Elf32_Ehdr, e_flags), offsetof(Elf32_Ehdr, e_ehsize), 102109313Sobrien offsetof(Elf32_Ehdr, e_phentsize), offsetof(Elf32_Ehdr, e_phnum), 103109313Sobrien offsetof(Elf32_Ehdr, e_shentsize), offsetof(Elf32_Ehdr, e_shnum), 104109313Sobrien offsetof(Elf32_Ehdr, e_shstrndx), 105109313Sobrien 106109313Sobrien offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), 107109313Sobrien offsetof(Elf_Note, n_type), 108109313Sobrien 109109313Sobrien offsetof(Elf32_Phdr, p_type), offsetof(Elf32_Phdr, p_offset), 110109313Sobrien offsetof(Elf32_Phdr, p_vaddr), offsetof(Elf32_Phdr, p_paddr), 111109313Sobrien offsetof(Elf32_Phdr, p_filesz), offsetof(Elf32_Phdr, p_memsz), 112109313Sobrien offsetof(Elf32_Phdr, p_flags), offsetof(Elf32_Phdr, p_align), 113109313Sobrien 114109313Sobrien offsetof(Elf32_Shdr, sh_name), offsetof(Elf32_Shdr, sh_type), 115109313Sobrien offsetof(Elf32_Shdr, sh_flags), offsetof(Elf32_Shdr, sh_addr), 116109313Sobrien offsetof(Elf32_Shdr, sh_offset), offsetof(Elf32_Shdr, sh_size), 117109313Sobrien offsetof(Elf32_Shdr, sh_link), offsetof(Elf32_Shdr, sh_info), 118109313Sobrien offsetof(Elf32_Shdr, sh_addralign), offsetof(Elf32_Shdr, sh_entsize), 119109313Sobrien 120109313Sobrien offsetof(Elf32_Sym, st_name), offsetof(Elf32_Sym, st_value), 121109313Sobrien offsetof(Elf32_Sym, st_size), offsetof(Elf32_Sym, st_info), 122109313Sobrien offsetof(Elf32_Sym, st_shndx), 123119794Sschweikh 124109313Sobrien offsetof(Elf32_Rel, r_offset), offsetof(Elf32_Rel, r_info), 125109313Sobrien 126109313Sobrien offsetof(Elf32_Rela, r_offset), offsetof(Elf32_Rela, r_info), 127109313Sobrien offsetof(Elf32_Rela, r_addend) 128109313Sobrien}; 129109313Sobrien 130241737Sedstatic int elf64_offsets[] = { 131109313Sobrien 0, 132109313Sobrien 133109313Sobrien offsetof(Elf64_Dyn, d_tag), offsetof(Elf64_Dyn, d_un.d_ptr), 134109313Sobrien offsetof(Elf64_Dyn, d_un.d_val), 135119794Sschweikh 136109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_CLASS]), 137109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_DATA]), 138109313Sobrien offsetof(Elf32_Ehdr, e_ident[EI_OSABI]), 139109313Sobrien offsetof(Elf64_Ehdr, e_type), offsetof(Elf64_Ehdr, e_machine), 140109313Sobrien offsetof(Elf64_Ehdr, e_version), offsetof(Elf64_Ehdr, e_entry), 141109313Sobrien offsetof(Elf64_Ehdr, e_phoff), offsetof(Elf64_Ehdr, e_shoff), 142109313Sobrien offsetof(Elf64_Ehdr, e_flags), offsetof(Elf64_Ehdr, e_ehsize), 143109313Sobrien offsetof(Elf64_Ehdr, e_phentsize), offsetof(Elf64_Ehdr, e_phnum), 144109313Sobrien offsetof(Elf64_Ehdr, e_shentsize), offsetof(Elf64_Ehdr, e_shnum), 145109313Sobrien offsetof(Elf64_Ehdr, e_shstrndx), 146109313Sobrien 147109313Sobrien offsetof(Elf_Note, n_namesz), offsetof(Elf_Note, n_descsz), 148109313Sobrien offsetof(Elf_Note, n_type), 149109313Sobrien 150109313Sobrien offsetof(Elf64_Phdr, p_type), offsetof(Elf64_Phdr, p_offset), 151109313Sobrien offsetof(Elf64_Phdr, p_vaddr), offsetof(Elf64_Phdr, p_paddr), 152109313Sobrien offsetof(Elf64_Phdr, p_filesz), offsetof(Elf64_Phdr, p_memsz), 153109313Sobrien offsetof(Elf64_Phdr, p_flags), offsetof(Elf64_Phdr, p_align), 154109313Sobrien 155109313Sobrien offsetof(Elf64_Shdr, sh_name), offsetof(Elf64_Shdr, sh_type), 156109313Sobrien offsetof(Elf64_Shdr, sh_flags), offsetof(Elf64_Shdr, sh_addr), 157109313Sobrien offsetof(Elf64_Shdr, sh_offset), offsetof(Elf64_Shdr, sh_size), 158109313Sobrien offsetof(Elf64_Shdr, sh_link), offsetof(Elf64_Shdr, sh_info), 159109313Sobrien offsetof(Elf64_Shdr, sh_addralign), offsetof(Elf64_Shdr, sh_entsize), 160109313Sobrien 161109313Sobrien offsetof(Elf64_Sym, st_name), offsetof(Elf64_Sym, st_value), 162109313Sobrien offsetof(Elf64_Sym, st_size), offsetof(Elf64_Sym, st_info), 163109313Sobrien offsetof(Elf64_Sym, st_shndx), 164119794Sschweikh 165109313Sobrien offsetof(Elf64_Rel, r_offset), offsetof(Elf64_Rel, r_info), 166109313Sobrien 167109313Sobrien offsetof(Elf64_Rela, r_offset), offsetof(Elf64_Rela, r_info), 168109313Sobrien offsetof(Elf64_Rela, r_addend) 169109313Sobrien}; 170109313Sobrien 171109332Sobrien/* http://www.sco.com/developers/gabi/latest/ch5.dynamic.html#tag_encodings */ 172110256Sobrienstatic const char * 173270969Semasted_tags(u_int64_t tag) 174270969Semaste{ 175270969Semaste static char unknown_tag[48]; 176270969Semaste 177109332Sobrien switch (tag) { 178270969Semaste case DT_NULL: return "DT_NULL"; 179270969Semaste case DT_NEEDED: return "DT_NEEDED"; 180270969Semaste case DT_PLTRELSZ: return "DT_PLTRELSZ"; 181270969Semaste case DT_PLTGOT: return "DT_PLTGOT"; 182270969Semaste case DT_HASH: return "DT_HASH"; 183270969Semaste case DT_STRTAB: return "DT_STRTAB"; 184270969Semaste case DT_SYMTAB: return "DT_SYMTAB"; 185270969Semaste case DT_RELA: return "DT_RELA"; 186270969Semaste case DT_RELASZ: return "DT_RELASZ"; 187270969Semaste case DT_RELAENT: return "DT_RELAENT"; 188270969Semaste case DT_STRSZ: return "DT_STRSZ"; 189270969Semaste case DT_SYMENT: return "DT_SYMENT"; 190270969Semaste case DT_INIT: return "DT_INIT"; 191270969Semaste case DT_FINI: return "DT_FINI"; 192270969Semaste case DT_SONAME: return "DT_SONAME"; 193270969Semaste case DT_RPATH: return "DT_RPATH"; 194270969Semaste case DT_SYMBOLIC: return "DT_SYMBOLIC"; 195270969Semaste case DT_REL: return "DT_REL"; 196270969Semaste case DT_RELSZ: return "DT_RELSZ"; 197270969Semaste case DT_RELENT: return "DT_RELENT"; 198270969Semaste case DT_PLTREL: return "DT_PLTREL"; 199270969Semaste case DT_DEBUG: return "DT_DEBUG"; 200270969Semaste case DT_TEXTREL: return "DT_TEXTREL"; 201270969Semaste case DT_JMPREL: return "DT_JMPREL"; 202270969Semaste case DT_BIND_NOW: return "DT_BIND_NOW"; 203270969Semaste case DT_INIT_ARRAY: return "DT_INIT_ARRAY"; 204270969Semaste case DT_FINI_ARRAY: return "DT_FINI_ARRAY"; 205270969Semaste case DT_INIT_ARRAYSZ: return "DT_INIT_ARRAYSZ"; 206270969Semaste case DT_FINI_ARRAYSZ: return "DT_FINI_ARRAYSZ"; 207270969Semaste case DT_RUNPATH: return "DT_RUNPATH"; 208270969Semaste case DT_FLAGS: return "DT_FLAGS"; 209270969Semaste case DT_PREINIT_ARRAY: return "DT_PREINIT_ARRAY"; /* XXX DT_ENCODING */ 210270969Semaste case DT_PREINIT_ARRAYSZ:return "DT_PREINIT_ARRAYSZ"; 211109332Sobrien /* 0x6000000D - 0x6ffff000 operating system-specific semantics */ 212270969Semaste case 0x6ffffdf5: return "DT_GNU_PRELINKED"; 213270969Semaste case 0x6ffffdf6: return "DT_GNU_CONFLICTSZ"; 214270969Semaste case 0x6ffffdf7: return "DT_GNU_LIBLISTSZ"; 215270969Semaste case 0x6ffffdf8: return "DT_SUNW_CHECKSUM"; 216270969Semaste case DT_PLTPADSZ: return "DT_PLTPADSZ"; 217270969Semaste case DT_MOVEENT: return "DT_MOVEENT"; 218270969Semaste case DT_MOVESZ: return "DT_MOVESZ"; 219270969Semaste case DT_FEATURE: return "DT_FEATURE"; 220270969Semaste case DT_POSFLAG_1: return "DT_POSFLAG_1"; 221270969Semaste case DT_SYMINSZ: return "DT_SYMINSZ"; 222270969Semaste case DT_SYMINENT : return "DT_SYMINENT (DT_VALRNGHI)"; 223270969Semaste case DT_ADDRRNGLO: return "DT_ADDRRNGLO"; 224270969Semaste case DT_GNU_HASH: return "DT_GNU_HASH"; 225270969Semaste case 0x6ffffef8: return "DT_GNU_CONFLICT"; 226270969Semaste case 0x6ffffef9: return "DT_GNU_LIBLIST"; 227270969Semaste case DT_CONFIG: return "DT_CONFIG"; 228270969Semaste case DT_DEPAUDIT: return "DT_DEPAUDIT"; 229270969Semaste case DT_AUDIT: return "DT_AUDIT"; 230270969Semaste case DT_PLTPAD: return "DT_PLTPAD"; 231270969Semaste case DT_MOVETAB: return "DT_MOVETAB"; 232270969Semaste case DT_SYMINFO : return "DT_SYMINFO (DT_ADDRRNGHI)"; 233270969Semaste case DT_RELACOUNT: return "DT_RELACOUNT"; 234270969Semaste case DT_RELCOUNT: return "DT_RELCOUNT"; 235270969Semaste case DT_FLAGS_1: return "DT_FLAGS_1"; 236270969Semaste case DT_VERDEF: return "DT_VERDEF"; 237270969Semaste case DT_VERDEFNUM: return "DT_VERDEFNUM"; 238270969Semaste case DT_VERNEED: return "DT_VERNEED"; 239270969Semaste case DT_VERNEEDNUM: return "DT_VERNEEDNUM"; 240270969Semaste case 0x6ffffff0: return "DT_GNU_VERSYM"; 241109332Sobrien /* 0x70000000 - 0x7fffffff processor-specific semantics */ 242270969Semaste case 0x70000000: return "DT_IA_64_PLT_RESERVE"; 243307834Semaste case DT_AUXILIARY: return "DT_AUXILIARY"; 244307834Semaste case DT_USED: return "DT_USED"; 245307834Semaste case DT_FILTER: return "DT_FILTER"; 246109332Sobrien } 247270969Semaste snprintf(unknown_tag, sizeof(unknown_tag), 248270969Semaste "ERROR: TAG NOT DEFINED -- tag 0x%jx", (uintmax_t)tag); 249270969Semaste return (unknown_tag); 250119794Sschweikh} 251109313Sobrien 252110256Sobrienstatic const char * 253109457Smarcele_machines(u_int mach) 254109457Smarcel{ 255153500Smarcel static char machdesc[64]; 256153500Smarcel 257109457Smarcel switch (mach) { 258109457Smarcel case EM_NONE: return "EM_NONE"; 259109457Smarcel case EM_M32: return "EM_M32"; 260109457Smarcel case EM_SPARC: return "EM_SPARC"; 261109457Smarcel case EM_386: return "EM_386"; 262109457Smarcel case EM_68K: return "EM_68K"; 263109457Smarcel case EM_88K: return "EM_88K"; 264288173Semaste case EM_IAMCU: return "EM_IAMCU"; 265109457Smarcel case EM_860: return "EM_860"; 266109457Smarcel case EM_MIPS: return "EM_MIPS"; 267153500Smarcel case EM_PPC: return "EM_PPC"; 268261002Sjhibbits case EM_PPC64: return "EM_PPC64"; 269153500Smarcel case EM_ARM: return "EM_ARM"; 270153500Smarcel case EM_ALPHA: return "EM_ALPHA (legacy)"; 271153500Smarcel case EM_SPARCV9:return "EM_SPARCV9"; 272109457Smarcel case EM_IA_64: return "EM_IA_64"; 273153500Smarcel case EM_X86_64: return "EM_X86_64"; 274270969Semaste case EM_AARCH64:return "EM_AARCH64"; 275288171Semaste case EM_RISCV: return "EM_RISCV"; 276109457Smarcel } 277153500Smarcel snprintf(machdesc, sizeof(machdesc), 278153500Smarcel "(unknown machine) -- type 0x%x", mach); 279153500Smarcel return (machdesc); 280119794Sschweikh} 281109313Sobrien 282241737Sedstatic const char *e_types[] = { 283109313Sobrien "ET_NONE", "ET_REL", "ET_EXEC", "ET_DYN", "ET_CORE" 284109313Sobrien}; 285109313Sobrien 286241737Sedstatic const char *ei_versions[] = { 287109313Sobrien "EV_NONE", "EV_CURRENT" 288109313Sobrien}; 289109313Sobrien 290241737Sedstatic const char *ei_classes[] = { 291109313Sobrien "ELFCLASSNONE", "ELFCLASS32", "ELFCLASS64" 292109313Sobrien}; 293109313Sobrien 294241737Sedstatic const char *ei_data[] = { 295109313Sobrien "ELFDATANONE", "ELFDATA2LSB", "ELFDATA2MSB" 296109313Sobrien}; 297109313Sobrien 298241737Sedstatic const char *ei_abis[256] = { 299109313Sobrien "ELFOSABI_SYSV", "ELFOSABI_HPUX", "ELFOSABI_NETBSD", "ELFOSABI_LINUX", 300226434Smarcel "ELFOSABI_HURD", "ELFOSABI_86OPEN", "ELFOSABI_SOLARIS", "ELFOSABI_AIX", 301226434Smarcel "ELFOSABI_IRIX", "ELFOSABI_FREEBSD", "ELFOSABI_TRU64", 302226434Smarcel "ELFOSABI_MODESTO", "ELFOSABI_OPENBSD", 303226434Smarcel [255] = "ELFOSABI_STANDALONE" 304109313Sobrien}; 305109313Sobrien 306241737Sedstatic const char *p_types[] = { 307109313Sobrien "PT_NULL", "PT_LOAD", "PT_DYNAMIC", "PT_INTERP", "PT_NOTE", 308126484Sjake "PT_SHLIB", "PT_PHDR", "PT_TLS" 309109313Sobrien}; 310109313Sobrien 311241737Sedstatic const char *p_flags[] = { 312109313Sobrien "", "PF_X", "PF_W", "PF_X|PF_W", "PF_R", "PF_X|PF_R", "PF_W|PF_R", 313109313Sobrien "PF_X|PF_W|PF_R" 314109313Sobrien}; 315109313Sobrien 316109329Sobrien/* http://www.sco.com/developers/gabi/latest/ch4.sheader.html#sh_type */ 317110256Sobrienstatic const char * 318270969Semastesh_types(uint64_t machine, uint64_t sht) { 319270969Semaste static char unknown_buf[64]; 320270969Semaste 321270969Semaste if (sht < 0x60000000) { 322270969Semaste switch (sht) { 323270969Semaste case SHT_NULL: return "SHT_NULL"; 324270969Semaste case SHT_PROGBITS: return "SHT_PROGBITS"; 325270969Semaste case SHT_SYMTAB: return "SHT_SYMTAB"; 326270969Semaste case SHT_STRTAB: return "SHT_STRTAB"; 327270969Semaste case SHT_RELA: return "SHT_RELA"; 328270969Semaste case SHT_HASH: return "SHT_HASH"; 329270969Semaste case SHT_DYNAMIC: return "SHT_DYNAMIC"; 330270969Semaste case SHT_NOTE: return "SHT_NOTE"; 331270969Semaste case SHT_NOBITS: return "SHT_NOBITS"; 332270969Semaste case SHT_REL: return "SHT_REL"; 333270969Semaste case SHT_SHLIB: return "SHT_SHLIB"; 334270969Semaste case SHT_DYNSYM: return "SHT_DYNSYM"; 335270969Semaste case SHT_INIT_ARRAY: return "SHT_INIT_ARRAY"; 336270969Semaste case SHT_FINI_ARRAY: return "SHT_FINI_ARRAY"; 337270969Semaste case SHT_PREINIT_ARRAY: return "SHT_PREINIT_ARRAY"; 338270969Semaste case SHT_GROUP: return "SHT_GROUP"; 339270969Semaste case SHT_SYMTAB_SHNDX: return "SHT_SYMTAB_SHNDX"; 340270969Semaste } 341270969Semaste snprintf(unknown_buf, sizeof(unknown_buf), 342270969Semaste "ERROR: SHT %ju NOT DEFINED", (uintmax_t)sht); 343270969Semaste return (unknown_buf); 344270969Semaste } else if (sht < 0x70000000) { 345270969Semaste /* 0x60000000-0x6fffffff operating system-specific semantics */ 346270969Semaste switch (sht) { 347270969Semaste case 0x6ffffff0: return "XXX:VERSYM"; 348270969Semaste case SHT_SUNW_dof: return "SHT_SUNW_dof"; 349270969Semaste case SHT_GNU_HASH: return "SHT_GNU_HASH"; 350270969Semaste case 0x6ffffff7: return "SHT_GNU_LIBLIST"; 351270969Semaste case 0x6ffffffc: return "XXX:VERDEF"; 352270969Semaste case SHT_SUNW_verdef: return "SHT_SUNW(GNU)_verdef"; 353270969Semaste case SHT_SUNW_verneed: return "SHT_SUNW(GNU)_verneed"; 354270969Semaste case SHT_SUNW_versym: return "SHT_SUNW(GNU)_versym"; 355270969Semaste } 356270969Semaste snprintf(unknown_buf, sizeof(unknown_buf), 357270969Semaste "ERROR: OS-SPECIFIC SHT 0x%jx NOT DEFINED", 358270969Semaste (uintmax_t)sht); 359270969Semaste return (unknown_buf); 360270969Semaste } else if (sht < 0x80000000) { 361270969Semaste /* 0x70000000-0x7fffffff processor-specific semantics */ 362270969Semaste switch (machine) { 363270969Semaste case EM_ARM: 364270969Semaste switch (sht) { 365270969Semaste case SHT_ARM_EXIDX: return "SHT_ARM_EXIDX"; 366270969Semaste case SHT_ARM_PREEMPTMAP:return "SHT_ARM_PREEMPTMAP"; 367270969Semaste case SHT_ARM_ATTRIBUTES:return "SHT_ARM_ATTRIBUTES"; 368270969Semaste case SHT_ARM_DEBUGOVERLAY: 369270969Semaste return "SHT_ARM_DEBUGOVERLAY"; 370270969Semaste case SHT_ARM_OVERLAYSECTION: 371270969Semaste return "SHT_ARM_OVERLAYSECTION"; 372270969Semaste } 373270969Semaste break; 374270969Semaste case EM_IA_64: 375270969Semaste switch (sht) { 376270969Semaste case 0x70000000: return "SHT_IA_64_EXT"; 377270969Semaste case 0x70000001: return "SHT_IA_64_UNWIND"; 378270969Semaste } 379270969Semaste break; 380270969Semaste case EM_MIPS: 381270969Semaste switch (sht) { 382294450Semaste case SHT_MIPS_REGINFO: return "SHT_MIPS_REGINFO"; 383270969Semaste case SHT_MIPS_OPTIONS: return "SHT_MIPS_OPTIONS"; 384294450Semaste case SHT_MIPS_ABIFLAGS: return "SHT_MIPS_ABIFLAGS"; 385270969Semaste } 386270969Semaste break; 387270969Semaste } 388270969Semaste switch (sht) { 389270969Semaste case 0x7ffffffd: return "XXX:AUXILIARY"; 390270969Semaste case 0x7fffffff: return "XXX:FILTER"; 391270969Semaste } 392270969Semaste snprintf(unknown_buf, sizeof(unknown_buf), 393270969Semaste "ERROR: PROCESSOR-SPECIFIC SHT 0x%jx NOT DEFINED", 394270969Semaste (uintmax_t)sht); 395270969Semaste return (unknown_buf); 396270969Semaste } else { 397270969Semaste /* 0x80000000-0xffffffff application programs */ 398270969Semaste snprintf(unknown_buf, sizeof(unknown_buf), 399270969Semaste "ERROR: SHT 0x%jx NOT DEFINED", 400270969Semaste (uintmax_t)sht); 401270969Semaste return (unknown_buf); 402109329Sobrien } 403119795Sschweikh} 404109313Sobrien 405241737Sedstatic const char *sh_flags[] = { 406109313Sobrien "", "SHF_WRITE", "SHF_ALLOC", "SHF_WRITE|SHF_ALLOC", "SHF_EXECINSTR", 407109313Sobrien "SHF_WRITE|SHF_EXECINSTR", "SHF_ALLOC|SHF_EXECINSTR", 408109313Sobrien "SHF_WRITE|SHF_ALLOC|SHF_EXECINSTR" 409109313Sobrien}; 410109313Sobrien 411241737Sedstatic const char *st_types[] = { 412109313Sobrien "STT_NOTYPE", "STT_OBJECT", "STT_FUNC", "STT_SECTION", "STT_FILE" 413109313Sobrien}; 414109313Sobrien 415241737Sedstatic const char *st_bindings[] = { 416109313Sobrien "STB_LOCAL", "STB_GLOBAL", "STB_WEAK" 417109313Sobrien}; 418109313Sobrien 419241737Sedstatic char *dynstr; 420241737Sedstatic char *shstrtab; 421241737Sedstatic char *strtab; 422241737Sedstatic FILE *out; 423109313Sobrien 424241737Sedstatic u_int64_t elf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member); 425241737Sedstatic u_int64_t elf_get_quarter(Elf32_Ehdr *e, void *base, 426241737Sed elf_member_t member); 427241737Sed#if 0 428241737Sedstatic u_int64_t elf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member); 429241737Sed#endif 430241737Sedstatic u_int64_t elf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member); 431241737Sedstatic u_int64_t elf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member); 432109313Sobrien 433267958Semastestatic void elf_print_ehdr(Elf32_Ehdr *e, void *sh); 434241737Sedstatic void elf_print_phdr(Elf32_Ehdr *e, void *p); 435241737Sedstatic void elf_print_shdr(Elf32_Ehdr *e, void *sh); 436241737Sedstatic void elf_print_symtab(Elf32_Ehdr *e, void *sh, char *str); 437241737Sedstatic void elf_print_dynamic(Elf32_Ehdr *e, void *sh); 438241737Sedstatic void elf_print_rel(Elf32_Ehdr *e, void *r); 439241737Sedstatic void elf_print_rela(Elf32_Ehdr *e, void *ra); 440241737Sedstatic void elf_print_interp(Elf32_Ehdr *e, void *p); 441241737Sedstatic void elf_print_got(Elf32_Ehdr *e, void *sh); 442241737Sedstatic void elf_print_hash(Elf32_Ehdr *e, void *sh); 443241737Sedstatic void elf_print_note(Elf32_Ehdr *e, void *sh); 444109313Sobrien 445241737Sedstatic void usage(void); 446109313Sobrien 447267958Semaste/* 448267958Semaste * Helpers for ELF files with shnum or shstrndx values that don't fit in the 449267958Semaste * ELF header. If the values are too large then an escape value is used to 450267958Semaste * indicate that the actual value is found in one of section 0's fields. 451267958Semaste */ 452267958Semastestatic uint64_t 453267958Semasteelf_get_shnum(Elf32_Ehdr *e, void *sh) 454267958Semaste{ 455267958Semaste uint64_t shnum; 456267958Semaste 457267958Semaste shnum = elf_get_quarter(e, e, E_SHNUM); 458267958Semaste if (shnum == 0) 459267958Semaste shnum = elf_get_word(e, (char *)sh, SH_SIZE); 460267958Semaste return shnum; 461267958Semaste} 462267958Semaste 463267958Semastestatic uint64_t 464267958Semasteelf_get_shstrndx(Elf32_Ehdr *e, void *sh) 465267958Semaste{ 466267958Semaste uint64_t shstrndx; 467267958Semaste 468267958Semaste shstrndx = elf_get_quarter(e, e, E_SHSTRNDX); 469267958Semaste if (shstrndx == SHN_XINDEX) 470267958Semaste shstrndx = elf_get_word(e, (char *)sh, SH_LINK); 471267958Semaste return shstrndx; 472267958Semaste} 473267958Semaste 474109313Sobrienint 475109313Sobrienmain(int ac, char **av) 476109313Sobrien{ 477275945Sbrueffer cap_rights_t rights; 478109313Sobrien u_int64_t phoff; 479109313Sobrien u_int64_t shoff; 480109313Sobrien u_int64_t phentsize; 481109313Sobrien u_int64_t phnum; 482109313Sobrien u_int64_t shentsize; 483109313Sobrien u_int64_t shnum; 484109313Sobrien u_int64_t shstrndx; 485109313Sobrien u_int64_t offset; 486109313Sobrien u_int64_t name; 487109313Sobrien u_int64_t type; 488109313Sobrien struct stat sb; 489109313Sobrien u_int flags; 490110252Sobrien Elf32_Ehdr *e; 491109313Sobrien void *p; 492109313Sobrien void *sh; 493109313Sobrien void *v; 494109313Sobrien int fd; 495109313Sobrien int ch; 496109313Sobrien int i; 497109313Sobrien 498109313Sobrien out = stdout; 499109313Sobrien flags = 0; 500109313Sobrien while ((ch = getopt(ac, av, "acdeiGhnprsw:")) != -1) 501109313Sobrien switch (ch) { 502109313Sobrien case 'a': 503109313Sobrien flags = ED_ALL; 504109313Sobrien break; 505109313Sobrien case 'c': 506109313Sobrien flags |= ED_SHDR; 507109313Sobrien break; 508109313Sobrien case 'd': 509109313Sobrien flags |= ED_DYN; 510109313Sobrien break; 511109313Sobrien case 'e': 512109313Sobrien flags |= ED_EHDR; 513109313Sobrien break; 514109313Sobrien case 'i': 515109313Sobrien flags |= ED_INTERP; 516109313Sobrien break; 517109313Sobrien case 'G': 518109313Sobrien flags |= ED_GOT; 519109313Sobrien break; 520109313Sobrien case 'h': 521109313Sobrien flags |= ED_HASH; 522109313Sobrien break; 523109313Sobrien case 'n': 524109313Sobrien flags |= ED_NOTE; 525109313Sobrien break; 526109313Sobrien case 'p': 527109313Sobrien flags |= ED_PHDR; 528109313Sobrien break; 529109313Sobrien case 'r': 530109313Sobrien flags |= ED_REL; 531109313Sobrien break; 532109313Sobrien case 's': 533109313Sobrien flags |= ED_SYMTAB; 534109313Sobrien break; 535109313Sobrien case 'w': 536109313Sobrien if ((out = fopen(optarg, "w")) == NULL) 537109313Sobrien err(1, "%s", optarg); 538275945Sbrueffer cap_rights_init(&rights, CAP_FSTAT, CAP_WRITE); 539275945Sbrueffer if (cap_rights_limit(fileno(out), &rights) < 0 && errno != ENOSYS) 540275945Sbrueffer err(1, "unable to limit rights for %s", optarg); 541109313Sobrien break; 542109313Sobrien case '?': 543109313Sobrien default: 544109313Sobrien usage(); 545109313Sobrien } 546109313Sobrien ac -= optind; 547109313Sobrien av += optind; 548109313Sobrien if (ac == 0 || flags == 0) 549109313Sobrien usage(); 550109313Sobrien if ((fd = open(*av, O_RDONLY)) < 0 || 551109313Sobrien fstat(fd, &sb) < 0) 552117009Sru err(1, "%s", *av); 553275945Sbrueffer cap_rights_init(&rights, CAP_MMAP_R); 554275945Sbrueffer if (cap_rights_limit(fd, &rights) < 0 && errno != ENOSYS) 555275945Sbrueffer err(1, "unable to limit rights for %s", *av); 556275945Sbrueffer close(STDIN_FILENO); 557275945Sbrueffer cap_rights_init(&rights, CAP_WRITE); 558275945Sbrueffer if (cap_rights_limit(STDOUT_FILENO, &rights) < 0 && errno != ENOSYS) 559275945Sbrueffer err(1, "unable to limit rights for stdout"); 560275945Sbrueffer if (cap_rights_limit(STDERR_FILENO, &rights) < 0 && errno != ENOSYS) 561275945Sbrueffer err(1, "unable to limit rights for stderr"); 562275945Sbrueffer if (cap_enter() < 0 && errno != ENOSYS) 563275945Sbrueffer err(1, "unable to enter capability mode"); 564109313Sobrien e = mmap(NULL, sb.st_size, PROT_READ, MAP_SHARED, fd, 0); 565109313Sobrien if (e == MAP_FAILED) 566109313Sobrien err(1, NULL); 567109313Sobrien if (!IS_ELF(*(Elf32_Ehdr *)e)) 568109313Sobrien errx(1, "not an elf file"); 569109313Sobrien phoff = elf_get_off(e, e, E_PHOFF); 570109313Sobrien shoff = elf_get_off(e, e, E_SHOFF); 571109313Sobrien phentsize = elf_get_quarter(e, e, E_PHENTSIZE); 572109313Sobrien phnum = elf_get_quarter(e, e, E_PHNUM); 573109313Sobrien shentsize = elf_get_quarter(e, e, E_SHENTSIZE); 574110256Sobrien p = (char *)e + phoff; 575267958Semaste if (shoff > 0) { 576267958Semaste sh = (char *)e + shoff; 577267958Semaste shnum = elf_get_shnum(e, sh); 578267958Semaste shstrndx = elf_get_shstrndx(e, sh); 579267958Semaste offset = elf_get_off(e, (char *)sh + shstrndx * shentsize, 580267958Semaste SH_OFFSET); 581267958Semaste shstrtab = (char *)e + offset; 582267958Semaste } else { 583267958Semaste sh = NULL; 584267958Semaste shnum = 0; 585267958Semaste shstrndx = 0; 586267958Semaste shstrtab = NULL; 587267958Semaste } 588110256Sobrien for (i = 0; (u_int64_t)i < shnum; i++) { 589110256Sobrien name = elf_get_word(e, (char *)sh + i * shentsize, SH_NAME); 590110256Sobrien offset = elf_get_off(e, (char *)sh + i * shentsize, SH_OFFSET); 591109313Sobrien if (strcmp(shstrtab + name, ".strtab") == 0) 592110252Sobrien strtab = (char *)e + offset; 593109313Sobrien if (strcmp(shstrtab + name, ".dynstr") == 0) 594110252Sobrien dynstr = (char *)e + offset; 595109313Sobrien } 596109313Sobrien if (flags & ED_EHDR) 597267958Semaste elf_print_ehdr(e, sh); 598109313Sobrien if (flags & ED_PHDR) 599109313Sobrien elf_print_phdr(e, p); 600109313Sobrien if (flags & ED_SHDR) 601109313Sobrien elf_print_shdr(e, sh); 602110256Sobrien for (i = 0; (u_int64_t)i < phnum; i++) { 603110256Sobrien v = (char *)p + i * phentsize; 604109313Sobrien type = elf_get_word(e, v, P_TYPE); 605109313Sobrien switch (type) { 606109313Sobrien case PT_INTERP: 607109313Sobrien if (flags & ED_INTERP) 608109313Sobrien elf_print_interp(e, v); 609109313Sobrien break; 610109313Sobrien case PT_NULL: 611109313Sobrien case PT_LOAD: 612109313Sobrien case PT_DYNAMIC: 613109313Sobrien case PT_NOTE: 614109313Sobrien case PT_SHLIB: 615109313Sobrien case PT_PHDR: 616109313Sobrien break; 617109313Sobrien } 618109313Sobrien } 619110256Sobrien for (i = 0; (u_int64_t)i < shnum; i++) { 620110256Sobrien v = (char *)sh + i * shentsize; 621109313Sobrien type = elf_get_word(e, v, SH_TYPE); 622109313Sobrien switch (type) { 623109313Sobrien case SHT_SYMTAB: 624109313Sobrien if (flags & ED_SYMTAB) 625109313Sobrien elf_print_symtab(e, v, strtab); 626109313Sobrien break; 627109313Sobrien case SHT_DYNAMIC: 628109313Sobrien if (flags & ED_DYN) 629109313Sobrien elf_print_dynamic(e, v); 630109313Sobrien break; 631109313Sobrien case SHT_RELA: 632109313Sobrien if (flags & ED_REL) 633109313Sobrien elf_print_rela(e, v); 634109313Sobrien break; 635109313Sobrien case SHT_REL: 636109313Sobrien if (flags & ED_REL) 637109313Sobrien elf_print_rel(e, v); 638109313Sobrien break; 639109313Sobrien case SHT_NOTE: 640109313Sobrien name = elf_get_word(e, v, SH_NAME); 641109313Sobrien if (flags & ED_NOTE && 642109313Sobrien strcmp(shstrtab + name, ".note.ABI-tag") == 0) 643109313Sobrien elf_print_note(e, v); 644109313Sobrien break; 645109313Sobrien case SHT_DYNSYM: 646109313Sobrien if (flags & ED_SYMTAB) 647109313Sobrien elf_print_symtab(e, v, dynstr); 648109313Sobrien break; 649109313Sobrien case SHT_PROGBITS: 650109313Sobrien name = elf_get_word(e, v, SH_NAME); 651109313Sobrien if (flags & ED_GOT && 652109313Sobrien strcmp(shstrtab + name, ".got") == 0) 653109313Sobrien elf_print_got(e, v); 654109313Sobrien break; 655109313Sobrien case SHT_HASH: 656109313Sobrien if (flags & ED_HASH) 657109313Sobrien elf_print_hash(e, v); 658109313Sobrien break; 659109313Sobrien case SHT_NULL: 660109313Sobrien case SHT_STRTAB: 661109313Sobrien case SHT_NOBITS: 662109313Sobrien case SHT_SHLIB: 663109313Sobrien break; 664109313Sobrien } 665109313Sobrien } 666109313Sobrien 667109313Sobrien return 0; 668109313Sobrien} 669109313Sobrien 670241737Sedstatic void 671267958Semasteelf_print_ehdr(Elf32_Ehdr *e, void *sh) 672109313Sobrien{ 673109313Sobrien u_int64_t class; 674109313Sobrien u_int64_t data; 675109313Sobrien u_int64_t osabi; 676109313Sobrien u_int64_t type; 677109313Sobrien u_int64_t machine; 678109313Sobrien u_int64_t version; 679109313Sobrien u_int64_t entry; 680109313Sobrien u_int64_t phoff; 681109313Sobrien u_int64_t shoff; 682109313Sobrien u_int64_t flags; 683109313Sobrien u_int64_t ehsize; 684109313Sobrien u_int64_t phentsize; 685109313Sobrien u_int64_t phnum; 686109313Sobrien u_int64_t shentsize; 687109313Sobrien u_int64_t shnum; 688109313Sobrien u_int64_t shstrndx; 689109313Sobrien 690109313Sobrien class = elf_get_byte(e, e, E_CLASS); 691109313Sobrien data = elf_get_byte(e, e, E_DATA); 692109313Sobrien osabi = elf_get_byte(e, e, E_OSABI); 693109313Sobrien type = elf_get_quarter(e, e, E_TYPE); 694109313Sobrien machine = elf_get_quarter(e, e, E_MACHINE); 695109313Sobrien version = elf_get_word(e, e, E_VERSION); 696109313Sobrien entry = elf_get_addr(e, e, E_ENTRY); 697109313Sobrien phoff = elf_get_off(e, e, E_PHOFF); 698109313Sobrien shoff = elf_get_off(e, e, E_SHOFF); 699109313Sobrien flags = elf_get_word(e, e, E_FLAGS); 700109313Sobrien ehsize = elf_get_quarter(e, e, E_EHSIZE); 701109313Sobrien phentsize = elf_get_quarter(e, e, E_PHENTSIZE); 702109313Sobrien phnum = elf_get_quarter(e, e, E_PHNUM); 703109313Sobrien shentsize = elf_get_quarter(e, e, E_SHENTSIZE); 704109313Sobrien fprintf(out, "\nelf header:\n"); 705109313Sobrien fprintf(out, "\n"); 706109313Sobrien fprintf(out, "\te_ident: %s %s %s\n", ei_classes[class], ei_data[data], 707109313Sobrien ei_abis[osabi]); 708109313Sobrien fprintf(out, "\te_type: %s\n", e_types[type]); 709109457Smarcel fprintf(out, "\te_machine: %s\n", e_machines(machine)); 710109313Sobrien fprintf(out, "\te_version: %s\n", ei_versions[version]); 711110257Sobrien fprintf(out, "\te_entry: %#jx\n", (intmax_t)entry); 712110257Sobrien fprintf(out, "\te_phoff: %jd\n", (intmax_t)phoff); 713110257Sobrien fprintf(out, "\te_shoff: %jd\n", (intmax_t)shoff); 714110257Sobrien fprintf(out, "\te_flags: %jd\n", (intmax_t)flags); 715110257Sobrien fprintf(out, "\te_ehsize: %jd\n", (intmax_t)ehsize); 716110257Sobrien fprintf(out, "\te_phentsize: %jd\n", (intmax_t)phentsize); 717110257Sobrien fprintf(out, "\te_phnum: %jd\n", (intmax_t)phnum); 718110257Sobrien fprintf(out, "\te_shentsize: %jd\n", (intmax_t)shentsize); 719267958Semaste if (sh != NULL) { 720267958Semaste shnum = elf_get_shnum(e, sh); 721267958Semaste shstrndx = elf_get_shstrndx(e, sh); 722267958Semaste fprintf(out, "\te_shnum: %jd\n", (intmax_t)shnum); 723267958Semaste fprintf(out, "\te_shstrndx: %jd\n", (intmax_t)shstrndx); 724267958Semaste } 725109313Sobrien} 726109313Sobrien 727241737Sedstatic void 728110252Sobrienelf_print_phdr(Elf32_Ehdr *e, void *p) 729109313Sobrien{ 730109313Sobrien u_int64_t phentsize; 731109313Sobrien u_int64_t phnum; 732109313Sobrien u_int64_t type; 733109313Sobrien u_int64_t offset; 734109313Sobrien u_int64_t vaddr; 735109313Sobrien u_int64_t paddr; 736109313Sobrien u_int64_t filesz; 737109313Sobrien u_int64_t memsz; 738109313Sobrien u_int64_t flags; 739109313Sobrien u_int64_t align; 740109313Sobrien void *v; 741109313Sobrien int i; 742109313Sobrien 743109313Sobrien phentsize = elf_get_quarter(e, e, E_PHENTSIZE); 744109313Sobrien phnum = elf_get_quarter(e, e, E_PHNUM); 745109313Sobrien fprintf(out, "\nprogram header:\n"); 746110256Sobrien for (i = 0; (u_int64_t)i < phnum; i++) { 747110256Sobrien v = (char *)p + i * phentsize; 748109313Sobrien type = elf_get_word(e, v, P_TYPE); 749109313Sobrien offset = elf_get_off(e, v, P_OFFSET); 750109313Sobrien vaddr = elf_get_addr(e, v, P_VADDR); 751109313Sobrien paddr = elf_get_addr(e, v, P_PADDR); 752109313Sobrien filesz = elf_get_size(e, v, P_FILESZ); 753109313Sobrien memsz = elf_get_size(e, v, P_MEMSZ); 754109313Sobrien flags = elf_get_word(e, v, P_FLAGS); 755109313Sobrien align = elf_get_size(e, v, P_ALIGN); 756109313Sobrien fprintf(out, "\n"); 757109313Sobrien fprintf(out, "entry: %d\n", i); 758109313Sobrien fprintf(out, "\tp_type: %s\n", p_types[type & 0x7]); 759110257Sobrien fprintf(out, "\tp_offset: %jd\n", (intmax_t)offset); 760110257Sobrien fprintf(out, "\tp_vaddr: %#jx\n", (intmax_t)vaddr); 761110257Sobrien fprintf(out, "\tp_paddr: %#jx\n", (intmax_t)paddr); 762110257Sobrien fprintf(out, "\tp_filesz: %jd\n", (intmax_t)filesz); 763110257Sobrien fprintf(out, "\tp_memsz: %jd\n", (intmax_t)memsz); 764109313Sobrien fprintf(out, "\tp_flags: %s\n", p_flags[flags]); 765110257Sobrien fprintf(out, "\tp_align: %jd\n", (intmax_t)align); 766109313Sobrien } 767109313Sobrien} 768109313Sobrien 769241737Sedstatic void 770110252Sobrienelf_print_shdr(Elf32_Ehdr *e, void *sh) 771109313Sobrien{ 772109313Sobrien u_int64_t shentsize; 773109313Sobrien u_int64_t shnum; 774109313Sobrien u_int64_t name; 775109313Sobrien u_int64_t type; 776109313Sobrien u_int64_t flags; 777109313Sobrien u_int64_t addr; 778109313Sobrien u_int64_t offset; 779109313Sobrien u_int64_t size; 780110256Sobrien u_int64_t shlink; 781109313Sobrien u_int64_t info; 782109313Sobrien u_int64_t addralign; 783109313Sobrien u_int64_t entsize; 784270969Semaste u_int64_t machine; 785109313Sobrien void *v; 786109313Sobrien int i; 787109313Sobrien 788267958Semaste if (sh == NULL) { 789267958Semaste fprintf(out, "\nNo section headers\n"); 790267958Semaste return; 791267958Semaste } 792267958Semaste 793270969Semaste machine = elf_get_quarter(e, e, E_MACHINE); 794109313Sobrien shentsize = elf_get_quarter(e, e, E_SHENTSIZE); 795267958Semaste shnum = elf_get_shnum(e, sh); 796109313Sobrien fprintf(out, "\nsection header:\n"); 797110256Sobrien for (i = 0; (u_int64_t)i < shnum; i++) { 798110256Sobrien v = (char *)sh + i * shentsize; 799109313Sobrien name = elf_get_word(e, v, SH_NAME); 800109313Sobrien type = elf_get_word(e, v, SH_TYPE); 801109313Sobrien flags = elf_get_word(e, v, SH_FLAGS); 802109313Sobrien addr = elf_get_addr(e, v, SH_ADDR); 803109313Sobrien offset = elf_get_off(e, v, SH_OFFSET); 804109313Sobrien size = elf_get_size(e, v, SH_SIZE); 805110256Sobrien shlink = elf_get_word(e, v, SH_LINK); 806109313Sobrien info = elf_get_word(e, v, SH_INFO); 807109313Sobrien addralign = elf_get_size(e, v, SH_ADDRALIGN); 808109313Sobrien entsize = elf_get_size(e, v, SH_ENTSIZE); 809109313Sobrien fprintf(out, "\n"); 810109313Sobrien fprintf(out, "entry: %d\n", i); 811109313Sobrien fprintf(out, "\tsh_name: %s\n", shstrtab + name); 812270969Semaste fprintf(out, "\tsh_type: %s\n", sh_types(machine, type)); 813109313Sobrien fprintf(out, "\tsh_flags: %s\n", sh_flags[flags & 0x7]); 814110257Sobrien fprintf(out, "\tsh_addr: %#jx\n", addr); 815110257Sobrien fprintf(out, "\tsh_offset: %jd\n", (intmax_t)offset); 816110257Sobrien fprintf(out, "\tsh_size: %jd\n", (intmax_t)size); 817110257Sobrien fprintf(out, "\tsh_link: %jd\n", (intmax_t)shlink); 818110257Sobrien fprintf(out, "\tsh_info: %jd\n", (intmax_t)info); 819110257Sobrien fprintf(out, "\tsh_addralign: %jd\n", (intmax_t)addralign); 820110257Sobrien fprintf(out, "\tsh_entsize: %jd\n", (intmax_t)entsize); 821109313Sobrien } 822109313Sobrien} 823109313Sobrien 824241737Sedstatic void 825110252Sobrienelf_print_symtab(Elf32_Ehdr *e, void *sh, char *str) 826109313Sobrien{ 827109313Sobrien u_int64_t offset; 828109313Sobrien u_int64_t entsize; 829109313Sobrien u_int64_t size; 830109313Sobrien u_int64_t name; 831109313Sobrien u_int64_t value; 832109313Sobrien u_int64_t info; 833109313Sobrien u_int64_t shndx; 834109313Sobrien void *st; 835109313Sobrien int len; 836109313Sobrien int i; 837109313Sobrien 838109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 839109313Sobrien entsize = elf_get_size(e, sh, SH_ENTSIZE); 840109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 841109313Sobrien name = elf_get_word(e, sh, SH_NAME); 842109313Sobrien len = size / entsize; 843109313Sobrien fprintf(out, "\nsymbol table (%s):\n", shstrtab + name); 844109313Sobrien for (i = 0; i < len; i++) { 845110256Sobrien st = (char *)e + offset + i * entsize; 846109313Sobrien name = elf_get_word(e, st, ST_NAME); 847109313Sobrien value = elf_get_addr(e, st, ST_VALUE); 848109313Sobrien size = elf_get_size(e, st, ST_SIZE); 849109313Sobrien info = elf_get_byte(e, st, ST_INFO); 850109313Sobrien shndx = elf_get_quarter(e, st, ST_SHNDX); 851109313Sobrien fprintf(out, "\n"); 852109313Sobrien fprintf(out, "entry: %d\n", i); 853109313Sobrien fprintf(out, "\tst_name: %s\n", str + name); 854110257Sobrien fprintf(out, "\tst_value: %#jx\n", value); 855110257Sobrien fprintf(out, "\tst_size: %jd\n", (intmax_t)size); 856109313Sobrien fprintf(out, "\tst_info: %s %s\n", 857109313Sobrien st_types[ELF32_ST_TYPE(info)], 858109313Sobrien st_bindings[ELF32_ST_BIND(info)]); 859110257Sobrien fprintf(out, "\tst_shndx: %jd\n", (intmax_t)shndx); 860109313Sobrien } 861109313Sobrien} 862109313Sobrien 863241737Sedstatic void 864110252Sobrienelf_print_dynamic(Elf32_Ehdr *e, void *sh) 865109313Sobrien{ 866109313Sobrien u_int64_t offset; 867109313Sobrien u_int64_t entsize; 868109313Sobrien u_int64_t size; 869109313Sobrien int64_t tag; 870109313Sobrien u_int64_t ptr; 871109313Sobrien u_int64_t val; 872109313Sobrien void *d; 873109313Sobrien int i; 874109313Sobrien 875109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 876109313Sobrien entsize = elf_get_size(e, sh, SH_ENTSIZE); 877109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 878109313Sobrien fprintf(out, "\ndynamic:\n"); 879110256Sobrien for (i = 0; (u_int64_t)i < size / entsize; i++) { 880110256Sobrien d = (char *)e + offset + i * entsize; 881109313Sobrien tag = elf_get_size(e, d, D_TAG); 882109313Sobrien ptr = elf_get_size(e, d, D_PTR); 883109313Sobrien val = elf_get_addr(e, d, D_VAL); 884109313Sobrien fprintf(out, "\n"); 885109313Sobrien fprintf(out, "entry: %d\n", i); 886109332Sobrien fprintf(out, "\td_tag: %s\n", d_tags(tag)); 887109313Sobrien switch (tag) { 888109313Sobrien case DT_NEEDED: 889109313Sobrien case DT_SONAME: 890109313Sobrien case DT_RPATH: 891109313Sobrien fprintf(out, "\td_val: %s\n", dynstr + val); 892109313Sobrien break; 893109313Sobrien case DT_PLTRELSZ: 894109313Sobrien case DT_RELA: 895109313Sobrien case DT_RELASZ: 896109313Sobrien case DT_RELAENT: 897109313Sobrien case DT_STRSZ: 898109313Sobrien case DT_SYMENT: 899109313Sobrien case DT_RELSZ: 900109313Sobrien case DT_RELENT: 901109313Sobrien case DT_PLTREL: 902110257Sobrien fprintf(out, "\td_val: %jd\n", (intmax_t)val); 903109313Sobrien break; 904109313Sobrien case DT_PLTGOT: 905109313Sobrien case DT_HASH: 906109313Sobrien case DT_STRTAB: 907109313Sobrien case DT_SYMTAB: 908109313Sobrien case DT_INIT: 909109313Sobrien case DT_FINI: 910109313Sobrien case DT_REL: 911109313Sobrien case DT_JMPREL: 912110257Sobrien fprintf(out, "\td_ptr: %#jx\n", ptr); 913109313Sobrien break; 914109313Sobrien case DT_NULL: 915109313Sobrien case DT_SYMBOLIC: 916109313Sobrien case DT_DEBUG: 917109313Sobrien case DT_TEXTREL: 918109313Sobrien break; 919109313Sobrien } 920109313Sobrien } 921109313Sobrien} 922109313Sobrien 923241737Sedstatic void 924110252Sobrienelf_print_rela(Elf32_Ehdr *e, void *sh) 925109313Sobrien{ 926109313Sobrien u_int64_t offset; 927109313Sobrien u_int64_t entsize; 928109313Sobrien u_int64_t size; 929109313Sobrien u_int64_t name; 930109313Sobrien u_int64_t info; 931109313Sobrien int64_t addend; 932109313Sobrien void *ra; 933109313Sobrien void *v; 934109313Sobrien int i; 935109313Sobrien 936109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 937109313Sobrien entsize = elf_get_size(e, sh, SH_ENTSIZE); 938109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 939109313Sobrien name = elf_get_word(e, sh, SH_NAME); 940110256Sobrien v = (char *)e + offset; 941109313Sobrien fprintf(out, "\nrelocation with addend (%s):\n", shstrtab + name); 942110256Sobrien for (i = 0; (u_int64_t)i < size / entsize; i++) { 943110256Sobrien ra = (char *)v + i * entsize; 944109313Sobrien offset = elf_get_addr(e, ra, RA_OFFSET); 945109313Sobrien info = elf_get_word(e, ra, RA_INFO); 946109313Sobrien addend = elf_get_off(e, ra, RA_ADDEND); 947109313Sobrien fprintf(out, "\n"); 948109313Sobrien fprintf(out, "entry: %d\n", i); 949110257Sobrien fprintf(out, "\tr_offset: %#jx\n", offset); 950110257Sobrien fprintf(out, "\tr_info: %jd\n", (intmax_t)info); 951110257Sobrien fprintf(out, "\tr_addend: %jd\n", (intmax_t)addend); 952109313Sobrien } 953109313Sobrien} 954109313Sobrien 955241737Sedstatic void 956110252Sobrienelf_print_rel(Elf32_Ehdr *e, void *sh) 957109313Sobrien{ 958109313Sobrien u_int64_t offset; 959109313Sobrien u_int64_t entsize; 960109313Sobrien u_int64_t size; 961109313Sobrien u_int64_t name; 962109313Sobrien u_int64_t info; 963109313Sobrien void *r; 964109313Sobrien void *v; 965109313Sobrien int i; 966109313Sobrien 967109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 968109313Sobrien entsize = elf_get_size(e, sh, SH_ENTSIZE); 969109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 970109313Sobrien name = elf_get_word(e, sh, SH_NAME); 971110256Sobrien v = (char *)e + offset; 972109313Sobrien fprintf(out, "\nrelocation (%s):\n", shstrtab + name); 973110256Sobrien for (i = 0; (u_int64_t)i < size / entsize; i++) { 974110256Sobrien r = (char *)v + i * entsize; 975109313Sobrien offset = elf_get_addr(e, r, R_OFFSET); 976109313Sobrien info = elf_get_word(e, r, R_INFO); 977109313Sobrien fprintf(out, "\n"); 978109313Sobrien fprintf(out, "entry: %d\n", i); 979110257Sobrien fprintf(out, "\tr_offset: %#jx\n", offset); 980110257Sobrien fprintf(out, "\tr_info: %jd\n", (intmax_t)info); 981109313Sobrien } 982109313Sobrien} 983109313Sobrien 984241737Sedstatic void 985110252Sobrienelf_print_interp(Elf32_Ehdr *e, void *p) 986109313Sobrien{ 987109313Sobrien u_int64_t offset; 988109313Sobrien char *s; 989109313Sobrien 990109313Sobrien offset = elf_get_off(e, p, P_OFFSET); 991110252Sobrien s = (char *)e + offset; 992109313Sobrien fprintf(out, "\ninterp:\n"); 993109313Sobrien fprintf(out, "\t%s\n", s); 994109313Sobrien} 995109313Sobrien 996241737Sedstatic void 997110252Sobrienelf_print_got(Elf32_Ehdr *e, void *sh) 998109313Sobrien{ 999109313Sobrien u_int64_t offset; 1000109313Sobrien u_int64_t addralign; 1001109313Sobrien u_int64_t size; 1002109313Sobrien u_int64_t addr; 1003109313Sobrien void *v; 1004109313Sobrien int i; 1005109313Sobrien 1006109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 1007109313Sobrien addralign = elf_get_size(e, sh, SH_ADDRALIGN); 1008109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 1009110256Sobrien v = (char *)e + offset; 1010109313Sobrien fprintf(out, "\nglobal offset table:\n"); 1011110256Sobrien for (i = 0; (u_int64_t)i < size / addralign; i++) { 1012110256Sobrien addr = elf_get_addr(e, (char *)v + i * addralign, 0); 1013109313Sobrien fprintf(out, "\n"); 1014109313Sobrien fprintf(out, "entry: %d\n", i); 1015110257Sobrien fprintf(out, "\t%#jx\n", addr); 1016109313Sobrien } 1017109313Sobrien} 1018109313Sobrien 1019241737Sedstatic void 1020110256Sobrienelf_print_hash(Elf32_Ehdr *e __unused, void *sh __unused) 1021109313Sobrien{ 1022109313Sobrien} 1023109313Sobrien 1024241737Sedstatic void 1025110252Sobrienelf_print_note(Elf32_Ehdr *e, void *sh) 1026109313Sobrien{ 1027109313Sobrien u_int64_t offset; 1028109313Sobrien u_int64_t size; 1029109313Sobrien u_int64_t name; 1030109313Sobrien u_int32_t namesz; 1031109313Sobrien u_int32_t descsz; 1032109313Sobrien u_int32_t desc; 1033110256Sobrien char *n, *s; 1034109313Sobrien 1035109313Sobrien offset = elf_get_off(e, sh, SH_OFFSET); 1036109313Sobrien size = elf_get_size(e, sh, SH_SIZE); 1037109313Sobrien name = elf_get_word(e, sh, SH_NAME); 1038110256Sobrien n = (char *)e + offset; 1039109313Sobrien fprintf(out, "\nnote (%s):\n", shstrtab + name); 1040110256Sobrien while (n < ((char *)e + offset + size)) { 1041109313Sobrien namesz = elf_get_word(e, n, N_NAMESZ); 1042109313Sobrien descsz = elf_get_word(e, n, N_DESCSZ); 1043110256Sobrien s = n + sizeof(Elf_Note); 1044110256Sobrien desc = elf_get_word(e, n + sizeof(Elf_Note) + namesz, 0); 1045109313Sobrien fprintf(out, "\t%s %d\n", s, desc); 1046109313Sobrien n += sizeof(Elf_Note) + namesz + descsz; 1047109313Sobrien } 1048109313Sobrien} 1049109313Sobrien 1050241737Sedstatic u_int64_t 1051109313Sobrienelf_get_byte(Elf32_Ehdr *e, void *base, elf_member_t member) 1052109313Sobrien{ 1053109313Sobrien u_int64_t val; 1054109313Sobrien 1055109313Sobrien val = 0; 1056109313Sobrien switch (e->e_ident[EI_CLASS]) { 1057109313Sobrien case ELFCLASS32: 1058226434Smarcel val = ((uint8_t *)base)[elf32_offsets[member]]; 1059109313Sobrien break; 1060109313Sobrien case ELFCLASS64: 1061226434Smarcel val = ((uint8_t *)base)[elf64_offsets[member]]; 1062109313Sobrien break; 1063109313Sobrien case ELFCLASSNONE: 1064109313Sobrien errx(1, "invalid class"); 1065109313Sobrien } 1066109313Sobrien 1067109313Sobrien return val; 1068109313Sobrien} 1069109313Sobrien 1070241737Sedstatic u_int64_t 1071109313Sobrienelf_get_quarter(Elf32_Ehdr *e, void *base, elf_member_t member) 1072109313Sobrien{ 1073109313Sobrien u_int64_t val; 1074109313Sobrien 1075109313Sobrien val = 0; 1076109313Sobrien switch (e->e_ident[EI_CLASS]) { 1077109313Sobrien case ELFCLASS32: 1078118680Smarcel base = (char *)base + elf32_offsets[member]; 1079109313Sobrien switch (e->e_ident[EI_DATA]) { 1080109313Sobrien case ELFDATA2MSB: 1081118680Smarcel val = be16dec(base); 1082109313Sobrien break; 1083109313Sobrien case ELFDATA2LSB: 1084118680Smarcel val = le16dec(base); 1085109313Sobrien break; 1086109313Sobrien case ELFDATANONE: 1087109313Sobrien errx(1, "invalid data format"); 1088109313Sobrien } 1089109313Sobrien break; 1090109313Sobrien case ELFCLASS64: 1091118680Smarcel base = (char *)base + elf64_offsets[member]; 1092109313Sobrien switch (e->e_ident[EI_DATA]) { 1093109313Sobrien case ELFDATA2MSB: 1094118680Smarcel val = be16dec(base); 1095109313Sobrien break; 1096109313Sobrien case ELFDATA2LSB: 1097118680Smarcel val = le16dec(base); 1098109313Sobrien break; 1099109313Sobrien case ELFDATANONE: 1100109313Sobrien errx(1, "invalid data format"); 1101109313Sobrien } 1102109313Sobrien break; 1103109313Sobrien case ELFCLASSNONE: 1104109313Sobrien errx(1, "invalid class"); 1105109313Sobrien } 1106109313Sobrien 1107109313Sobrien return val; 1108109313Sobrien} 1109109313Sobrien 1110241737Sed#if 0 1111241737Sedstatic u_int64_t 1112109313Sobrienelf_get_half(Elf32_Ehdr *e, void *base, elf_member_t member) 1113109313Sobrien{ 1114109313Sobrien u_int64_t val; 1115109313Sobrien 1116109313Sobrien val = 0; 1117109313Sobrien switch (e->e_ident[EI_CLASS]) { 1118109313Sobrien case ELFCLASS32: 1119118680Smarcel base = (char *)base + elf32_offsets[member]; 1120109313Sobrien switch (e->e_ident[EI_DATA]) { 1121109313Sobrien case ELFDATA2MSB: 1122118680Smarcel val = be16dec(base); 1123109313Sobrien break; 1124109313Sobrien case ELFDATA2LSB: 1125118680Smarcel val = le16dec(base); 1126109313Sobrien break; 1127109313Sobrien case ELFDATANONE: 1128109313Sobrien errx(1, "invalid data format"); 1129109313Sobrien } 1130109313Sobrien break; 1131109313Sobrien case ELFCLASS64: 1132118680Smarcel base = (char *)base + elf64_offsets[member]; 1133109313Sobrien switch (e->e_ident[EI_DATA]) { 1134109313Sobrien case ELFDATA2MSB: 1135118680Smarcel val = be32dec(base); 1136109313Sobrien break; 1137109313Sobrien case ELFDATA2LSB: 1138118680Smarcel val = le32dec(base); 1139109313Sobrien break; 1140109313Sobrien case ELFDATANONE: 1141109313Sobrien errx(1, "invalid data format"); 1142109313Sobrien } 1143109313Sobrien break; 1144109313Sobrien case ELFCLASSNONE: 1145109313Sobrien errx(1, "invalid class"); 1146109313Sobrien } 1147109313Sobrien 1148109313Sobrien return val; 1149109313Sobrien} 1150241737Sed#endif 1151109313Sobrien 1152241737Sedstatic u_int64_t 1153109313Sobrienelf_get_word(Elf32_Ehdr *e, void *base, elf_member_t member) 1154109313Sobrien{ 1155109313Sobrien u_int64_t val; 1156109313Sobrien 1157109313Sobrien val = 0; 1158109313Sobrien switch (e->e_ident[EI_CLASS]) { 1159109313Sobrien case ELFCLASS32: 1160118680Smarcel base = (char *)base + elf32_offsets[member]; 1161109313Sobrien switch (e->e_ident[EI_DATA]) { 1162109313Sobrien case ELFDATA2MSB: 1163118680Smarcel val = be32dec(base); 1164109313Sobrien break; 1165109313Sobrien case ELFDATA2LSB: 1166118680Smarcel val = le32dec(base); 1167109313Sobrien break; 1168109313Sobrien case ELFDATANONE: 1169109313Sobrien errx(1, "invalid data format"); 1170109313Sobrien } 1171109313Sobrien break; 1172109313Sobrien case ELFCLASS64: 1173118680Smarcel base = (char *)base + elf64_offsets[member]; 1174109313Sobrien switch (e->e_ident[EI_DATA]) { 1175109313Sobrien case ELFDATA2MSB: 1176118680Smarcel val = be32dec(base); 1177109313Sobrien break; 1178109313Sobrien case ELFDATA2LSB: 1179118680Smarcel val = le32dec(base); 1180109313Sobrien break; 1181109313Sobrien case ELFDATANONE: 1182109313Sobrien errx(1, "invalid data format"); 1183109313Sobrien } 1184109313Sobrien break; 1185109313Sobrien case ELFCLASSNONE: 1186109313Sobrien errx(1, "invalid class"); 1187109313Sobrien } 1188109313Sobrien 1189109313Sobrien return val; 1190109313Sobrien} 1191109313Sobrien 1192241737Sedstatic u_int64_t 1193109313Sobrienelf_get_quad(Elf32_Ehdr *e, void *base, elf_member_t member) 1194109313Sobrien{ 1195109313Sobrien u_int64_t val; 1196109313Sobrien 1197109313Sobrien val = 0; 1198109313Sobrien switch (e->e_ident[EI_CLASS]) { 1199109313Sobrien case ELFCLASS32: 1200118680Smarcel base = (char *)base + elf32_offsets[member]; 1201109313Sobrien switch (e->e_ident[EI_DATA]) { 1202109313Sobrien case ELFDATA2MSB: 1203118680Smarcel val = be32dec(base); 1204109313Sobrien break; 1205109313Sobrien case ELFDATA2LSB: 1206118680Smarcel val = le32dec(base); 1207109313Sobrien break; 1208109313Sobrien case ELFDATANONE: 1209109313Sobrien errx(1, "invalid data format"); 1210109313Sobrien } 1211109313Sobrien break; 1212109313Sobrien case ELFCLASS64: 1213118680Smarcel base = (char *)base + elf64_offsets[member]; 1214109313Sobrien switch (e->e_ident[EI_DATA]) { 1215109313Sobrien case ELFDATA2MSB: 1216118680Smarcel val = be64dec(base); 1217109313Sobrien break; 1218109313Sobrien case ELFDATA2LSB: 1219118680Smarcel val = le64dec(base); 1220109313Sobrien break; 1221109313Sobrien case ELFDATANONE: 1222109313Sobrien errx(1, "invalid data format"); 1223109313Sobrien } 1224109313Sobrien break; 1225109313Sobrien case ELFCLASSNONE: 1226109313Sobrien errx(1, "invalid class"); 1227109313Sobrien } 1228109313Sobrien 1229109313Sobrien return val; 1230109313Sobrien} 1231109313Sobrien 1232241737Sedstatic void 1233109313Sobrienusage(void) 1234109313Sobrien{ 1235117009Sru fprintf(stderr, "usage: elfdump -a | -cdeGhinprs [-w file] file\n"); 1236109313Sobrien exit(1); 1237109313Sobrien} 1238