Path: blob/main/contrib/elftoolchain/readelf/readelf.c
39536 views
/*-1* Copyright (c) 2009-2015 Kai Wang2* All rights reserved.3*4* Redistribution and use in source and binary forms, with or without5* modification, are permitted provided that the following conditions6* are met:7* 1. Redistributions of source code must retain the above copyright8* notice, this list of conditions and the following disclaimer.9* 2. Redistributions in binary form must reproduce the above copyright10* notice, this list of conditions and the following disclaimer in the11* documentation and/or other materials provided with the distribution.12*13* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND14* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE15* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE16* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE17* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL18* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS19* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)20* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT21* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY22* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF23* SUCH DAMAGE.24*/2526#include <sys/param.h>27#include <sys/queue.h>2829#include <ar.h>30#include <assert.h>31#include <capsicum_helpers.h>32#include <ctype.h>33#include <dwarf.h>34#include <err.h>35#include <fcntl.h>36#include <gelf.h>37#include <getopt.h>38#include <libdwarf.h>39#include <libelftc.h>40#include <libgen.h>41#include <stdarg.h>42#include <stdbool.h>43#include <stdint.h>44#include <stdio.h>45#include <stdlib.h>46#include <string.h>47#include <time.h>48#include <unistd.h>49#include <zlib.h>5051#include <libcasper.h>52#include <casper/cap_fileargs.h>5354#include "_elftc.h"5556ELFTC_VCSID("$Id: readelf.c 3769 2019-06-29 15:15:02Z emaste $");5758/* Backwards compatability for older FreeBSD releases. */59#ifndef STB_GNU_UNIQUE60#define STB_GNU_UNIQUE 1061#endif62#ifndef STT_SPARC_REGISTER63#define STT_SPARC_REGISTER 1364#endif656667/*68* readelf(1) options.69*/70#define RE_AA 0x0000000171#define RE_C 0x0000000272#define RE_DD 0x0000000473#define RE_D 0x0000000874#define RE_G 0x0000001075#define RE_H 0x0000002076#define RE_II 0x0000004077#define RE_I 0x0000008078#define RE_L 0x0000010079#define RE_NN 0x0000020080#define RE_N 0x0000040081#define RE_P 0x0000080082#define RE_R 0x0000100083#define RE_SS 0x0000200084#define RE_S 0x0000400085#define RE_T 0x0000800086#define RE_U 0x0001000087#define RE_VV 0x0002000088#define RE_WW 0x0004000089#define RE_W 0x0008000090#define RE_X 0x0010000091#define RE_Z 0x002000009293/*94* dwarf dump options.95*/96#define DW_A 0x0000000197#define DW_FF 0x0000000298#define DW_F 0x0000000499#define DW_I 0x00000008100#define DW_LL 0x00000010101#define DW_L 0x00000020102#define DW_M 0x00000040103#define DW_O 0x00000080104#define DW_P 0x00000100105#define DW_RR 0x00000200106#define DW_R 0x00000400107#define DW_S 0x00000800108109#define DW_DEFAULT_OPTIONS (DW_A | DW_F | DW_I | DW_L | DW_O | DW_P | \110DW_R | DW_RR | DW_S)111112/*113* readelf(1) run control flags.114*/115#define DISPLAY_FILENAME 0x0001116117/*118* Internal data structure for sections.119*/120struct section {121const char *name; /* section name */122Elf_Scn *scn; /* section scn */123uint64_t off; /* section offset */124uint64_t sz; /* section size */125uint64_t entsize; /* section entsize */126uint64_t align; /* section alignment */127uint64_t type; /* section type */128uint64_t flags; /* section flags */129uint64_t addr; /* section virtual addr */130uint32_t link; /* section link ndx */131uint32_t info; /* section info ndx */132};133134struct dumpop {135union {136size_t si; /* section index */137const char *sn; /* section name */138} u;139enum {140DUMP_BY_INDEX = 0,141DUMP_BY_NAME142} type; /* dump type */143#define HEX_DUMP 0x0001144#define STR_DUMP 0x0002145int op; /* dump operation */146STAILQ_ENTRY(dumpop) dumpop_list;147};148149struct symver {150const char *name;151int type;152};153154/*155* Structure encapsulates the global data for readelf(1).156*/157struct readelf {158const char *filename; /* current processing file. */159int options; /* command line options. */160int flags; /* run control flags. */161int dop; /* dwarf dump options. */162Elf *elf; /* underlying ELF descriptor. */163Elf *ar; /* archive ELF descriptor. */164Dwarf_Debug dbg; /* DWARF handle. */165Dwarf_Half cu_psize; /* DWARF CU pointer size. */166Dwarf_Half cu_osize; /* DWARF CU offset size. */167Dwarf_Half cu_ver; /* DWARF CU version. */168GElf_Ehdr ehdr; /* ELF header. */169int ec; /* ELF class. */170size_t shnum; /* #sections. */171struct section *vd_s; /* Verdef section. */172struct section *vn_s; /* Verneed section. */173struct section *vs_s; /* Versym section. */174uint16_t *vs; /* Versym array. */175int vs_sz; /* Versym array size. */176struct symver *ver; /* Version array. */177int ver_sz; /* Size of version array. */178struct section *sl; /* list of sections. */179STAILQ_HEAD(, dumpop) v_dumpop; /* list of dump ops. */180uint64_t (*dw_read)(Elf_Data *, uint64_t *, int);181uint64_t (*dw_decode)(uint8_t **, int);182};183184enum options185{186OPTION_DEBUG_DUMP187};188189static struct option longopts[] = {190{"all", no_argument, NULL, 'a'},191{"arch-specific", no_argument, NULL, 'A'},192{"archive-index", no_argument, NULL, 'c'},193{"debug-dump", optional_argument, NULL, OPTION_DEBUG_DUMP},194{"decompress", no_argument, 0, 'z'},195{"dynamic", no_argument, NULL, 'd'},196{"file-header", no_argument, NULL, 'h'},197{"full-section-name", no_argument, NULL, 'N'},198{"headers", no_argument, NULL, 'e'},199{"help", no_argument, 0, 'H'},200{"hex-dump", required_argument, NULL, 'x'},201{"histogram", no_argument, NULL, 'I'},202{"notes", no_argument, NULL, 'n'},203{"program-headers", no_argument, NULL, 'l'},204{"relocs", no_argument, NULL, 'r'},205{"sections", no_argument, NULL, 'S'},206{"section-headers", no_argument, NULL, 'S'},207{"section-groups", no_argument, NULL, 'g'},208{"section-details", no_argument, NULL, 't'},209{"segments", no_argument, NULL, 'l'},210{"string-dump", required_argument, NULL, 'p'},211{"symbols", no_argument, NULL, 's'},212{"syms", no_argument, NULL, 's'},213{"unwind", no_argument, NULL, 'u'},214{"use-dynamic", no_argument, NULL, 'D'},215{"version-info", no_argument, 0, 'V'},216{"version", no_argument, 0, 'v'},217{"wide", no_argument, 0, 'W'},218{NULL, 0, NULL, 0}219};220221struct eflags_desc {222uint64_t flag;223const char *desc;224};225226struct flag_desc {227uint64_t flag;228const char *desc;229};230231struct flag_desc_list {232uint32_t type;233const char *desc_str;234struct flag_desc *desc;235};236237struct mips_option {238uint64_t flag;239const char *desc;240};241242struct loc_at {243Dwarf_Attribute la_at;244Dwarf_Unsigned la_off;245Dwarf_Unsigned la_lowpc;246Dwarf_Half la_cu_psize;247Dwarf_Half la_cu_osize;248Dwarf_Half la_cu_ver;249};250251static void add_dumpop(struct readelf *re, size_t si, const char *sn, int op,252int t);253static const char *aeabi_adv_simd_arch(uint64_t simd);254static const char *aeabi_align_needed(uint64_t an);255static const char *aeabi_align_preserved(uint64_t ap);256static const char *aeabi_arm_isa(uint64_t ai);257static const char *aeabi_cpu_arch(uint64_t arch);258static const char *aeabi_cpu_arch_profile(uint64_t pf);259static const char *aeabi_div(uint64_t du);260static const char *aeabi_enum_size(uint64_t es);261static const char *aeabi_fp_16bit_format(uint64_t fp16);262static const char *aeabi_fp_arch(uint64_t fp);263static const char *aeabi_fp_denormal(uint64_t fd);264static const char *aeabi_fp_exceptions(uint64_t fe);265static const char *aeabi_fp_hpext(uint64_t fh);266static const char *aeabi_fp_number_model(uint64_t fn);267static const char *aeabi_fp_optm_goal(uint64_t fog);268static const char *aeabi_fp_rounding(uint64_t fr);269static const char *aeabi_hardfp(uint64_t hfp);270static const char *aeabi_mpext(uint64_t mp);271static const char *aeabi_optm_goal(uint64_t og);272static const char *aeabi_pcs_config(uint64_t pcs);273static const char *aeabi_pcs_got(uint64_t got);274static const char *aeabi_pcs_r9(uint64_t r9);275static const char *aeabi_pcs_ro(uint64_t ro);276static const char *aeabi_pcs_rw(uint64_t rw);277static const char *aeabi_pcs_wchar_t(uint64_t wt);278static const char *aeabi_t2ee(uint64_t t2ee);279static const char *aeabi_thumb_isa(uint64_t ti);280static const char *aeabi_fp_user_exceptions(uint64_t fu);281static const char *aeabi_unaligned_access(uint64_t ua);282static const char *aeabi_vfp_args(uint64_t va);283static const char *aeabi_virtual(uint64_t vt);284static const char *aeabi_wmmx_arch(uint64_t wmmx);285static const char *aeabi_wmmx_args(uint64_t wa);286static const char *elf_class(unsigned int class);287static const char *elf_endian(unsigned int endian);288static const char *elf_machine(unsigned int mach);289static const char *elf_osabi(unsigned int abi);290static const char *elf_type(unsigned int type);291static const char *elf_ver(unsigned int ver);292static const char *dt_type(unsigned int mach, unsigned int dtype);293static bool dump_ar(struct readelf *re, int);294static void dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe);295static void dump_attributes(struct readelf *re);296static uint8_t *dump_compatibility_tag(uint8_t *p, uint8_t *pe);297static void dump_dwarf(struct readelf *re);298static void dump_dwarf_abbrev(struct readelf *re);299static void dump_dwarf_aranges(struct readelf *re);300static void dump_dwarf_block(struct readelf *re, uint8_t *b,301Dwarf_Unsigned len);302static void dump_dwarf_die(struct readelf *re, Dwarf_Die die, int level);303static void dump_dwarf_frame(struct readelf *re, int alt);304static void dump_dwarf_frame_inst(struct readelf *re, Dwarf_Cie cie,305uint8_t *insts, Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf,306Dwarf_Addr pc, Dwarf_Debug dbg);307static int dump_dwarf_frame_regtable(struct readelf *re, Dwarf_Fde fde,308Dwarf_Addr pc, Dwarf_Unsigned func_len, Dwarf_Half cie_ra);309static void dump_dwarf_frame_section(struct readelf *re, struct section *s,310int alt);311static void dump_dwarf_info(struct readelf *re, Dwarf_Bool is_info);312static void dump_dwarf_macinfo(struct readelf *re);313static void dump_dwarf_line(struct readelf *re);314static void dump_dwarf_line_decoded(struct readelf *re);315static void dump_dwarf_loc(struct readelf *re, Dwarf_Loc *lr);316static void dump_dwarf_loclist(struct readelf *re);317static void dump_dwarf_pubnames(struct readelf *re);318static void dump_dwarf_ranges(struct readelf *re);319static void dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die,320Dwarf_Addr base);321static void dump_dwarf_str(struct readelf *re);322static void dump_eflags(struct readelf *re, uint64_t e_flags);323static bool dump_elf(struct readelf *re);324static void dump_flags(struct flag_desc *fd, uint64_t flags);325static void dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab);326static void dump_dynamic(struct readelf *re);327static void dump_liblist(struct readelf *re);328static void dump_mips_abiflags(struct readelf *re, struct section *s);329static void dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe);330static void dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz);331static void dump_mips_options(struct readelf *re, struct section *s);332static void dump_mips_option_flags(const char *name, struct mips_option *opt,333uint64_t info);334static void dump_mips_reginfo(struct readelf *re, struct section *s);335static void dump_mips_specific_info(struct readelf *re);336static void dump_notes(struct readelf *re);337static void dump_notes_content(struct readelf *re, const char *buf, size_t sz,338off_t off);339static void dump_notes_data(struct readelf *re, const char *name,340uint32_t type, const char *buf, size_t sz);341static void dump_svr4_hash(struct section *s);342static void dump_svr4_hash64(struct readelf *re, struct section *s);343static void dump_gnu_hash(struct readelf *re, struct section *s);344static void dump_gnu_property_type_0(struct readelf *re, const char *buf,345size_t sz);346static void dump_hash(struct readelf *re);347static void dump_phdr(struct readelf *re);348static void dump_ppc_attributes(uint8_t *p, uint8_t *pe);349static void dump_section_groups(struct readelf *re);350static void dump_symtab(struct readelf *re, int i);351static void dump_symtabs(struct readelf *re);352static uint8_t *dump_unknown_tag(uint64_t tag, uint8_t *p, uint8_t *pe);353static void dump_ver(struct readelf *re);354static void dump_verdef(struct readelf *re, int dump);355static void dump_verneed(struct readelf *re, int dump);356static void dump_versym(struct readelf *re);357static const char *dwarf_reg(unsigned int mach, unsigned int reg);358static const char *dwarf_regname(struct readelf *re, unsigned int num);359static struct dumpop *find_dumpop(struct readelf *re, size_t si,360const char *sn, int op, int t);361static int get_ent_count(struct section *s, int *ent_count);362static int get_mips_register_size(uint8_t flag);363static char *get_regoff_str(struct readelf *re, Dwarf_Half reg,364Dwarf_Addr off);365static const char *get_string(struct readelf *re, int strtab, size_t off);366static const char *get_symbol_name(struct readelf *re, int symtab, int i);367static uint64_t get_symbol_value(struct readelf *re, int symtab, int i);368static void load_sections(struct readelf *re);369static int loc_at_comparator(const void *la1, const void *la2);370static const char *mips_abi_fp(uint64_t fp);371static const char *note_type(const char *note_name, unsigned int et,372unsigned int nt);373static const char *note_type_freebsd(unsigned int nt);374static const char *note_type_freebsd_core(unsigned int nt);375static const char *note_type_go(unsigned int nt);376static const char *note_type_gnu(unsigned int nt);377static const char *note_type_linux_core(unsigned int nt);378static const char *note_type_netbsd(unsigned int nt);379static const char *note_type_openbsd(unsigned int nt);380static const char *note_type_unknown(unsigned int nt);381static const char *note_type_xen(unsigned int nt);382static const char *option_kind(uint8_t kind);383static const char *phdr_type(unsigned int mach, unsigned int ptype);384static const char *ppc_abi_fp(uint64_t fp);385static const char *ppc_abi_vector(uint64_t vec);386static void readelf_usage(int status);387static void readelf_version(void);388static void search_loclist_at(struct readelf *re, Dwarf_Die die,389Dwarf_Unsigned lowpc, struct loc_at **la_list,390size_t *la_list_len, size_t *la_list_cap);391static void search_ver(struct readelf *re);392static const char *section_type(unsigned int mach, unsigned int stype);393static void set_cu_context(struct readelf *re, Dwarf_Half psize,394Dwarf_Half osize, Dwarf_Half ver);395static const char *st_bind(unsigned int sbind);396static const char *st_shndx(unsigned int shndx);397static const char *st_type(unsigned int mach, unsigned int os,398unsigned int stype);399static const char *st_vis(unsigned int svis);400static const char *top_tag(unsigned int tag);401static void unload_sections(struct readelf *re);402static uint64_t _read_lsb(Elf_Data *d, uint64_t *offsetp,403int bytes_to_read);404static uint64_t _read_msb(Elf_Data *d, uint64_t *offsetp,405int bytes_to_read);406static uint64_t _decode_lsb(uint8_t **data, int bytes_to_read);407static uint64_t _decode_msb(uint8_t **data, int bytes_to_read);408static int64_t _decode_sleb128(uint8_t **dp, uint8_t *dpe);409static uint64_t _decode_uleb128(uint8_t **dp, uint8_t *dpe);410411static struct eflags_desc arm_eflags_desc[] = {412{EF_ARM_RELEXEC, "relocatable executable"},413{EF_ARM_HASENTRY, "has entry point"},414{EF_ARM_SYMSARESORTED, "sorted symbol tables"},415{EF_ARM_DYNSYMSUSESEGIDX, "dynamic symbols use segment index"},416{EF_ARM_MAPSYMSFIRST, "mapping symbols precede others"},417{EF_ARM_BE8, "BE8"},418{EF_ARM_LE8, "LE8"},419{EF_ARM_INTERWORK, "interworking enabled"},420{EF_ARM_APCS_26, "uses APCS/26"},421{EF_ARM_APCS_FLOAT, "uses APCS/float"},422{EF_ARM_PIC, "position independent"},423{EF_ARM_ALIGN8, "8 bit structure alignment"},424{EF_ARM_NEW_ABI, "uses new ABI"},425{EF_ARM_OLD_ABI, "uses old ABI"},426{EF_ARM_SOFT_FLOAT, "software FP"},427{EF_ARM_VFP_FLOAT, "VFP"},428{EF_ARM_MAVERICK_FLOAT, "Maverick FP"},429{0, NULL}430};431432static struct eflags_desc mips_eflags_desc[] = {433{EF_MIPS_NOREORDER, "noreorder"},434{EF_MIPS_PIC, "pic"},435{EF_MIPS_CPIC, "cpic"},436{EF_MIPS_UCODE, "ugen_reserved"},437{EF_MIPS_ABI2, "abi2"},438{EF_MIPS_OPTIONS_FIRST, "odk first"},439{EF_MIPS_ARCH_ASE_MDMX, "mdmx"},440{EF_MIPS_ARCH_ASE_M16, "mips16"},441{0, NULL}442};443444static struct eflags_desc powerpc_eflags_desc[] = {445{EF_PPC_EMB, "emb"},446{EF_PPC_RELOCATABLE, "relocatable"},447{EF_PPC_RELOCATABLE_LIB, "relocatable-lib"},448{0, NULL}449};450451static struct eflags_desc riscv_eflags_desc[] = {452{EF_RISCV_RVC, "RVC"},453{EF_RISCV_RVE, "RVE"},454{EF_RISCV_TSO, "TSO"},455{0, NULL}456};457458static struct eflags_desc sparc_eflags_desc[] = {459{EF_SPARC_32PLUS, "v8+"},460{EF_SPARC_SUN_US1, "ultrasparcI"},461{EF_SPARC_HAL_R1, "halr1"},462{EF_SPARC_SUN_US3, "ultrasparcIII"},463{0, NULL}464};465466static const char *467elf_osabi(unsigned int abi)468{469static char s_abi[32];470471switch(abi) {472case ELFOSABI_NONE: return "NONE";473case ELFOSABI_HPUX: return "HPUX";474case ELFOSABI_NETBSD: return "NetBSD";475case ELFOSABI_GNU: return "GNU";476case ELFOSABI_HURD: return "HURD";477case ELFOSABI_86OPEN: return "86OPEN";478case ELFOSABI_SOLARIS: return "Solaris";479case ELFOSABI_AIX: return "AIX";480case ELFOSABI_IRIX: return "IRIX";481case ELFOSABI_FREEBSD: return "FreeBSD";482case ELFOSABI_TRU64: return "TRU64";483case ELFOSABI_MODESTO: return "MODESTO";484case ELFOSABI_OPENBSD: return "OpenBSD";485case ELFOSABI_OPENVMS: return "OpenVMS";486case ELFOSABI_NSK: return "NSK";487case ELFOSABI_CLOUDABI: return "CloudABI";488case ELFOSABI_ARM_AEABI: return "ARM EABI";489case ELFOSABI_ARM: return "ARM";490case ELFOSABI_STANDALONE: return "StandAlone";491default:492snprintf(s_abi, sizeof(s_abi), "<unknown: %#x>", abi);493return (s_abi);494}495};496497static const char *498elf_machine(unsigned int mach)499{500static char s_mach[32];501502switch (mach) {503case EM_NONE: return "Unknown machine";504case EM_M32: return "AT&T WE32100";505case EM_SPARC: return "Sun SPARC";506case EM_386: return "Intel i386";507case EM_68K: return "Motorola 68000";508case EM_IAMCU: return "Intel MCU";509case EM_88K: return "Motorola 88000";510case EM_860: return "Intel i860";511case EM_MIPS: return "MIPS R3000 Big-Endian only";512case EM_S370: return "IBM System/370";513case EM_MIPS_RS3_LE: return "MIPS R3000 Little-Endian";514case EM_PARISC: return "HP PA-RISC";515case EM_VPP500: return "Fujitsu VPP500";516case EM_SPARC32PLUS: return "SPARC v8plus";517case EM_960: return "Intel 80960";518case EM_PPC: return "PowerPC 32-bit";519case EM_PPC64: return "PowerPC 64-bit";520case EM_S390: return "IBM System/390";521case EM_V800: return "NEC V800";522case EM_FR20: return "Fujitsu FR20";523case EM_RH32: return "TRW RH-32";524case EM_RCE: return "Motorola RCE";525case EM_ARM: return "ARM";526case EM_SH: return "Hitachi SH";527case EM_SPARCV9: return "SPARC v9 64-bit";528case EM_TRICORE: return "Siemens TriCore embedded processor";529case EM_ARC: return "Argonaut RISC Core";530case EM_H8_300: return "Hitachi H8/300";531case EM_H8_300H: return "Hitachi H8/300H";532case EM_H8S: return "Hitachi H8S";533case EM_H8_500: return "Hitachi H8/500";534case EM_IA_64: return "Intel IA-64 Processor";535case EM_MIPS_X: return "Stanford MIPS-X";536case EM_COLDFIRE: return "Motorola ColdFire";537case EM_68HC12: return "Motorola M68HC12";538case EM_MMA: return "Fujitsu MMA";539case EM_PCP: return "Siemens PCP";540case EM_NCPU: return "Sony nCPU";541case EM_NDR1: return "Denso NDR1 microprocessor";542case EM_STARCORE: return "Motorola Star*Core processor";543case EM_ME16: return "Toyota ME16 processor";544case EM_ST100: return "STMicroelectronics ST100 processor";545case EM_TINYJ: return "Advanced Logic Corp. TinyJ processor";546case EM_X86_64: return "Advanced Micro Devices x86-64";547case EM_PDSP: return "Sony DSP Processor";548case EM_FX66: return "Siemens FX66 microcontroller";549case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 microcontroller";550case EM_ST7: return "STmicroelectronics ST7 8-bit microcontroller";551case EM_68HC16: return "Motorola MC68HC16 microcontroller";552case EM_68HC11: return "Motorola MC68HC11 microcontroller";553case EM_68HC08: return "Motorola MC68HC08 microcontroller";554case EM_68HC05: return "Motorola MC68HC05 microcontroller";555case EM_SVX: return "Silicon Graphics SVx";556case EM_ST19: return "STMicroelectronics ST19 8-bit mc";557case EM_VAX: return "Digital VAX";558case EM_CRIS: return "Axis Communications 32-bit embedded processor";559case EM_JAVELIN: return "Infineon Tech. 32bit embedded processor";560case EM_FIREPATH: return "Element 14 64-bit DSP Processor";561case EM_ZSP: return "LSI Logic 16-bit DSP Processor";562case EM_MMIX: return "Donald Knuth's educational 64-bit proc";563case EM_HUANY: return "Harvard University MI object files";564case EM_PRISM: return "SiTera Prism";565case EM_AVR: return "Atmel AVR 8-bit microcontroller";566case EM_FR30: return "Fujitsu FR30";567case EM_D10V: return "Mitsubishi D10V";568case EM_D30V: return "Mitsubishi D30V";569case EM_V850: return "NEC v850";570case EM_M32R: return "Mitsubishi M32R";571case EM_MN10300: return "Matsushita MN10300";572case EM_MN10200: return "Matsushita MN10200";573case EM_PJ: return "picoJava";574case EM_OPENRISC: return "OpenRISC 32-bit embedded processor";575case EM_ARC_A5: return "ARC Cores Tangent-A5";576case EM_XTENSA: return "Tensilica Xtensa Architecture";577case EM_VIDEOCORE: return "Alphamosaic VideoCore processor";578case EM_TMM_GPP: return "Thompson Multimedia General Purpose Processor";579case EM_NS32K: return "National Semiconductor 32000 series";580case EM_TPC: return "Tenor Network TPC processor";581case EM_SNP1K: return "Trebia SNP 1000 processor";582case EM_ST200: return "STMicroelectronics ST200 microcontroller";583case EM_IP2K: return "Ubicom IP2xxx microcontroller family";584case EM_MAX: return "MAX Processor";585case EM_CR: return "National Semiconductor CompactRISC microprocessor";586case EM_F2MC16: return "Fujitsu F2MC16";587case EM_MSP430: return "TI embedded microcontroller msp430";588case EM_BLACKFIN: return "Analog Devices Blackfin (DSP) processor";589case EM_SE_C33: return "S1C33 Family of Seiko Epson processors";590case EM_SEP: return "Sharp embedded microprocessor";591case EM_ARCA: return "Arca RISC Microprocessor";592case EM_UNICORE: return "Microprocessor series from PKU-Unity Ltd";593case EM_AARCH64: return "AArch64";594case EM_RISCV: return "RISC-V";595default:596snprintf(s_mach, sizeof(s_mach), "<unknown: %#x>", mach);597return (s_mach);598}599600}601602static const char *603elf_class(unsigned int class)604{605static char s_class[32];606607switch (class) {608case ELFCLASSNONE: return "none";609case ELFCLASS32: return "ELF32";610case ELFCLASS64: return "ELF64";611default:612snprintf(s_class, sizeof(s_class), "<unknown: %#x>", class);613return (s_class);614}615}616617static const char *618elf_endian(unsigned int endian)619{620static char s_endian[32];621622switch (endian) {623case ELFDATANONE: return "none";624case ELFDATA2LSB: return "2's complement, little endian";625case ELFDATA2MSB: return "2's complement, big endian";626default:627snprintf(s_endian, sizeof(s_endian), "<unknown: %#x>", endian);628return (s_endian);629}630}631632static const char *633elf_type(unsigned int type)634{635static char s_type[32];636637switch (type) {638case ET_NONE: return "NONE (None)";639case ET_REL: return "REL (Relocatable file)";640case ET_EXEC: return "EXEC (Executable file)";641case ET_DYN: return "DYN (Shared object file)";642case ET_CORE: return "CORE (Core file)";643default:644if (type >= ET_LOPROC)645snprintf(s_type, sizeof(s_type), "<proc: %#x>", type);646else if (type >= ET_LOOS && type <= ET_HIOS)647snprintf(s_type, sizeof(s_type), "<os: %#x>", type);648else649snprintf(s_type, sizeof(s_type), "<unknown: %#x>",650type);651return (s_type);652}653}654655static const char *656elf_ver(unsigned int ver)657{658static char s_ver[32];659660switch (ver) {661case EV_CURRENT: return "(current)";662case EV_NONE: return "(none)";663default:664snprintf(s_ver, sizeof(s_ver), "<unknown: %#x>",665ver);666return (s_ver);667}668}669670static const char *671phdr_type(unsigned int mach, unsigned int ptype)672{673static char s_ptype[32];674675if (ptype >= PT_LOPROC && ptype <= PT_HIPROC) {676switch (mach) {677case EM_ARM:678switch (ptype) {679case PT_ARM_ARCHEXT: return "ARM_ARCHEXT";680case PT_ARM_EXIDX: return "ARM_EXIDX";681}682break;683}684snprintf(s_ptype, sizeof(s_ptype), "LOPROC+%#x",685ptype - PT_LOPROC);686return (s_ptype);687}688689switch (ptype) {690case PT_NULL: return "NULL";691case PT_LOAD: return "LOAD";692case PT_DYNAMIC: return "DYNAMIC";693case PT_INTERP: return "INTERP";694case PT_NOTE: return "NOTE";695case PT_SHLIB: return "SHLIB";696case PT_PHDR: return "PHDR";697case PT_TLS: return "TLS";698case PT_GNU_EH_FRAME: return "GNU_EH_FRAME";699case PT_GNU_STACK: return "GNU_STACK";700case PT_GNU_RELRO: return "GNU_RELRO";701case PT_OPENBSD_RANDOMIZE: return "OPENBSD_RANDOMIZE";702case PT_OPENBSD_WXNEEDED: return "OPENBSD_WXNEEDED";703case PT_OPENBSD_BOOTDATA: return "OPENBSD_BOOTDATA";704default:705if (ptype >= PT_LOOS && ptype <= PT_HIOS)706snprintf(s_ptype, sizeof(s_ptype), "LOOS+%#x",707ptype - PT_LOOS);708else709snprintf(s_ptype, sizeof(s_ptype), "<unknown: %#x>",710ptype);711return (s_ptype);712}713}714715static const char *716section_type(unsigned int mach, unsigned int stype)717{718static char s_stype[32];719720if (stype >= SHT_LOPROC && stype <= SHT_HIPROC) {721switch (mach) {722case EM_ARM:723switch (stype) {724case SHT_ARM_EXIDX: return "ARM_EXIDX";725case SHT_ARM_PREEMPTMAP: return "ARM_PREEMPTMAP";726case SHT_ARM_ATTRIBUTES: return "ARM_ATTRIBUTES";727case SHT_ARM_DEBUGOVERLAY: return "ARM_DEBUGOVERLAY";728case SHT_ARM_OVERLAYSECTION: return "ARM_OVERLAYSECTION";729}730break;731case EM_X86_64:732switch (stype) {733case SHT_X86_64_UNWIND: return "X86_64_UNWIND";734default:735break;736}737break;738case EM_MIPS:739case EM_MIPS_RS3_LE:740switch (stype) {741case SHT_MIPS_LIBLIST: return "MIPS_LIBLIST";742case SHT_MIPS_MSYM: return "MIPS_MSYM";743case SHT_MIPS_CONFLICT: return "MIPS_CONFLICT";744case SHT_MIPS_GPTAB: return "MIPS_GPTAB";745case SHT_MIPS_UCODE: return "MIPS_UCODE";746case SHT_MIPS_DEBUG: return "MIPS_DEBUG";747case SHT_MIPS_REGINFO: return "MIPS_REGINFO";748case SHT_MIPS_PACKAGE: return "MIPS_PACKAGE";749case SHT_MIPS_PACKSYM: return "MIPS_PACKSYM";750case SHT_MIPS_RELD: return "MIPS_RELD";751case SHT_MIPS_IFACE: return "MIPS_IFACE";752case SHT_MIPS_CONTENT: return "MIPS_CONTENT";753case SHT_MIPS_OPTIONS: return "MIPS_OPTIONS";754case SHT_MIPS_DELTASYM: return "MIPS_DELTASYM";755case SHT_MIPS_DELTAINST: return "MIPS_DELTAINST";756case SHT_MIPS_DELTACLASS: return "MIPS_DELTACLASS";757case SHT_MIPS_DWARF: return "MIPS_DWARF";758case SHT_MIPS_DELTADECL: return "MIPS_DELTADECL";759case SHT_MIPS_SYMBOL_LIB: return "MIPS_SYMBOL_LIB";760case SHT_MIPS_EVENTS: return "MIPS_EVENTS";761case SHT_MIPS_TRANSLATE: return "MIPS_TRANSLATE";762case SHT_MIPS_PIXIE: return "MIPS_PIXIE";763case SHT_MIPS_XLATE: return "MIPS_XLATE";764case SHT_MIPS_XLATE_DEBUG: return "MIPS_XLATE_DEBUG";765case SHT_MIPS_WHIRL: return "MIPS_WHIRL";766case SHT_MIPS_EH_REGION: return "MIPS_EH_REGION";767case SHT_MIPS_XLATE_OLD: return "MIPS_XLATE_OLD";768case SHT_MIPS_PDR_EXCEPTION: return "MIPS_PDR_EXCEPTION";769case SHT_MIPS_ABIFLAGS: return "MIPS_ABIFLAGS";770default:771break;772}773break;774default:775break;776}777778snprintf(s_stype, sizeof(s_stype), "LOPROC+%#x",779stype - SHT_LOPROC);780return (s_stype);781}782783switch (stype) {784case SHT_NULL: return "NULL";785case SHT_PROGBITS: return "PROGBITS";786case SHT_SYMTAB: return "SYMTAB";787case SHT_STRTAB: return "STRTAB";788case SHT_RELA: return "RELA";789case SHT_HASH: return "HASH";790case SHT_DYNAMIC: return "DYNAMIC";791case SHT_NOTE: return "NOTE";792case SHT_NOBITS: return "NOBITS";793case SHT_REL: return "REL";794case SHT_SHLIB: return "SHLIB";795case SHT_DYNSYM: return "DYNSYM";796case SHT_INIT_ARRAY: return "INIT_ARRAY";797case SHT_FINI_ARRAY: return "FINI_ARRAY";798case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY";799case SHT_GROUP: return "GROUP";800case SHT_SYMTAB_SHNDX: return "SYMTAB_SHNDX";801case SHT_SUNW_dof: return "SUNW_dof";802case SHT_SUNW_cap: return "SUNW_cap";803case SHT_GNU_HASH: return "GNU_HASH";804case SHT_SUNW_ANNOTATE: return "SUNW_ANNOTATE";805case SHT_SUNW_DEBUGSTR: return "SUNW_DEBUGSTR";806case SHT_SUNW_DEBUG: return "SUNW_DEBUG";807case SHT_SUNW_move: return "SUNW_move";808case SHT_SUNW_COMDAT: return "SUNW_COMDAT";809case SHT_SUNW_syminfo: return "SUNW_syminfo";810case SHT_SUNW_verdef: return "SUNW_verdef";811case SHT_SUNW_verneed: return "SUNW_verneed";812case SHT_SUNW_versym: return "SUNW_versym";813default:814if (stype >= SHT_LOOS && stype <= SHT_HIOS)815snprintf(s_stype, sizeof(s_stype), "LOOS+%#x",816stype - SHT_LOOS);817else if (stype >= SHT_LOUSER)818snprintf(s_stype, sizeof(s_stype), "LOUSER+%#x",819stype - SHT_LOUSER);820else821snprintf(s_stype, sizeof(s_stype), "<unknown: %#x>",822stype);823return (s_stype);824}825}826827static const char *828dt_type(unsigned int mach, unsigned int dtype)829{830static char s_dtype[32];831832switch (dtype) {833case DT_NULL: return "NULL";834case DT_NEEDED: return "NEEDED";835case DT_PLTRELSZ: return "PLTRELSZ";836case DT_PLTGOT: return "PLTGOT";837case DT_HASH: return "HASH";838case DT_STRTAB: return "STRTAB";839case DT_SYMTAB: return "SYMTAB";840case DT_RELA: return "RELA";841case DT_RELASZ: return "RELASZ";842case DT_RELAENT: return "RELAENT";843case DT_STRSZ: return "STRSZ";844case DT_SYMENT: return "SYMENT";845case DT_INIT: return "INIT";846case DT_FINI: return "FINI";847case DT_SONAME: return "SONAME";848case DT_RPATH: return "RPATH";849case DT_SYMBOLIC: return "SYMBOLIC";850case DT_REL: return "REL";851case DT_RELSZ: return "RELSZ";852case DT_RELENT: return "RELENT";853case DT_PLTREL: return "PLTREL";854case DT_DEBUG: return "DEBUG";855case DT_TEXTREL: return "TEXTREL";856case DT_JMPREL: return "JMPREL";857case DT_BIND_NOW: return "BIND_NOW";858case DT_INIT_ARRAY: return "INIT_ARRAY";859case DT_FINI_ARRAY: return "FINI_ARRAY";860case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ";861case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ";862case DT_RUNPATH: return "RUNPATH";863case DT_FLAGS: return "FLAGS";864case DT_PREINIT_ARRAY: return "PREINIT_ARRAY";865case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ";866case DT_MAXPOSTAGS: return "MAXPOSTAGS";867case DT_SUNW_AUXILIARY: return "SUNW_AUXILIARY";868case DT_SUNW_RTLDINF: return "SUNW_RTLDINF";869case DT_SUNW_FILTER: return "SUNW_FILTER";870case DT_SUNW_CAP: return "SUNW_CAP";871case DT_SUNW_ASLR: return "SUNW_ASLR";872case DT_CHECKSUM: return "CHECKSUM";873case DT_PLTPADSZ: return "PLTPADSZ";874case DT_MOVEENT: return "MOVEENT";875case DT_MOVESZ: return "MOVESZ";876case DT_FEATURE: return "FEATURE";877case DT_POSFLAG_1: return "POSFLAG_1";878case DT_SYMINSZ: return "SYMINSZ";879case DT_SYMINENT: return "SYMINENT";880case DT_GNU_HASH: return "GNU_HASH";881case DT_TLSDESC_PLT: return "DT_TLSDESC_PLT";882case DT_TLSDESC_GOT: return "DT_TLSDESC_GOT";883case DT_GNU_CONFLICT: return "GNU_CONFLICT";884case DT_GNU_LIBLIST: return "GNU_LIBLIST";885case DT_CONFIG: return "CONFIG";886case DT_DEPAUDIT: return "DEPAUDIT";887case DT_AUDIT: return "AUDIT";888case DT_PLTPAD: return "PLTPAD";889case DT_MOVETAB: return "MOVETAB";890case DT_SYMINFO: return "SYMINFO";891case DT_VERSYM: return "VERSYM";892case DT_RELACOUNT: return "RELACOUNT";893case DT_RELCOUNT: return "RELCOUNT";894case DT_FLAGS_1: return "FLAGS_1";895case DT_VERDEF: return "VERDEF";896case DT_VERDEFNUM: return "VERDEFNUM";897case DT_VERNEED: return "VERNEED";898case DT_VERNEEDNUM: return "VERNEEDNUM";899case DT_AUXILIARY: return "AUXILIARY";900case DT_USED: return "USED";901case DT_FILTER: return "FILTER";902case DT_GNU_PRELINKED: return "GNU_PRELINKED";903case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ";904case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ";905}906907if (dtype >= DT_LOPROC && dtype <= DT_HIPROC) {908switch (mach) {909case EM_ARM:910switch (dtype) {911case DT_ARM_SYMTABSZ:912return "ARM_SYMTABSZ";913default:914break;915}916break;917case EM_MIPS:918case EM_MIPS_RS3_LE:919switch (dtype) {920case DT_MIPS_RLD_VERSION:921return "MIPS_RLD_VERSION";922case DT_MIPS_TIME_STAMP:923return "MIPS_TIME_STAMP";924case DT_MIPS_ICHECKSUM:925return "MIPS_ICHECKSUM";926case DT_MIPS_IVERSION:927return "MIPS_IVERSION";928case DT_MIPS_FLAGS:929return "MIPS_FLAGS";930case DT_MIPS_BASE_ADDRESS:931return "MIPS_BASE_ADDRESS";932case DT_MIPS_CONFLICT:933return "MIPS_CONFLICT";934case DT_MIPS_LIBLIST:935return "MIPS_LIBLIST";936case DT_MIPS_LOCAL_GOTNO:937return "MIPS_LOCAL_GOTNO";938case DT_MIPS_CONFLICTNO:939return "MIPS_CONFLICTNO";940case DT_MIPS_LIBLISTNO:941return "MIPS_LIBLISTNO";942case DT_MIPS_SYMTABNO:943return "MIPS_SYMTABNO";944case DT_MIPS_UNREFEXTNO:945return "MIPS_UNREFEXTNO";946case DT_MIPS_GOTSYM:947return "MIPS_GOTSYM";948case DT_MIPS_HIPAGENO:949return "MIPS_HIPAGENO";950case DT_MIPS_RLD_MAP:951return "MIPS_RLD_MAP";952case DT_MIPS_DELTA_CLASS:953return "MIPS_DELTA_CLASS";954case DT_MIPS_DELTA_CLASS_NO:955return "MIPS_DELTA_CLASS_NO";956case DT_MIPS_DELTA_INSTANCE:957return "MIPS_DELTA_INSTANCE";958case DT_MIPS_DELTA_INSTANCE_NO:959return "MIPS_DELTA_INSTANCE_NO";960case DT_MIPS_DELTA_RELOC:961return "MIPS_DELTA_RELOC";962case DT_MIPS_DELTA_RELOC_NO:963return "MIPS_DELTA_RELOC_NO";964case DT_MIPS_DELTA_SYM:965return "MIPS_DELTA_SYM";966case DT_MIPS_DELTA_SYM_NO:967return "MIPS_DELTA_SYM_NO";968case DT_MIPS_DELTA_CLASSSYM:969return "MIPS_DELTA_CLASSSYM";970case DT_MIPS_DELTA_CLASSSYM_NO:971return "MIPS_DELTA_CLASSSYM_NO";972case DT_MIPS_CXX_FLAGS:973return "MIPS_CXX_FLAGS";974case DT_MIPS_PIXIE_INIT:975return "MIPS_PIXIE_INIT";976case DT_MIPS_SYMBOL_LIB:977return "MIPS_SYMBOL_LIB";978case DT_MIPS_LOCALPAGE_GOTIDX:979return "MIPS_LOCALPAGE_GOTIDX";980case DT_MIPS_LOCAL_GOTIDX:981return "MIPS_LOCAL_GOTIDX";982case DT_MIPS_HIDDEN_GOTIDX:983return "MIPS_HIDDEN_GOTIDX";984case DT_MIPS_PROTECTED_GOTIDX:985return "MIPS_PROTECTED_GOTIDX";986case DT_MIPS_OPTIONS:987return "MIPS_OPTIONS";988case DT_MIPS_INTERFACE:989return "MIPS_INTERFACE";990case DT_MIPS_DYNSTR_ALIGN:991return "MIPS_DYNSTR_ALIGN";992case DT_MIPS_INTERFACE_SIZE:993return "MIPS_INTERFACE_SIZE";994case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:995return "MIPS_RLD_TEXT_RESOLVE_ADDR";996case DT_MIPS_PERF_SUFFIX:997return "MIPS_PERF_SUFFIX";998case DT_MIPS_COMPACT_SIZE:999return "MIPS_COMPACT_SIZE";1000case DT_MIPS_GP_VALUE:1001return "MIPS_GP_VALUE";1002case DT_MIPS_AUX_DYNAMIC:1003return "MIPS_AUX_DYNAMIC";1004case DT_MIPS_PLTGOT:1005return "MIPS_PLTGOT";1006case DT_MIPS_RLD_OBJ_UPDATE:1007return "MIPS_RLD_OBJ_UPDATE";1008case DT_MIPS_RWPLT:1009return "MIPS_RWPLT";1010default:1011break;1012}1013break;1014case EM_SPARC:1015case EM_SPARC32PLUS:1016case EM_SPARCV9:1017switch (dtype) {1018case DT_SPARC_REGISTER:1019return "DT_SPARC_REGISTER";1020default:1021break;1022}1023break;1024default:1025break;1026}1027}10281029snprintf(s_dtype, sizeof(s_dtype), "<unknown: %#x>", dtype);1030return (s_dtype);1031}10321033static const char *1034st_bind(unsigned int sbind)1035{1036static char s_sbind[32];10371038switch (sbind) {1039case STB_LOCAL: return "LOCAL";1040case STB_GLOBAL: return "GLOBAL";1041case STB_WEAK: return "WEAK";1042case STB_GNU_UNIQUE: return "UNIQUE";1043default:1044if (sbind >= STB_LOOS && sbind <= STB_HIOS)1045return "OS";1046else if (sbind >= STB_LOPROC && sbind <= STB_HIPROC)1047return "PROC";1048else1049snprintf(s_sbind, sizeof(s_sbind), "<unknown: %#x>",1050sbind);1051return (s_sbind);1052}1053}10541055static const char *1056st_type(unsigned int mach, unsigned int os, unsigned int stype)1057{1058static char s_stype[32];10591060switch (stype) {1061case STT_NOTYPE: return "NOTYPE";1062case STT_OBJECT: return "OBJECT";1063case STT_FUNC: return "FUNC";1064case STT_SECTION: return "SECTION";1065case STT_FILE: return "FILE";1066case STT_COMMON: return "COMMON";1067case STT_TLS: return "TLS";1068default:1069if (stype >= STT_LOOS && stype <= STT_HIOS) {1070if ((os == ELFOSABI_GNU || os == ELFOSABI_FREEBSD) &&1071stype == STT_GNU_IFUNC)1072return "IFUNC";1073snprintf(s_stype, sizeof(s_stype), "OS+%#x",1074stype - STT_LOOS);1075} else if (stype >= STT_LOPROC && stype <= STT_HIPROC) {1076if (mach == EM_SPARCV9 && stype == STT_SPARC_REGISTER)1077return "REGISTER";1078snprintf(s_stype, sizeof(s_stype), "PROC+%#x",1079stype - STT_LOPROC);1080} else1081snprintf(s_stype, sizeof(s_stype), "<unknown: %#x>",1082stype);1083return (s_stype);1084}1085}10861087static const char *1088st_vis(unsigned int svis)1089{1090static char s_svis[32];10911092switch(svis) {1093case STV_DEFAULT: return "DEFAULT";1094case STV_INTERNAL: return "INTERNAL";1095case STV_HIDDEN: return "HIDDEN";1096case STV_PROTECTED: return "PROTECTED";1097default:1098snprintf(s_svis, sizeof(s_svis), "<unknown: %#x>", svis);1099return (s_svis);1100}1101}11021103static const char *1104st_shndx(unsigned int shndx)1105{1106static char s_shndx[32];11071108switch (shndx) {1109case SHN_UNDEF: return "UND";1110case SHN_ABS: return "ABS";1111case SHN_COMMON: return "COM";1112default:1113if (shndx >= SHN_LOPROC && shndx <= SHN_HIPROC)1114return "PRC";1115else if (shndx >= SHN_LOOS && shndx <= SHN_HIOS)1116return "OS";1117else1118snprintf(s_shndx, sizeof(s_shndx), "%u", shndx);1119return (s_shndx);1120}1121}11221123static struct {1124const char *ln;1125char sn;1126int value;1127} section_flag[] = {1128{"WRITE", 'W', SHF_WRITE},1129{"ALLOC", 'A', SHF_ALLOC},1130{"EXEC", 'X', SHF_EXECINSTR},1131{"MERGE", 'M', SHF_MERGE},1132{"STRINGS", 'S', SHF_STRINGS},1133{"INFO LINK", 'I', SHF_INFO_LINK},1134{"OS NONCONF", 'O', SHF_OS_NONCONFORMING},1135{"GROUP", 'G', SHF_GROUP},1136{"TLS", 'T', SHF_TLS},1137{"COMPRESSED", 'C', SHF_COMPRESSED},1138{NULL, 0, 0}1139};11401141static const char *1142note_type(const char *name, unsigned int et, unsigned int nt)1143{1144if ((strcmp(name, "CORE") == 0 || strcmp(name, "LINUX") == 0) &&1145et == ET_CORE)1146return note_type_linux_core(nt);1147else if (strcmp(name, "FreeBSD") == 0)1148if (et == ET_CORE)1149return note_type_freebsd_core(nt);1150else1151return note_type_freebsd(nt);1152else if (strcmp(name, "GNU") == 0 && et != ET_CORE)1153return note_type_gnu(nt);1154else if (strcmp(name, "Go") == 0 && et != ET_CORE)1155return note_type_go(nt);1156else if (strcmp(name, "NetBSD") == 0 && et != ET_CORE)1157return note_type_netbsd(nt);1158else if (strcmp(name, "OpenBSD") == 0 && et != ET_CORE)1159return note_type_openbsd(nt);1160else if (strcmp(name, "Xen") == 0 && et != ET_CORE)1161return note_type_xen(nt);1162return note_type_unknown(nt);1163}11641165static const char *1166note_type_freebsd(unsigned int nt)1167{1168switch (nt) {1169case 1: return "NT_FREEBSD_ABI_TAG";1170case 2: return "NT_FREEBSD_NOINIT_TAG";1171case 3: return "NT_FREEBSD_ARCH_TAG";1172case 4: return "NT_FREEBSD_FEATURE_CTL";1173default: return (note_type_unknown(nt));1174}1175}11761177static const char *1178note_type_freebsd_core(unsigned int nt)1179{1180switch (nt) {1181case 1: return "NT_PRSTATUS";1182case 2: return "NT_FPREGSET";1183case 3: return "NT_PRPSINFO";1184case 7: return "NT_THRMISC";1185case 8: return "NT_PROCSTAT_PROC";1186case 9: return "NT_PROCSTAT_FILES";1187case 10: return "NT_PROCSTAT_VMMAP";1188case 11: return "NT_PROCSTAT_GROUPS";1189case 12: return "NT_PROCSTAT_UMASK";1190case 13: return "NT_PROCSTAT_RLIMIT";1191case 14: return "NT_PROCSTAT_OSREL";1192case 15: return "NT_PROCSTAT_PSSTRINGS";1193case 16: return "NT_PROCSTAT_AUXV";1194case 17: return "NT_PTLWPINFO";1195case 0x100: return "NT_PPC_VMX (ppc Altivec registers)";1196case 0x102: return "NT_PPC_VSX (ppc VSX registers)";1197case 0x200: return "NT_X86_SEGBASES (x86 segment base registers)";1198case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)";1199case 0x400: return "NT_ARM_VFP (arm VFP registers)";1200case 0x401: return "NT_ARM_TLS (arm TLS register)";1201case 0x406: return "NT_ARM_ADDR_MASK (arm address mask)";1202default: return (note_type_unknown(nt));1203}1204}12051206static const char *1207note_type_linux_core(unsigned int nt)1208{1209switch (nt) {1210case 1: return "NT_PRSTATUS (Process status)";1211case 2: return "NT_FPREGSET (Floating point information)";1212case 3: return "NT_PRPSINFO (Process information)";1213case 4: return "NT_TASKSTRUCT (Task structure)";1214case 6: return "NT_AUXV (Auxiliary vector)";1215case 10: return "NT_PSTATUS (Linux process status)";1216case 12: return "NT_FPREGS (Linux floating point regset)";1217case 13: return "NT_PSINFO (Linux process information)";1218case 16: return "NT_LWPSTATUS (Linux lwpstatus_t type)";1219case 17: return "NT_LWPSINFO (Linux lwpinfo_t type)";1220case 18: return "NT_WIN32PSTATUS (win32_pstatus structure)";1221case 0x100: return "NT_PPC_VMX (ppc Altivec registers)";1222case 0x102: return "NT_PPC_VSX (ppc VSX registers)";1223case 0x202: return "NT_X86_XSTATE (x86 XSAVE extended state)";1224case 0x300: return "NT_S390_HIGH_GPRS (s390 upper register halves)";1225case 0x301: return "NT_S390_TIMER (s390 timer register)";1226case 0x302: return "NT_S390_TODCMP (s390 TOD comparator register)";1227case 0x303: return "NT_S390_TODPREG (s390 TOD programmable register)";1228case 0x304: return "NT_S390_CTRS (s390 control registers)";1229case 0x305: return "NT_S390_PREFIX (s390 prefix register)";1230case 0x400: return "NT_ARM_VFP (arm VFP registers)";1231case 0x401: return "NT_ARM_TLS (arm TLS register)";1232case 0x402: return "NT_ARM_HW_BREAK (arm hardware breakpoint registers)";1233case 0x403: return "NT_ARM_HW_WATCH (arm hardware watchpoint registers)";1234case 0x404: return "NT_ARM_SYSTEM_CALL (arm system call number)";1235case 0x405: return "NT_ARM_SVE (arm scalable vector extension registers)";1236case 0x406: return "NT_ARM_PAC_MASK (arm pointer authentication code mask)";1237case 0x407: return "NT_ARM_PACA_KEYS (arm pointer authentication address keys)";1238case 0x408: return "NT_ARM_PACG_KEYS (arm pointer authentication generic keys)";1239case 0x409: return "NT_ARM_TAGGED_ADDR_CTRL (arm64 tagged address control)";1240case 0x40a: return "NT_ARM_PAC_ENABLED_KEYS (arm64 ptr auth enabled keys)";1241case 0x46494c45UL: return "NT_FILE (mapped files)";1242case 0x46E62B7FUL: return "NT_PRXFPREG (Linux user_xfpregs structure)";1243case 0x53494749UL: return "NT_SIGINFO (siginfo_t data)";1244default: return (note_type_unknown(nt));1245}1246}12471248static const char *1249note_type_gnu(unsigned int nt)1250{1251switch (nt) {1252case 1: return "NT_GNU_ABI_TAG";1253case 2: return "NT_GNU_HWCAP (Hardware capabilities)";1254case 3: return "NT_GNU_BUILD_ID (Build id set by ld(1))";1255case 4: return "NT_GNU_GOLD_VERSION (GNU gold version)";1256case 5: return "NT_GNU_PROPERTY_TYPE_0";1257default: return (note_type_unknown(nt));1258}1259}12601261static const char *1262note_type_go(unsigned int nt)1263{1264switch (nt) {1265case 4: return "elfGoBuildIDTag";1266default: return (note_type_unknown(nt));1267}1268}12691270static const char *1271note_type_netbsd(unsigned int nt)1272{1273switch (nt) {1274case 1: return "NT_NETBSD_IDENT";1275default: return (note_type_unknown(nt));1276}1277}12781279static const char *1280note_type_openbsd(unsigned int nt)1281{1282switch (nt) {1283case 1: return "NT_OPENBSD_IDENT";1284default: return (note_type_unknown(nt));1285}1286}12871288static const char *1289note_type_unknown(unsigned int nt)1290{1291static char s_nt[32];12921293snprintf(s_nt, sizeof(s_nt),1294nt >= 0x100 ? "<unknown: 0x%x>" : "<unknown: %u>", nt);1295return (s_nt);1296}12971298static const char *1299note_type_xen(unsigned int nt)1300{1301switch (nt) {1302case 0: return "XEN_ELFNOTE_INFO";1303case 1: return "XEN_ELFNOTE_ENTRY";1304case 2: return "XEN_ELFNOTE_HYPERCALL_PAGE";1305case 3: return "XEN_ELFNOTE_VIRT_BASE";1306case 4: return "XEN_ELFNOTE_PADDR_OFFSET";1307case 5: return "XEN_ELFNOTE_XEN_VERSION";1308case 6: return "XEN_ELFNOTE_GUEST_OS";1309case 7: return "XEN_ELFNOTE_GUEST_VERSION";1310case 8: return "XEN_ELFNOTE_LOADER";1311case 9: return "XEN_ELFNOTE_PAE_MODE";1312case 10: return "XEN_ELFNOTE_FEATURES";1313case 11: return "XEN_ELFNOTE_BSD_SYMTAB";1314case 12: return "XEN_ELFNOTE_HV_START_LOW";1315case 13: return "XEN_ELFNOTE_L1_MFN_VALID";1316case 14: return "XEN_ELFNOTE_SUSPEND_CANCEL";1317case 15: return "XEN_ELFNOTE_INIT_P2M";1318case 16: return "XEN_ELFNOTE_MOD_START_PFN";1319case 17: return "XEN_ELFNOTE_SUPPORTED_FEATURES";1320case 18: return "XEN_ELFNOTE_PHYS32_ENTRY";1321default: return (note_type_unknown(nt));1322}1323}13241325static struct {1326const char *name;1327int value;1328} l_flag[] = {1329{"EXACT_MATCH", LL_EXACT_MATCH},1330{"IGNORE_INT_VER", LL_IGNORE_INT_VER},1331{"REQUIRE_MINOR", LL_REQUIRE_MINOR},1332{"EXPORTS", LL_EXPORTS},1333{"DELAY_LOAD", LL_DELAY_LOAD},1334{"DELTA", LL_DELTA},1335{NULL, 0}1336};13371338static struct mips_option mips_exceptions_option[] = {1339{OEX_PAGE0, "PAGE0"},1340{OEX_SMM, "SMM"},1341{OEX_PRECISEFP, "PRECISEFP"},1342{OEX_DISMISS, "DISMISS"},1343{0, NULL}1344};13451346static struct mips_option mips_pad_option[] = {1347{OPAD_PREFIX, "PREFIX"},1348{OPAD_POSTFIX, "POSTFIX"},1349{OPAD_SYMBOL, "SYMBOL"},1350{0, NULL}1351};13521353static struct mips_option mips_hwpatch_option[] = {1354{OHW_R4KEOP, "R4KEOP"},1355{OHW_R8KPFETCH, "R8KPFETCH"},1356{OHW_R5KEOP, "R5KEOP"},1357{OHW_R5KCVTL, "R5KCVTL"},1358{0, NULL}1359};13601361static struct mips_option mips_hwa_option[] = {1362{OHWA0_R4KEOP_CHECKED, "R4KEOP_CHECKED"},1363{OHWA0_R4KEOP_CLEAN, "R4KEOP_CLEAN"},1364{0, NULL}1365};13661367static struct mips_option mips_hwo_option[] = {1368{OHWO0_FIXADE, "FIXADE"},1369{0, NULL}1370};13711372static const char *1373option_kind(uint8_t kind)1374{1375static char s_kind[32];13761377switch (kind) {1378case ODK_NULL: return "NULL";1379case ODK_REGINFO: return "REGINFO";1380case ODK_EXCEPTIONS: return "EXCEPTIONS";1381case ODK_PAD: return "PAD";1382case ODK_HWPATCH: return "HWPATCH";1383case ODK_FILL: return "FILL";1384case ODK_TAGS: return "TAGS";1385case ODK_HWAND: return "HWAND";1386case ODK_HWOR: return "HWOR";1387case ODK_GP_GROUP: return "GP_GROUP";1388case ODK_IDENT: return "IDENT";1389default:1390snprintf(s_kind, sizeof(s_kind), "<unknown: %u>", kind);1391return (s_kind);1392}1393}13941395static const char *1396top_tag(unsigned int tag)1397{1398static char s_top_tag[32];13991400switch (tag) {1401case 1: return "File Attributes";1402case 2: return "Section Attributes";1403case 3: return "Symbol Attributes";1404default:1405snprintf(s_top_tag, sizeof(s_top_tag), "Unknown tag: %u", tag);1406return (s_top_tag);1407}1408}14091410static const char *1411aeabi_cpu_arch(uint64_t arch)1412{1413static char s_cpu_arch[32];14141415switch (arch) {1416case 0: return "Pre-V4";1417case 1: return "ARM v4";1418case 2: return "ARM v4T";1419case 3: return "ARM v5T";1420case 4: return "ARM v5TE";1421case 5: return "ARM v5TEJ";1422case 6: return "ARM v6";1423case 7: return "ARM v6KZ";1424case 8: return "ARM v6T2";1425case 9: return "ARM v6K";1426case 10: return "ARM v7";1427case 11: return "ARM v6-M";1428case 12: return "ARM v6S-M";1429case 13: return "ARM v7E-M";1430default:1431snprintf(s_cpu_arch, sizeof(s_cpu_arch),1432"Unknown (%ju)", (uintmax_t) arch);1433return (s_cpu_arch);1434}1435}14361437static const char *1438aeabi_cpu_arch_profile(uint64_t pf)1439{1440static char s_arch_profile[32];14411442switch (pf) {1443case 0:1444return "Not applicable";1445case 0x41: /* 'A' */1446return "Application Profile";1447case 0x52: /* 'R' */1448return "Real-Time Profile";1449case 0x4D: /* 'M' */1450return "Microcontroller Profile";1451case 0x53: /* 'S' */1452return "Application or Real-Time Profile";1453default:1454snprintf(s_arch_profile, sizeof(s_arch_profile),1455"Unknown (%ju)\n", (uintmax_t) pf);1456return (s_arch_profile);1457}1458}14591460static const char *1461aeabi_arm_isa(uint64_t ai)1462{1463static char s_ai[32];14641465switch (ai) {1466case 0: return "No";1467case 1: return "Yes";1468default:1469snprintf(s_ai, sizeof(s_ai), "Unknown (%ju)\n",1470(uintmax_t) ai);1471return (s_ai);1472}1473}14741475static const char *1476aeabi_thumb_isa(uint64_t ti)1477{1478static char s_ti[32];14791480switch (ti) {1481case 0: return "No";1482case 1: return "16-bit Thumb";1483case 2: return "32-bit Thumb";1484default:1485snprintf(s_ti, sizeof(s_ti), "Unknown (%ju)\n",1486(uintmax_t) ti);1487return (s_ti);1488}1489}14901491static const char *1492aeabi_fp_arch(uint64_t fp)1493{1494static char s_fp_arch[32];14951496switch (fp) {1497case 0: return "No";1498case 1: return "VFPv1";1499case 2: return "VFPv2";1500case 3: return "VFPv3";1501case 4: return "VFPv3-D16";1502case 5: return "VFPv4";1503case 6: return "VFPv4-D16";1504default:1505snprintf(s_fp_arch, sizeof(s_fp_arch), "Unknown (%ju)",1506(uintmax_t) fp);1507return (s_fp_arch);1508}1509}15101511static const char *1512aeabi_wmmx_arch(uint64_t wmmx)1513{1514static char s_wmmx[32];15151516switch (wmmx) {1517case 0: return "No";1518case 1: return "WMMXv1";1519case 2: return "WMMXv2";1520default:1521snprintf(s_wmmx, sizeof(s_wmmx), "Unknown (%ju)",1522(uintmax_t) wmmx);1523return (s_wmmx);1524}1525}15261527static const char *1528aeabi_adv_simd_arch(uint64_t simd)1529{1530static char s_simd[32];15311532switch (simd) {1533case 0: return "No";1534case 1: return "NEONv1";1535case 2: return "NEONv2";1536default:1537snprintf(s_simd, sizeof(s_simd), "Unknown (%ju)",1538(uintmax_t) simd);1539return (s_simd);1540}1541}15421543static const char *1544aeabi_pcs_config(uint64_t pcs)1545{1546static char s_pcs[32];15471548switch (pcs) {1549case 0: return "None";1550case 1: return "Bare platform";1551case 2: return "Linux";1552case 3: return "Linux DSO";1553case 4: return "Palm OS 2004";1554case 5: return "Palm OS (future)";1555case 6: return "Symbian OS 2004";1556case 7: return "Symbian OS (future)";1557default:1558snprintf(s_pcs, sizeof(s_pcs), "Unknown (%ju)",1559(uintmax_t) pcs);1560return (s_pcs);1561}1562}15631564static const char *1565aeabi_pcs_r9(uint64_t r9)1566{1567static char s_r9[32];15681569switch (r9) {1570case 0: return "V6";1571case 1: return "SB";1572case 2: return "TLS pointer";1573case 3: return "Unused";1574default:1575snprintf(s_r9, sizeof(s_r9), "Unknown (%ju)", (uintmax_t) r9);1576return (s_r9);1577}1578}15791580static const char *1581aeabi_pcs_rw(uint64_t rw)1582{1583static char s_rw[32];15841585switch (rw) {1586case 0: return "Absolute";1587case 1: return "PC-relative";1588case 2: return "SB-relative";1589case 3: return "None";1590default:1591snprintf(s_rw, sizeof(s_rw), "Unknown (%ju)", (uintmax_t) rw);1592return (s_rw);1593}1594}15951596static const char *1597aeabi_pcs_ro(uint64_t ro)1598{1599static char s_ro[32];16001601switch (ro) {1602case 0: return "Absolute";1603case 1: return "PC-relative";1604case 2: return "None";1605default:1606snprintf(s_ro, sizeof(s_ro), "Unknown (%ju)", (uintmax_t) ro);1607return (s_ro);1608}1609}16101611static const char *1612aeabi_pcs_got(uint64_t got)1613{1614static char s_got[32];16151616switch (got) {1617case 0: return "None";1618case 1: return "direct";1619case 2: return "indirect via GOT";1620default:1621snprintf(s_got, sizeof(s_got), "Unknown (%ju)",1622(uintmax_t) got);1623return (s_got);1624}1625}16261627static const char *1628aeabi_pcs_wchar_t(uint64_t wt)1629{1630static char s_wt[32];16311632switch (wt) {1633case 0: return "None";1634case 2: return "wchar_t size 2";1635case 4: return "wchar_t size 4";1636default:1637snprintf(s_wt, sizeof(s_wt), "Unknown (%ju)", (uintmax_t) wt);1638return (s_wt);1639}1640}16411642static const char *1643aeabi_enum_size(uint64_t es)1644{1645static char s_es[32];16461647switch (es) {1648case 0: return "None";1649case 1: return "smallest";1650case 2: return "32-bit";1651case 3: return "visible 32-bit";1652default:1653snprintf(s_es, sizeof(s_es), "Unknown (%ju)", (uintmax_t) es);1654return (s_es);1655}1656}16571658static const char *1659aeabi_align_needed(uint64_t an)1660{1661static char s_align_n[64];16621663switch (an) {1664case 0: return "No";1665case 1: return "8-byte align";1666case 2: return "4-byte align";1667case 3: return "Reserved";1668default:1669if (an >= 4 && an <= 12)1670snprintf(s_align_n, sizeof(s_align_n), "8-byte align"1671" and up to 2^%ju-byte extended align",1672(uintmax_t) an);1673else1674snprintf(s_align_n, sizeof(s_align_n), "Unknown (%ju)",1675(uintmax_t) an);1676return (s_align_n);1677}1678}16791680static const char *1681aeabi_align_preserved(uint64_t ap)1682{1683static char s_align_p[128];16841685switch (ap) {1686case 0: return "No";1687case 1: return "8-byte align";1688case 2: return "8-byte align and SP % 8 == 0";1689case 3: return "Reserved";1690default:1691if (ap >= 4 && ap <= 12)1692snprintf(s_align_p, sizeof(s_align_p), "8-byte align"1693" and SP %% 8 == 0 and up to 2^%ju-byte extended"1694" align", (uintmax_t) ap);1695else1696snprintf(s_align_p, sizeof(s_align_p), "Unknown (%ju)",1697(uintmax_t) ap);1698return (s_align_p);1699}1700}17011702static const char *1703aeabi_fp_rounding(uint64_t fr)1704{1705static char s_fp_r[32];17061707switch (fr) {1708case 0: return "Unused";1709case 1: return "Needed";1710default:1711snprintf(s_fp_r, sizeof(s_fp_r), "Unknown (%ju)",1712(uintmax_t) fr);1713return (s_fp_r);1714}1715}17161717static const char *1718aeabi_fp_denormal(uint64_t fd)1719{1720static char s_fp_d[32];17211722switch (fd) {1723case 0: return "Unused";1724case 1: return "Needed";1725case 2: return "Sign Only";1726default:1727snprintf(s_fp_d, sizeof(s_fp_d), "Unknown (%ju)",1728(uintmax_t) fd);1729return (s_fp_d);1730}1731}17321733static const char *1734aeabi_fp_exceptions(uint64_t fe)1735{1736static char s_fp_e[32];17371738switch (fe) {1739case 0: return "Unused";1740case 1: return "Needed";1741default:1742snprintf(s_fp_e, sizeof(s_fp_e), "Unknown (%ju)",1743(uintmax_t) fe);1744return (s_fp_e);1745}1746}17471748static const char *1749aeabi_fp_user_exceptions(uint64_t fu)1750{1751static char s_fp_u[32];17521753switch (fu) {1754case 0: return "Unused";1755case 1: return "Needed";1756default:1757snprintf(s_fp_u, sizeof(s_fp_u), "Unknown (%ju)",1758(uintmax_t) fu);1759return (s_fp_u);1760}1761}17621763static const char *1764aeabi_fp_number_model(uint64_t fn)1765{1766static char s_fp_n[32];17671768switch (fn) {1769case 0: return "Unused";1770case 1: return "IEEE 754 normal";1771case 2: return "RTABI";1772case 3: return "IEEE 754";1773default:1774snprintf(s_fp_n, sizeof(s_fp_n), "Unknown (%ju)",1775(uintmax_t) fn);1776return (s_fp_n);1777}1778}17791780static const char *1781aeabi_fp_16bit_format(uint64_t fp16)1782{1783static char s_fp_16[64];17841785switch (fp16) {1786case 0: return "None";1787case 1: return "IEEE 754";1788case 2: return "VFPv3/Advanced SIMD (alternative format)";1789default:1790snprintf(s_fp_16, sizeof(s_fp_16), "Unknown (%ju)",1791(uintmax_t) fp16);1792return (s_fp_16);1793}1794}17951796static const char *1797aeabi_mpext(uint64_t mp)1798{1799static char s_mp[32];18001801switch (mp) {1802case 0: return "Not allowed";1803case 1: return "Allowed";1804default:1805snprintf(s_mp, sizeof(s_mp), "Unknown (%ju)",1806(uintmax_t) mp);1807return (s_mp);1808}1809}18101811static const char *1812aeabi_div(uint64_t du)1813{1814static char s_du[32];18151816switch (du) {1817case 0: return "Yes (V7-R/V7-M)";1818case 1: return "No";1819case 2: return "Yes (V7-A)";1820default:1821snprintf(s_du, sizeof(s_du), "Unknown (%ju)",1822(uintmax_t) du);1823return (s_du);1824}1825}18261827static const char *1828aeabi_t2ee(uint64_t t2ee)1829{1830static char s_t2ee[32];18311832switch (t2ee) {1833case 0: return "Not allowed";1834case 1: return "Allowed";1835default:1836snprintf(s_t2ee, sizeof(s_t2ee), "Unknown(%ju)",1837(uintmax_t) t2ee);1838return (s_t2ee);1839}18401841}18421843static const char *1844aeabi_hardfp(uint64_t hfp)1845{1846static char s_hfp[32];18471848switch (hfp) {1849case 0: return "Tag_FP_arch";1850case 1: return "only SP";1851case 2: return "only DP";1852case 3: return "both SP and DP";1853default:1854snprintf(s_hfp, sizeof(s_hfp), "Unknown (%ju)",1855(uintmax_t) hfp);1856return (s_hfp);1857}1858}18591860static const char *1861aeabi_vfp_args(uint64_t va)1862{1863static char s_va[32];18641865switch (va) {1866case 0: return "AAPCS (base variant)";1867case 1: return "AAPCS (VFP variant)";1868case 2: return "toolchain-specific";1869default:1870snprintf(s_va, sizeof(s_va), "Unknown (%ju)", (uintmax_t) va);1871return (s_va);1872}1873}18741875static const char *1876aeabi_wmmx_args(uint64_t wa)1877{1878static char s_wa[32];18791880switch (wa) {1881case 0: return "AAPCS (base variant)";1882case 1: return "Intel WMMX";1883case 2: return "toolchain-specific";1884default:1885snprintf(s_wa, sizeof(s_wa), "Unknown(%ju)", (uintmax_t) wa);1886return (s_wa);1887}1888}18891890static const char *1891aeabi_unaligned_access(uint64_t ua)1892{1893static char s_ua[32];18941895switch (ua) {1896case 0: return "Not allowed";1897case 1: return "Allowed";1898default:1899snprintf(s_ua, sizeof(s_ua), "Unknown(%ju)", (uintmax_t) ua);1900return (s_ua);1901}1902}19031904static const char *1905aeabi_fp_hpext(uint64_t fh)1906{1907static char s_fh[32];19081909switch (fh) {1910case 0: return "Not allowed";1911case 1: return "Allowed";1912default:1913snprintf(s_fh, sizeof(s_fh), "Unknown(%ju)", (uintmax_t) fh);1914return (s_fh);1915}1916}19171918static const char *1919aeabi_optm_goal(uint64_t og)1920{1921static char s_og[32];19221923switch (og) {1924case 0: return "None";1925case 1: return "Speed";1926case 2: return "Speed aggressive";1927case 3: return "Space";1928case 4: return "Space aggressive";1929case 5: return "Debugging";1930case 6: return "Best Debugging";1931default:1932snprintf(s_og, sizeof(s_og), "Unknown(%ju)", (uintmax_t) og);1933return (s_og);1934}1935}19361937static const char *1938aeabi_fp_optm_goal(uint64_t fog)1939{1940static char s_fog[32];19411942switch (fog) {1943case 0: return "None";1944case 1: return "Speed";1945case 2: return "Speed aggressive";1946case 3: return "Space";1947case 4: return "Space aggressive";1948case 5: return "Accurary";1949case 6: return "Best Accurary";1950default:1951snprintf(s_fog, sizeof(s_fog), "Unknown(%ju)",1952(uintmax_t) fog);1953return (s_fog);1954}1955}19561957static const char *1958aeabi_virtual(uint64_t vt)1959{1960static char s_virtual[64];19611962switch (vt) {1963case 0: return "No";1964case 1: return "TrustZone";1965case 2: return "Virtualization extension";1966case 3: return "TrustZone and virtualization extension";1967default:1968snprintf(s_virtual, sizeof(s_virtual), "Unknown(%ju)",1969(uintmax_t) vt);1970return (s_virtual);1971}1972}19731974static struct {1975uint64_t tag;1976const char *s_tag;1977const char *(*get_desc)(uint64_t val);1978} aeabi_tags[] = {1979{4, "Tag_CPU_raw_name", NULL},1980{5, "Tag_CPU_name", NULL},1981{6, "Tag_CPU_arch", aeabi_cpu_arch},1982{7, "Tag_CPU_arch_profile", aeabi_cpu_arch_profile},1983{8, "Tag_ARM_ISA_use", aeabi_arm_isa},1984{9, "Tag_THUMB_ISA_use", aeabi_thumb_isa},1985{10, "Tag_FP_arch", aeabi_fp_arch},1986{11, "Tag_WMMX_arch", aeabi_wmmx_arch},1987{12, "Tag_Advanced_SIMD_arch", aeabi_adv_simd_arch},1988{13, "Tag_PCS_config", aeabi_pcs_config},1989{14, "Tag_ABI_PCS_R9_use", aeabi_pcs_r9},1990{15, "Tag_ABI_PCS_RW_data", aeabi_pcs_rw},1991{16, "Tag_ABI_PCS_RO_data", aeabi_pcs_ro},1992{17, "Tag_ABI_PCS_GOT_use", aeabi_pcs_got},1993{18, "Tag_ABI_PCS_wchar_t", aeabi_pcs_wchar_t},1994{19, "Tag_ABI_FP_rounding", aeabi_fp_rounding},1995{20, "Tag_ABI_FP_denormal", aeabi_fp_denormal},1996{21, "Tag_ABI_FP_exceptions", aeabi_fp_exceptions},1997{22, "Tag_ABI_FP_user_exceptions", aeabi_fp_user_exceptions},1998{23, "Tag_ABI_FP_number_model", aeabi_fp_number_model},1999{24, "Tag_ABI_align_needed", aeabi_align_needed},2000{25, "Tag_ABI_align_preserved", aeabi_align_preserved},2001{26, "Tag_ABI_enum_size", aeabi_enum_size},2002{27, "Tag_ABI_HardFP_use", aeabi_hardfp},2003{28, "Tag_ABI_VFP_args", aeabi_vfp_args},2004{29, "Tag_ABI_WMMX_args", aeabi_wmmx_args},2005{30, "Tag_ABI_optimization_goals", aeabi_optm_goal},2006{31, "Tag_ABI_FP_optimization_goals", aeabi_fp_optm_goal},2007{32, "Tag_compatibility", NULL},2008{34, "Tag_CPU_unaligned_access", aeabi_unaligned_access},2009{36, "Tag_FP_HP_extension", aeabi_fp_hpext},2010{38, "Tag_ABI_FP_16bit_format", aeabi_fp_16bit_format},2011{42, "Tag_MPextension_use", aeabi_mpext},2012{44, "Tag_DIV_use", aeabi_div},2013{64, "Tag_nodefaults", NULL},2014{65, "Tag_also_compatible_with", NULL},2015{66, "Tag_T2EE_use", aeabi_t2ee},2016{67, "Tag_conformance", NULL},2017{68, "Tag_Virtualization_use", aeabi_virtual},2018{70, "Tag_MPextension_use", aeabi_mpext},2019};20202021static const char *2022mips_abi_fp(uint64_t fp)2023{2024static char s_mips_abi_fp[64];20252026switch (fp) {2027case 0: return "N/A";2028case 1: return "Hard float (double precision)";2029case 2: return "Hard float (single precision)";2030case 3: return "Soft float";2031case 4: return "64-bit float (-mips32r2 -mfp64)";2032default:2033snprintf(s_mips_abi_fp, sizeof(s_mips_abi_fp), "Unknown(%ju)",2034(uintmax_t) fp);2035return (s_mips_abi_fp);2036}2037}20382039static const char *2040ppc_abi_fp(uint64_t fp)2041{2042static char s_ppc_abi_fp[64];20432044switch (fp) {2045case 0: return "N/A";2046case 1: return "Hard float (double precision)";2047case 2: return "Soft float";2048case 3: return "Hard float (single precision)";2049default:2050snprintf(s_ppc_abi_fp, sizeof(s_ppc_abi_fp), "Unknown(%ju)",2051(uintmax_t) fp);2052return (s_ppc_abi_fp);2053}2054}20552056static const char *2057ppc_abi_vector(uint64_t vec)2058{2059static char s_vec[64];20602061switch (vec) {2062case 0: return "N/A";2063case 1: return "Generic purpose registers";2064case 2: return "AltiVec registers";2065case 3: return "SPE registers";2066default:2067snprintf(s_vec, sizeof(s_vec), "Unknown(%ju)", (uintmax_t) vec);2068return (s_vec);2069}2070}20712072static const char *2073dwarf_reg(unsigned int mach, unsigned int reg)2074{20752076switch (mach) {2077case EM_386:2078case EM_IAMCU:2079switch (reg) {2080case 0: return "eax";2081case 1: return "ecx";2082case 2: return "edx";2083case 3: return "ebx";2084case 4: return "esp";2085case 5: return "ebp";2086case 6: return "esi";2087case 7: return "edi";2088case 8: return "eip";2089case 9: return "eflags";2090case 11: return "st0";2091case 12: return "st1";2092case 13: return "st2";2093case 14: return "st3";2094case 15: return "st4";2095case 16: return "st5";2096case 17: return "st6";2097case 18: return "st7";2098case 21: return "xmm0";2099case 22: return "xmm1";2100case 23: return "xmm2";2101case 24: return "xmm3";2102case 25: return "xmm4";2103case 26: return "xmm5";2104case 27: return "xmm6";2105case 28: return "xmm7";2106case 29: return "mm0";2107case 30: return "mm1";2108case 31: return "mm2";2109case 32: return "mm3";2110case 33: return "mm4";2111case 34: return "mm5";2112case 35: return "mm6";2113case 36: return "mm7";2114case 37: return "fcw";2115case 38: return "fsw";2116case 39: return "mxcsr";2117case 40: return "es";2118case 41: return "cs";2119case 42: return "ss";2120case 43: return "ds";2121case 44: return "fs";2122case 45: return "gs";2123case 48: return "tr";2124case 49: return "ldtr";2125default: return (NULL);2126}2127case EM_RISCV:2128switch (reg) {2129case 0: return "zero";2130case 1: return "ra";2131case 2: return "sp";2132case 3: return "gp";2133case 4: return "tp";2134case 5: return "t0";2135case 6: return "t1";2136case 7: return "t2";2137case 8: return "s0";2138case 9: return "s1";2139case 10: return "a0";2140case 11: return "a1";2141case 12: return "a2";2142case 13: return "a3";2143case 14: return "a4";2144case 15: return "a5";2145case 16: return "a6";2146case 17: return "a7";2147case 18: return "s2";2148case 19: return "s3";2149case 20: return "s4";2150case 21: return "s5";2151case 22: return "s6";2152case 23: return "s7";2153case 24: return "s8";2154case 25: return "s9";2155case 26: return "s10";2156case 27: return "s11";2157case 28: return "t3";2158case 29: return "t4";2159case 30: return "t5";2160case 31: return "t6";2161case 32: return "ft0";2162case 33: return "ft1";2163case 34: return "ft2";2164case 35: return "ft3";2165case 36: return "ft4";2166case 37: return "ft5";2167case 38: return "ft6";2168case 39: return "ft7";2169case 40: return "fs0";2170case 41: return "fs1";2171case 42: return "fa0";2172case 43: return "fa1";2173case 44: return "fa2";2174case 45: return "fa3";2175case 46: return "fa4";2176case 47: return "fa5";2177case 48: return "fa6";2178case 49: return "fa7";2179case 50: return "fs2";2180case 51: return "fs3";2181case 52: return "fs4";2182case 53: return "fs5";2183case 54: return "fs6";2184case 55: return "fs7";2185case 56: return "fs8";2186case 57: return "fs9";2187case 58: return "fs10";2188case 59: return "fs11";2189case 60: return "ft8";2190case 61: return "ft9";2191case 62: return "ft10";2192case 63: return "ft11";2193default: return (NULL);2194}2195case EM_X86_64:2196switch (reg) {2197case 0: return "rax";2198case 1: return "rdx";2199case 2: return "rcx";2200case 3: return "rbx";2201case 4: return "rsi";2202case 5: return "rdi";2203case 6: return "rbp";2204case 7: return "rsp";2205case 16: return "rip";2206case 17: return "xmm0";2207case 18: return "xmm1";2208case 19: return "xmm2";2209case 20: return "xmm3";2210case 21: return "xmm4";2211case 22: return "xmm5";2212case 23: return "xmm6";2213case 24: return "xmm7";2214case 25: return "xmm8";2215case 26: return "xmm9";2216case 27: return "xmm10";2217case 28: return "xmm11";2218case 29: return "xmm12";2219case 30: return "xmm13";2220case 31: return "xmm14";2221case 32: return "xmm15";2222case 33: return "st0";2223case 34: return "st1";2224case 35: return "st2";2225case 36: return "st3";2226case 37: return "st4";2227case 38: return "st5";2228case 39: return "st6";2229case 40: return "st7";2230case 41: return "mm0";2231case 42: return "mm1";2232case 43: return "mm2";2233case 44: return "mm3";2234case 45: return "mm4";2235case 46: return "mm5";2236case 47: return "mm6";2237case 48: return "mm7";2238case 49: return "rflags";2239case 50: return "es";2240case 51: return "cs";2241case 52: return "ss";2242case 53: return "ds";2243case 54: return "fs";2244case 55: return "gs";2245case 58: return "fs.base";2246case 59: return "gs.base";2247case 62: return "tr";2248case 63: return "ldtr";2249case 64: return "mxcsr";2250case 65: return "fcw";2251case 66: return "fsw";2252default: return (NULL);2253}2254default:2255return (NULL);2256}2257}22582259static void2260dump_ehdr(struct readelf *re)2261{2262size_t phnum, shnum, shstrndx;2263int i;22642265printf("ELF Header:\n");22662267/* e_ident[]. */2268printf(" Magic: ");2269for (i = 0; i < EI_NIDENT; i++)2270printf("%.2x ", re->ehdr.e_ident[i]);2271putchar('\n');22722273/* EI_CLASS. */2274printf("%-37s%s\n", " Class:", elf_class(re->ehdr.e_ident[EI_CLASS]));22752276/* EI_DATA. */2277printf("%-37s%s\n", " Data:", elf_endian(re->ehdr.e_ident[EI_DATA]));22782279/* EI_VERSION. */2280printf("%-37s%d %s\n", " Version:", re->ehdr.e_ident[EI_VERSION],2281elf_ver(re->ehdr.e_ident[EI_VERSION]));22822283/* EI_OSABI. */2284printf("%-37s%s\n", " OS/ABI:", elf_osabi(re->ehdr.e_ident[EI_OSABI]));22852286/* EI_ABIVERSION. */2287printf("%-37s%d\n", " ABI Version:", re->ehdr.e_ident[EI_ABIVERSION]);22882289/* e_type. */2290printf("%-37s%s\n", " Type:", elf_type(re->ehdr.e_type));22912292/* e_machine. */2293printf("%-37s%s\n", " Machine:", elf_machine(re->ehdr.e_machine));22942295/* e_version. */2296printf("%-37s%#x\n", " Version:", re->ehdr.e_version);22972298/* e_entry. */2299printf("%-37s%#jx\n", " Entry point address:",2300(uintmax_t)re->ehdr.e_entry);23012302/* e_phoff. */2303printf("%-37s%ju (bytes into file)\n", " Start of program headers:",2304(uintmax_t)re->ehdr.e_phoff);23052306/* e_shoff. */2307printf("%-37s%ju (bytes into file)\n", " Start of section headers:",2308(uintmax_t)re->ehdr.e_shoff);23092310/* e_flags. */2311printf("%-37s%#x", " Flags:", re->ehdr.e_flags);2312dump_eflags(re, re->ehdr.e_flags);2313putchar('\n');23142315/* e_ehsize. */2316printf("%-37s%u (bytes)\n", " Size of this header:",2317re->ehdr.e_ehsize);23182319/* e_phentsize. */2320printf("%-37s%u (bytes)\n", " Size of program headers:",2321re->ehdr.e_phentsize);23222323/* e_phnum. */2324printf("%-37s%u", " Number of program headers:", re->ehdr.e_phnum);2325if (re->ehdr.e_phnum == PN_XNUM) {2326/* Extended program header numbering is in use. */2327if (elf_getphnum(re->elf, &phnum))2328printf(" (%zu)", phnum);2329}2330putchar('\n');23312332/* e_shentsize. */2333printf("%-37s%u (bytes)\n", " Size of section headers:",2334re->ehdr.e_shentsize);23352336/* e_shnum. */2337printf("%-37s%u", " Number of section headers:", re->ehdr.e_shnum);2338if (re->ehdr.e_shnum == SHN_UNDEF) {2339/* Extended section numbering is in use. */2340if (elf_getshnum(re->elf, &shnum))2341printf(" (%ju)", (uintmax_t)shnum);2342}2343putchar('\n');23442345/* e_shstrndx. */2346printf("%-37s%u", " Section header string table index:",2347re->ehdr.e_shstrndx);2348if (re->ehdr.e_shstrndx == SHN_XINDEX) {2349/* Extended section numbering is in use. */2350if (elf_getshstrndx(re->elf, &shstrndx))2351printf(" (%ju)", (uintmax_t)shstrndx);2352}2353putchar('\n');2354}23552356static void2357dump_eflags(struct readelf *re, uint64_t e_flags)2358{2359struct eflags_desc *edesc;2360int arm_eabi;23612362edesc = NULL;2363switch (re->ehdr.e_machine) {2364case EM_ARM:2365arm_eabi = (e_flags & EF_ARM_EABIMASK) >> 24;2366if (arm_eabi == 0)2367printf(", GNU EABI");2368else if (arm_eabi <= 5)2369printf(", Version%d EABI", arm_eabi);2370edesc = arm_eflags_desc;2371break;2372case EM_MIPS:2373case EM_MIPS_RS3_LE:2374switch ((e_flags & EF_MIPS_ARCH) >> 28) {2375case 0: printf(", mips1"); break;2376case 1: printf(", mips2"); break;2377case 2: printf(", mips3"); break;2378case 3: printf(", mips4"); break;2379case 4: printf(", mips5"); break;2380case 5: printf(", mips32"); break;2381case 6: printf(", mips64"); break;2382case 7: printf(", mips32r2"); break;2383case 8: printf(", mips64r2"); break;2384default: break;2385}2386switch ((e_flags & 0x00FF0000) >> 16) {2387case 0x81: printf(", 3900"); break;2388case 0x82: printf(", 4010"); break;2389case 0x83: printf(", 4100"); break;2390case 0x85: printf(", 4650"); break;2391case 0x87: printf(", 4120"); break;2392case 0x88: printf(", 4111"); break;2393case 0x8a: printf(", sb1"); break;2394case 0x8b: printf(", octeon"); break;2395case 0x8c: printf(", xlr"); break;2396case 0x91: printf(", 5400"); break;2397case 0x98: printf(", 5500"); break;2398case 0x99: printf(", 9000"); break;2399case 0xa0: printf(", loongson-2e"); break;2400case 0xa1: printf(", loongson-2f"); break;2401default: break;2402}2403switch ((e_flags & 0x0000F000) >> 12) {2404case 1: printf(", o32"); break;2405case 2: printf(", o64"); break;2406case 3: printf(", eabi32"); break;2407case 4: printf(", eabi64"); break;2408default: break;2409}2410edesc = mips_eflags_desc;2411break;2412case EM_PPC64:2413switch (e_flags) {2414case 0: printf(", Unspecified or Power ELF V1 ABI"); break;2415case 1: printf(", Power ELF V1 ABI"); break;2416case 2: printf(", OpenPOWER ELF V2 ABI"); break;2417default: break;2418}2419/* FALLTHROUGH */2420case EM_PPC:2421edesc = powerpc_eflags_desc;2422break;2423case EM_RISCV:2424switch (e_flags & EF_RISCV_FLOAT_ABI_MASK) {2425case EF_RISCV_FLOAT_ABI_SOFT:2426printf(", soft-float ABI");2427break;2428case EF_RISCV_FLOAT_ABI_SINGLE:2429printf(", single-float ABI");2430break;2431case EF_RISCV_FLOAT_ABI_DOUBLE:2432printf(", double-float ABI");2433break;2434case EF_RISCV_FLOAT_ABI_QUAD:2435printf(", quad-float ABI");2436break;2437}2438edesc = riscv_eflags_desc;2439break;2440case EM_SPARC:2441case EM_SPARC32PLUS:2442case EM_SPARCV9:2443switch ((e_flags & EF_SPARCV9_MM)) {2444case EF_SPARCV9_TSO: printf(", tso"); break;2445case EF_SPARCV9_PSO: printf(", pso"); break;2446case EF_SPARCV9_MM: printf(", rmo"); break;2447default: break;2448}2449edesc = sparc_eflags_desc;2450break;2451default:2452break;2453}24542455if (edesc != NULL) {2456while (edesc->desc != NULL) {2457if (e_flags & edesc->flag)2458printf(", %s", edesc->desc);2459edesc++;2460}2461}2462}24632464static void2465dump_phdr(struct readelf *re)2466{2467const char *rawfile;2468GElf_Phdr phdr;2469size_t phnum, size;2470int i, j;24712472#define PH_HDR "Type", "Offset", "VirtAddr", "PhysAddr", "FileSiz", \2473"MemSiz", "Flg", "Align"2474#define PH_CT phdr_type(re->ehdr.e_machine, phdr.p_type), \2475(uintmax_t)phdr.p_offset, (uintmax_t)phdr.p_vaddr, \2476(uintmax_t)phdr.p_paddr, (uintmax_t)phdr.p_filesz, \2477(uintmax_t)phdr.p_memsz, \2478phdr.p_flags & PF_R ? 'R' : ' ', \2479phdr.p_flags & PF_W ? 'W' : ' ', \2480phdr.p_flags & PF_X ? 'E' : ' ', \2481(uintmax_t)phdr.p_align24822483if (elf_getphnum(re->elf, &phnum) == 0) {2484warnx("elf_getphnum failed: %s", elf_errmsg(-1));2485return;2486}2487if (phnum == 0) {2488printf("\nThere are no program headers in this file.\n");2489return;2490}24912492printf("\nElf file type is %s", elf_type(re->ehdr.e_type));2493printf("\nEntry point 0x%jx\n", (uintmax_t)re->ehdr.e_entry);2494printf("There are %ju program headers, starting at offset %ju\n",2495(uintmax_t)phnum, (uintmax_t)re->ehdr.e_phoff);24962497/* Dump program headers. */2498printf("\nProgram Headers:\n");2499if (re->ec == ELFCLASS32)2500printf(" %-15s%-9s%-11s%-11s%-8s%-8s%-4s%s\n", PH_HDR);2501else if (re->options & RE_WW)2502printf(" %-15s%-9s%-19s%-19s%-9s%-9s%-4s%s\n", PH_HDR);2503else2504printf(" %-15s%-19s%-19s%s\n %-19s%-20s"2505"%-7s%s\n", PH_HDR);2506for (i = 0; (size_t) i < phnum; i++) {2507if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {2508warnx("gelf_getphdr failed: %s", elf_errmsg(-1));2509continue;2510}2511/* TODO: Add arch-specific segment type dump. */2512if (re->ec == ELFCLASS32)2513printf(" %-14.14s 0x%6.6jx 0x%8.8jx 0x%8.8jx "2514"0x%5.5jx 0x%5.5jx %c%c%c %#jx\n", PH_CT);2515else if (re->options & RE_WW)2516printf(" %-14.14s 0x%6.6jx 0x%16.16jx 0x%16.16jx "2517"0x%6.6jx 0x%6.6jx %c%c%c %#jx\n", PH_CT);2518else2519printf(" %-14.14s 0x%16.16jx 0x%16.16jx 0x%16.16jx\n"2520" 0x%16.16jx 0x%16.16jx %c%c%c"2521" %#jx\n", PH_CT);2522if (phdr.p_type == PT_INTERP) {2523if ((rawfile = elf_rawfile(re->elf, &size)) == NULL) {2524warnx("elf_rawfile failed: %s", elf_errmsg(-1));2525continue;2526}2527if (phdr.p_offset >= size) {2528warnx("invalid program header offset");2529continue;2530}2531printf(" [Requesting program interpreter: %s]\n",2532rawfile + phdr.p_offset);2533}2534}25352536/* Dump section to segment mapping. */2537if (re->shnum == 0)2538return;2539printf("\n Section to Segment mapping:\n");2540printf(" Segment Sections...\n");2541for (i = 0; (size_t)i < phnum; i++) {2542if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {2543warnx("gelf_getphdr failed: %s", elf_errmsg(-1));2544continue;2545}2546printf(" %2.2d ", i);2547/* skip NULL section. */2548for (j = 1; (size_t)j < re->shnum; j++) {2549if (re->sl[j].off < phdr.p_offset)2550continue;2551if (re->sl[j].off + re->sl[j].sz >2552phdr.p_offset + phdr.p_filesz &&2553re->sl[j].type != SHT_NOBITS)2554continue;2555if (re->sl[j].addr < phdr.p_vaddr ||2556re->sl[j].addr + re->sl[j].sz >2557phdr.p_vaddr + phdr.p_memsz)2558continue;2559if (phdr.p_type == PT_TLS &&2560(re->sl[j].flags & SHF_TLS) == 0)2561continue;2562printf("%s ", re->sl[j].name);2563}2564printf("\n");2565}2566#undef PH_HDR2567#undef PH_CT2568}25692570static char *2571section_flags(struct readelf *re, struct section *s)2572{2573#define BUF_SZ 2562574static char buf[BUF_SZ];2575int i, p, nb;25762577p = 0;2578nb = re->ec == ELFCLASS32 ? 8 : 16;2579if (re->options & RE_T) {2580snprintf(buf, BUF_SZ, "[%*.*jx]: ", nb, nb,2581(uintmax_t)s->flags);2582p += nb + 4;2583}2584for (i = 0; section_flag[i].ln != NULL; i++) {2585if ((s->flags & section_flag[i].value) == 0)2586continue;2587if (re->options & RE_T) {2588snprintf(&buf[p], BUF_SZ - p, "%s, ",2589section_flag[i].ln);2590p += strlen(section_flag[i].ln) + 2;2591} else2592buf[p++] = section_flag[i].sn;2593}2594if (re->options & RE_T && p > nb + 4)2595p -= 2;2596buf[p] = '\0';25972598return (buf);2599}26002601static void2602dump_shdr(struct readelf *re)2603{2604struct section *s;2605int i;26062607#define S_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \2608"Flg", "Lk", "Inf", "Al"2609#define S_HDRL "[Nr] Name", "Type", "Address", "Offset", "Size", \2610"EntSize", "Flags", "Link", "Info", "Align"2611#define ST_HDR "[Nr] Name", "Type", "Addr", "Off", "Size", "ES", \2612"Lk", "Inf", "Al", "Flags"2613#define ST_HDRL "[Nr] Name", "Type", "Address", "Offset", "Link", \2614"Size", "EntSize", "Info", "Align", "Flags"2615#define S_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \2616(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\2617(uintmax_t)s->entsize, section_flags(re, s), \2618s->link, s->info, (uintmax_t)s->align2619#define ST_CT i, s->name, section_type(re->ehdr.e_machine, s->type), \2620(uintmax_t)s->addr, (uintmax_t)s->off, (uintmax_t)s->sz,\2621(uintmax_t)s->entsize, s->link, s->info, \2622(uintmax_t)s->align, section_flags(re, s)2623#define ST_CTL i, s->name, section_type(re->ehdr.e_machine, s->type), \2624(uintmax_t)s->addr, (uintmax_t)s->off, s->link, \2625(uintmax_t)s->sz, (uintmax_t)s->entsize, s->info, \2626(uintmax_t)s->align, section_flags(re, s)26272628if (re->shnum == 0) {2629printf("\nThere are no sections in this file.\n");2630return;2631}2632printf("There are %ju section headers, starting at offset 0x%jx:\n",2633(uintmax_t)re->shnum, (uintmax_t)re->ehdr.e_shoff);2634printf("\nSection Headers:\n");2635if (re->ec == ELFCLASS32) {2636if (re->options & RE_T)2637printf(" %s\n %-16s%-9s%-7s%-7s%-5s%-3s%-4s%s\n"2638"%12s\n", ST_HDR);2639else2640printf(" %-23s%-16s%-9s%-7s%-7s%-3s%-4s%-3s%-4s%s\n",2641S_HDR);2642} else if (re->options & RE_WW) {2643if (re->options & RE_T)2644printf(" %s\n %-16s%-17s%-7s%-7s%-5s%-3s%-4s%s\n"2645"%12s\n", ST_HDR);2646else2647printf(" %-23s%-16s%-17s%-7s%-7s%-3s%-4s%-3s%-4s%s\n",2648S_HDR);2649} else {2650if (re->options & RE_T)2651printf(" %s\n %-18s%-17s%-18s%s\n %-18s"2652"%-17s%-18s%s\n%12s\n", ST_HDRL);2653else2654printf(" %-23s%-17s%-18s%s\n %-18s%-17s%-7s%"2655"-6s%-6s%s\n", S_HDRL);2656}2657for (i = 0; (size_t)i < re->shnum; i++) {2658s = &re->sl[i];2659if (re->ec == ELFCLASS32) {2660if (re->options & RE_T)2661printf(" [%2d] %s\n %-15.15s %8.8jx"2662" %6.6jx %6.6jx %2.2jx %2u %3u %2ju\n"2663" %s\n", ST_CT);2664else2665if (re->options & RE_WW)2666printf(" [%2d] %-17s %-15.15s "2667"%8.8jx %6.6jx %6.6jx %2.2jx %3s "2668"%2u %3u %2ju\n", S_CT);2669else2670printf(" [%2d] %-17.17s %-15.15s "2671"%8.8jx %6.6jx %6.6jx %2.2jx %3s "2672"%2u %3u %2ju\n", S_CT);2673} else if (re->options & RE_WW) {2674if (re->options & RE_T)2675printf(" [%2d] %s\n %-15.15s %16.16jx"2676" %6.6jx %6.6jx %2.2jx %2u %3u %2ju\n"2677" %s\n", ST_CT);2678else2679printf(" [%2d] %-17s %-15.15s %16.16jx"2680" %6.6jx %6.6jx %2.2jx %3s %2u %3u %2ju\n",2681S_CT);2682} else {2683if (re->options & RE_T)2684printf(" [%2d] %s\n %-15.15s %16.16jx"2685" %16.16jx %u\n %16.16jx %16.16jx"2686" %-16u %ju\n %s\n", ST_CTL);2687else2688printf(" [%2d] %-17.17s %-15.15s %16.16jx"2689" %8.8jx\n %16.16jx %16.16jx "2690"%3s %2u %3u %ju\n", S_CT);2691}2692}2693if ((re->options & RE_T) == 0)2694printf("Key to Flags:\n W (write), A (alloc),"2695" X (execute), M (merge), S (strings)\n"2696" I (info), L (link order), G (group), x (unknown)\n"2697" O (extra OS processing required)"2698" o (OS specific), p (processor specific)\n");26992700#undef S_HDR2701#undef S_HDRL2702#undef ST_HDR2703#undef ST_HDRL2704#undef S_CT2705#undef ST_CT2706#undef ST_CTL2707}27082709/*2710* Return number of entries in the given section. We'd prefer ent_count be a2711* size_t *, but libelf APIs already use int for section indices.2712*/2713static int2714get_ent_count(struct section *s, int *ent_count)2715{2716if (s->entsize == 0) {2717warnx("section %s has entry size 0", s->name);2718return (0);2719} else if (s->sz / s->entsize > INT_MAX) {2720warnx("section %s has invalid section count", s->name);2721return (0);2722}2723*ent_count = (int)(s->sz / s->entsize);2724return (1);2725}27262727static void2728dump_dynamic(struct readelf *re)2729{2730GElf_Dyn dyn;2731Elf_Data *d;2732struct section *s;2733int elferr, i, is_dynamic, j, jmax, nentries;27342735is_dynamic = 0;27362737for (i = 0; (size_t)i < re->shnum; i++) {2738s = &re->sl[i];2739if (s->type != SHT_DYNAMIC)2740continue;2741(void) elf_errno();2742if ((d = elf_getdata(s->scn, NULL)) == NULL) {2743elferr = elf_errno();2744if (elferr != 0)2745warnx("elf_getdata failed: %s", elf_errmsg(-1));2746continue;2747}2748if (d->d_size <= 0)2749continue;27502751is_dynamic = 1;27522753/* Determine the actual number of table entries. */2754nentries = 0;2755if (!get_ent_count(s, &jmax))2756continue;2757for (j = 0; j < jmax; j++) {2758if (gelf_getdyn(d, j, &dyn) != &dyn) {2759warnx("gelf_getdyn failed: %s",2760elf_errmsg(-1));2761continue;2762}2763nentries ++;2764if (dyn.d_tag == DT_NULL)2765break;2766}27672768printf("\nDynamic section at offset 0x%jx", (uintmax_t)s->off);2769printf(" contains %u entries:\n", nentries);27702771if (re->ec == ELFCLASS32)2772printf("%5s%12s%28s\n", "Tag", "Type", "Name/Value");2773else2774printf("%5s%20s%28s\n", "Tag", "Type", "Name/Value");27752776for (j = 0; j < nentries; j++) {2777if (gelf_getdyn(d, j, &dyn) != &dyn)2778continue;2779/* Dump dynamic entry type. */2780if (re->ec == ELFCLASS32)2781printf(" 0x%8.8jx", (uintmax_t)dyn.d_tag);2782else2783printf(" 0x%16.16jx", (uintmax_t)dyn.d_tag);2784printf(" %-20s", dt_type(re->ehdr.e_machine,2785dyn.d_tag));2786/* Dump dynamic entry value. */2787dump_dyn_val(re, &dyn, s->link);2788}2789}27902791if (!is_dynamic)2792printf("\nThere is no dynamic section in this file.\n");2793}27942795static char *2796timestamp(time_t ti)2797{2798static char ts[32];2799struct tm *t;28002801t = gmtime(&ti);2802snprintf(ts, sizeof(ts), "%04d-%02d-%02dT%02d:%02d:%02d",2803t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour,2804t->tm_min, t->tm_sec);28052806return (ts);2807}28082809static const char *2810dyn_str(struct readelf *re, uint32_t stab, uint64_t d_val)2811{2812const char *name;28132814if (stab == SHN_UNDEF)2815name = "ERROR";2816else if ((name = elf_strptr(re->elf, stab, d_val)) == NULL) {2817(void) elf_errno(); /* clear error */2818name = "ERROR";2819}28202821return (name);2822}28232824static void2825dump_arch_dyn_val(struct readelf *re, GElf_Dyn *dyn)2826{2827switch (re->ehdr.e_machine) {2828case EM_MIPS:2829case EM_MIPS_RS3_LE:2830switch (dyn->d_tag) {2831case DT_MIPS_RLD_VERSION:2832case DT_MIPS_LOCAL_GOTNO:2833case DT_MIPS_CONFLICTNO:2834case DT_MIPS_LIBLISTNO:2835case DT_MIPS_SYMTABNO:2836case DT_MIPS_UNREFEXTNO:2837case DT_MIPS_GOTSYM:2838case DT_MIPS_HIPAGENO:2839case DT_MIPS_DELTA_CLASS_NO:2840case DT_MIPS_DELTA_INSTANCE_NO:2841case DT_MIPS_DELTA_RELOC_NO:2842case DT_MIPS_DELTA_SYM_NO:2843case DT_MIPS_DELTA_CLASSSYM_NO:2844case DT_MIPS_LOCALPAGE_GOTIDX:2845case DT_MIPS_LOCAL_GOTIDX:2846case DT_MIPS_HIDDEN_GOTIDX:2847case DT_MIPS_PROTECTED_GOTIDX:2848printf(" %ju\n", (uintmax_t) dyn->d_un.d_val);2849break;2850case DT_MIPS_ICHECKSUM:2851case DT_MIPS_FLAGS:2852case DT_MIPS_BASE_ADDRESS:2853case DT_MIPS_CONFLICT:2854case DT_MIPS_LIBLIST:2855case DT_MIPS_RLD_MAP:2856case DT_MIPS_DELTA_CLASS:2857case DT_MIPS_DELTA_INSTANCE:2858case DT_MIPS_DELTA_RELOC:2859case DT_MIPS_DELTA_SYM:2860case DT_MIPS_DELTA_CLASSSYM:2861case DT_MIPS_CXX_FLAGS:2862case DT_MIPS_PIXIE_INIT:2863case DT_MIPS_SYMBOL_LIB:2864case DT_MIPS_OPTIONS:2865case DT_MIPS_INTERFACE:2866case DT_MIPS_DYNSTR_ALIGN:2867case DT_MIPS_INTERFACE_SIZE:2868case DT_MIPS_RLD_TEXT_RESOLVE_ADDR:2869case DT_MIPS_COMPACT_SIZE:2870case DT_MIPS_GP_VALUE:2871case DT_MIPS_AUX_DYNAMIC:2872case DT_MIPS_PLTGOT:2873case DT_MIPS_RLD_OBJ_UPDATE:2874case DT_MIPS_RWPLT:2875printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val);2876break;2877case DT_MIPS_IVERSION:2878case DT_MIPS_PERF_SUFFIX:2879case DT_MIPS_TIME_STAMP:2880printf(" %s\n", timestamp(dyn->d_un.d_val));2881break;2882default:2883printf("\n");2884break;2885}2886break;2887default:2888printf("\n");2889break;2890}2891}28922893static void2894dump_flags(struct flag_desc *desc, uint64_t val)2895{2896struct flag_desc *fd;28972898for (fd = desc; fd->flag != 0; fd++) {2899if (val & fd->flag) {2900val &= ~fd->flag;2901printf(" %s", fd->desc);2902}2903}2904if (val != 0)2905printf(" unknown (0x%jx)", (uintmax_t)val);2906printf("\n");2907}29082909static struct flag_desc dt_flags[] = {2910{ DF_ORIGIN, "ORIGIN" },2911{ DF_SYMBOLIC, "SYMBOLIC" },2912{ DF_TEXTREL, "TEXTREL" },2913{ DF_BIND_NOW, "BIND_NOW" },2914{ DF_STATIC_TLS, "STATIC_TLS" },2915{ 0, NULL }2916};29172918static struct flag_desc dt_flags_1[] = {2919{ DF_1_BIND_NOW, "NOW" },2920{ DF_1_GLOBAL, "GLOBAL" },2921{ 0x4, "GROUP" },2922{ DF_1_NODELETE, "NODELETE" },2923{ DF_1_LOADFLTR, "LOADFLTR" },2924{ 0x20, "INITFIRST" },2925{ DF_1_NOOPEN, "NOOPEN" },2926{ DF_1_ORIGIN, "ORIGIN" },2927{ 0x100, "DIRECT" },2928{ DF_1_INTERPOSE, "INTERPOSE" },2929{ DF_1_NODEFLIB, "NODEFLIB" },2930{ 0x1000, "NODUMP" },2931{ 0x2000, "CONFALT" },2932{ 0x4000, "ENDFILTEE" },2933{ 0x8000, "DISPRELDNE" },2934{ 0x10000, "DISPRELPND" },2935{ 0x20000, "NODIRECT" },2936{ 0x40000, "IGNMULDEF" },2937{ 0x80000, "NOKSYMS" },2938{ 0x100000, "NOHDR" },2939{ 0x200000, "EDITED" },2940{ 0x400000, "NORELOC" },2941{ 0x800000, "SYMINTPOSE" },2942{ 0x1000000, "GLOBAUDIT" },2943{ 0x02000000, "SINGLETON" },2944{ 0x04000000, "STUB" },2945{ DF_1_PIE, "PIE" },2946{ 0, NULL }2947};29482949static void2950dump_dyn_val(struct readelf *re, GElf_Dyn *dyn, uint32_t stab)2951{2952const char *name;29532954if (dyn->d_tag >= DT_LOPROC && dyn->d_tag <= DT_HIPROC &&2955dyn->d_tag != DT_AUXILIARY && dyn->d_tag != DT_FILTER) {2956dump_arch_dyn_val(re, dyn);2957return;2958}29592960/* These entry values are index into the string table. */2961name = NULL;2962if (dyn->d_tag == DT_AUXILIARY || dyn->d_tag == DT_FILTER ||2963dyn->d_tag == DT_NEEDED || dyn->d_tag == DT_SONAME ||2964dyn->d_tag == DT_RPATH || dyn->d_tag == DT_RUNPATH)2965name = dyn_str(re, stab, dyn->d_un.d_val);29662967switch(dyn->d_tag) {2968case DT_NULL:2969case DT_PLTGOT:2970case DT_HASH:2971case DT_STRTAB:2972case DT_SYMTAB:2973case DT_RELA:2974case DT_INIT:2975case DT_SYMBOLIC:2976case DT_REL:2977case DT_DEBUG:2978case DT_TEXTREL:2979case DT_JMPREL:2980case DT_FINI:2981case DT_VERDEF:2982case DT_VERNEED:2983case DT_VERSYM:2984case DT_GNU_HASH:2985case DT_GNU_LIBLIST:2986case DT_GNU_CONFLICT:2987printf(" 0x%jx\n", (uintmax_t) dyn->d_un.d_val);2988break;2989case DT_PLTRELSZ:2990case DT_RELASZ:2991case DT_RELAENT:2992case DT_STRSZ:2993case DT_SYMENT:2994case DT_RELSZ:2995case DT_RELENT:2996case DT_PREINIT_ARRAYSZ:2997case DT_INIT_ARRAYSZ:2998case DT_FINI_ARRAYSZ:2999case DT_GNU_CONFLICTSZ:3000case DT_GNU_LIBLISTSZ:3001printf(" %ju (bytes)\n", (uintmax_t) dyn->d_un.d_val);3002break;3003case DT_RELACOUNT:3004case DT_RELCOUNT:3005case DT_VERDEFNUM:3006case DT_VERNEEDNUM:3007printf(" %ju\n", (uintmax_t) dyn->d_un.d_val);3008break;3009case DT_AUXILIARY:3010printf(" Auxiliary library: [%s]\n", name);3011break;3012case DT_FILTER:3013printf(" Filter library: [%s]\n", name);3014break;3015case DT_NEEDED:3016printf(" Shared library: [%s]\n", name);3017break;3018case DT_SONAME:3019printf(" Library soname: [%s]\n", name);3020break;3021case DT_RPATH:3022printf(" Library rpath: [%s]\n", name);3023break;3024case DT_RUNPATH:3025printf(" Library runpath: [%s]\n", name);3026break;3027case DT_PLTREL:3028printf(" %s\n", dt_type(re->ehdr.e_machine, dyn->d_un.d_val));3029break;3030case DT_GNU_PRELINKED:3031printf(" %s\n", timestamp(dyn->d_un.d_val));3032break;3033case DT_FLAGS:3034dump_flags(dt_flags, dyn->d_un.d_val);3035break;3036case DT_FLAGS_1:3037dump_flags(dt_flags_1, dyn->d_un.d_val);3038break;3039default:3040printf("\n");3041}3042}30433044static void3045dump_rel(struct readelf *re, struct section *s, Elf_Data *d)3046{3047GElf_Rel r;3048const char *symname;3049uint64_t symval;3050int i, len;3051uint32_t type;3052uint8_t type2, type3;30533054if (s->link >= re->shnum)3055return;30563057#define REL_HDR "r_offset", "r_info", "r_type", "st_value", "st_name"3058#define REL_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \3059elftc_reloc_type_str(re->ehdr.e_machine, \3060ELF32_R_TYPE(r.r_info)), (uintmax_t)symval, symname3061#define REL_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \3062elftc_reloc_type_str(re->ehdr.e_machine, type), \3063(uintmax_t)symval, symname30643065printf("\nRelocation section (%s):\n", s->name);3066if (re->ec == ELFCLASS32)3067printf("%-8s %-8s %-19s %-8s %s\n", REL_HDR);3068else {3069if (re->options & RE_WW)3070printf("%-16s %-16s %-24s %-16s %s\n", REL_HDR);3071else3072printf("%-12s %-12s %-19s %-16s %s\n", REL_HDR);3073}3074assert(d->d_size == s->sz);3075if (!get_ent_count(s, &len))3076return;3077for (i = 0; i < len; i++) {3078if (gelf_getrel(d, i, &r) != &r) {3079warnx("gelf_getrel failed: %s", elf_errmsg(-1));3080continue;3081}3082symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info));3083symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info));3084if (re->ec == ELFCLASS32) {3085r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info),3086ELF64_R_TYPE(r.r_info));3087printf("%8.8jx %8.8jx %-19.19s %8.8jx %s\n", REL_CT32);3088} else {3089type = ELF64_R_TYPE(r.r_info);3090if (re->ehdr.e_machine == EM_MIPS) {3091type2 = (type >> 8) & 0xFF;3092type3 = (type >> 16) & 0xFF;3093type = type & 0xFF;3094} else {3095type2 = type3 = 0;3096}3097if (re->options & RE_WW)3098printf("%16.16jx %16.16jx %-24.24s"3099" %16.16jx %s\n", REL_CT64);3100else3101printf("%12.12jx %12.12jx %-19.19s"3102" %16.16jx %s\n", REL_CT64);3103if (re->ehdr.e_machine == EM_MIPS) {3104if (re->options & RE_WW) {3105printf("%32s: %s\n", "Type2",3106elftc_reloc_type_str(EM_MIPS,3107type2));3108printf("%32s: %s\n", "Type3",3109elftc_reloc_type_str(EM_MIPS,3110type3));3111} else {3112printf("%24s: %s\n", "Type2",3113elftc_reloc_type_str(EM_MIPS,3114type2));3115printf("%24s: %s\n", "Type3",3116elftc_reloc_type_str(EM_MIPS,3117type3));3118}3119}3120}3121}31223123#undef REL_HDR3124#undef REL_CT3125}31263127static void3128dump_rela(struct readelf *re, struct section *s, Elf_Data *d)3129{3130GElf_Rela r;3131const char *symname;3132uint64_t symval;3133int i, len;3134uint32_t type;3135uint8_t type2, type3;31363137if (s->link >= re->shnum)3138return;31393140#define RELA_HDR "r_offset", "r_info", "r_type", "st_value", \3141"st_name + r_addend"3142#define RELA_CT32 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \3143elftc_reloc_type_str(re->ehdr.e_machine, \3144ELF32_R_TYPE(r.r_info)), (uintmax_t)symval, symname3145#define RELA_CT64 (uintmax_t)r.r_offset, (uintmax_t)r.r_info, \3146elftc_reloc_type_str(re->ehdr.e_machine, type), \3147(uintmax_t)symval, symname31483149printf("\nRelocation section with addend (%s):\n", s->name);3150if (re->ec == ELFCLASS32)3151printf("%-8s %-8s %-19s %-8s %s\n", RELA_HDR);3152else {3153if (re->options & RE_WW)3154printf("%-16s %-16s %-24s %-16s %s\n", RELA_HDR);3155else3156printf("%-12s %-12s %-19s %-16s %s\n", RELA_HDR);3157}3158assert(d->d_size == s->sz);3159if (!get_ent_count(s, &len))3160return;3161for (i = 0; i < len; i++) {3162if (gelf_getrela(d, i, &r) != &r) {3163warnx("gelf_getrel failed: %s", elf_errmsg(-1));3164continue;3165}3166symname = get_symbol_name(re, s->link, GELF_R_SYM(r.r_info));3167symval = get_symbol_value(re, s->link, GELF_R_SYM(r.r_info));3168if (re->ec == ELFCLASS32) {3169r.r_info = ELF32_R_INFO(ELF64_R_SYM(r.r_info),3170ELF64_R_TYPE(r.r_info));3171printf("%8.8jx %8.8jx %-19.19s %8.8jx %s", RELA_CT32);3172printf(" + %x\n", (uint32_t) r.r_addend);3173} else {3174type = ELF64_R_TYPE(r.r_info);3175if (re->ehdr.e_machine == EM_MIPS) {3176type2 = (type >> 8) & 0xFF;3177type3 = (type >> 16) & 0xFF;3178type = type & 0xFF;3179} else {3180type2 = type3 = 0;3181}3182if (re->options & RE_WW)3183printf("%16.16jx %16.16jx %-24.24s"3184" %16.16jx %s", RELA_CT64);3185else3186printf("%12.12jx %12.12jx %-19.19s"3187" %16.16jx %s", RELA_CT64);3188printf(" + %jx\n", (uintmax_t) r.r_addend);3189if (re->ehdr.e_machine == EM_MIPS) {3190if (re->options & RE_WW) {3191printf("%32s: %s\n", "Type2",3192elftc_reloc_type_str(EM_MIPS,3193type2));3194printf("%32s: %s\n", "Type3",3195elftc_reloc_type_str(EM_MIPS,3196type3));3197} else {3198printf("%24s: %s\n", "Type2",3199elftc_reloc_type_str(EM_MIPS,3200type2));3201printf("%24s: %s\n", "Type3",3202elftc_reloc_type_str(EM_MIPS,3203type3));3204}3205}3206}3207}32083209#undef RELA_HDR3210#undef RELA_CT3211}32123213static void3214dump_reloc(struct readelf *re)3215{3216struct section *s;3217Elf_Data *d;3218int i, elferr;32193220for (i = 0; (size_t)i < re->shnum; i++) {3221s = &re->sl[i];3222if (s->type == SHT_REL || s->type == SHT_RELA) {3223(void) elf_errno();3224if ((d = elf_getdata(s->scn, NULL)) == NULL) {3225elferr = elf_errno();3226if (elferr != 0)3227warnx("elf_getdata failed: %s",3228elf_errmsg(elferr));3229continue;3230}3231if (s->type == SHT_REL)3232dump_rel(re, s, d);3233else3234dump_rela(re, s, d);3235}3236}3237}32383239static void3240dump_symtab(struct readelf *re, int i)3241{3242struct section *s;3243Elf_Data *d;3244GElf_Sym sym;3245const char *name;3246uint32_t stab;3247int elferr, j, len;3248uint16_t vs;32493250s = &re->sl[i];3251if (s->link >= re->shnum)3252return;3253stab = s->link;3254(void) elf_errno();3255if ((d = elf_getdata(s->scn, NULL)) == NULL) {3256elferr = elf_errno();3257if (elferr != 0)3258warnx("elf_getdata failed: %s", elf_errmsg(elferr));3259return;3260}3261if (d->d_size <= 0)3262return;3263if (!get_ent_count(s, &len))3264return;3265printf("\nSymbol table '%s' contains %d entries:\n", s->name, len);3266printf("%7s%9s%14s%5s%8s%6s%9s%5s\n", "Num:", "Value", "Size", "Type",3267"Bind", "Vis", "Ndx", "Name");32683269for (j = 0; j < len; j++) {3270if (gelf_getsym(d, j, &sym) != &sym) {3271warnx("gelf_getsym failed: %s", elf_errmsg(-1));3272continue;3273}3274printf("%6d:", j);3275printf(" %16.16jx", (uintmax_t) sym.st_value);3276printf(" %5ju", (uintmax_t) sym.st_size);3277printf(" %-7s", st_type(re->ehdr.e_machine,3278re->ehdr.e_ident[EI_OSABI], GELF_ST_TYPE(sym.st_info)));3279printf(" %-6s", st_bind(GELF_ST_BIND(sym.st_info)));3280printf(" %-8s", st_vis(GELF_ST_VISIBILITY(sym.st_other)));3281printf(" %3s", st_shndx(sym.st_shndx));3282if ((name = elf_strptr(re->elf, stab, sym.st_name)) != NULL)3283printf(" %s", name);3284/* Append symbol version string for SHT_DYNSYM symbol table. */3285if (s->type == SHT_DYNSYM && re->ver != NULL &&3286re->vs != NULL && re->vs[j] > 1) {3287vs = re->vs[j] & VERSYM_VERSION;3288if (vs >= re->ver_sz || re->ver[vs].name == NULL) {3289warnx("invalid versym version index %u", vs);3290break;3291}3292if (re->vs[j] & VERSYM_HIDDEN || re->ver[vs].type == 0)3293printf("@%s (%d)", re->ver[vs].name, vs);3294else3295printf("@@%s (%d)", re->ver[vs].name, vs);3296}3297putchar('\n');3298}32993300}33013302static void3303dump_symtabs(struct readelf *re)3304{3305GElf_Dyn dyn;3306Elf_Data *d;3307struct section *s;3308uint64_t dyn_off;3309int elferr, i, len;33103311/*3312* If -D is specified, only dump the symbol table specified by3313* the DT_SYMTAB entry in the .dynamic section.3314*/3315dyn_off = 0;3316if (re->options & RE_DD) {3317s = NULL;3318for (i = 0; (size_t)i < re->shnum; i++)3319if (re->sl[i].type == SHT_DYNAMIC) {3320s = &re->sl[i];3321break;3322}3323if (s == NULL)3324return;3325(void) elf_errno();3326if ((d = elf_getdata(s->scn, NULL)) == NULL) {3327elferr = elf_errno();3328if (elferr != 0)3329warnx("elf_getdata failed: %s", elf_errmsg(-1));3330return;3331}3332if (d->d_size <= 0)3333return;3334if (!get_ent_count(s, &len))3335return;33363337for (i = 0; i < len; i++) {3338if (gelf_getdyn(d, i, &dyn) != &dyn) {3339warnx("gelf_getdyn failed: %s", elf_errmsg(-1));3340continue;3341}3342if (dyn.d_tag == DT_SYMTAB) {3343dyn_off = dyn.d_un.d_val;3344break;3345}3346}3347}33483349/* Find and dump symbol tables. */3350for (i = 0; (size_t)i < re->shnum; i++) {3351s = &re->sl[i];3352if (s->type == SHT_SYMTAB || s->type == SHT_DYNSYM) {3353if (re->options & RE_DD) {3354if (dyn_off == s->addr) {3355dump_symtab(re, i);3356break;3357}3358} else3359dump_symtab(re, i);3360}3361}3362}33633364static void3365dump_svr4_hash(struct section *s)3366{3367Elf_Data *d;3368uint32_t *buf;3369uint32_t nbucket, nchain;3370uint32_t *bucket, *chain;3371uint32_t *bl, *c, maxl, total;3372int elferr, i, j;33733374/* Read and parse the content of .hash section. */3375(void) elf_errno();3376if ((d = elf_getdata(s->scn, NULL)) == NULL) {3377elferr = elf_errno();3378if (elferr != 0)3379warnx("elf_getdata failed: %s", elf_errmsg(elferr));3380return;3381}3382if (d->d_size < 2 * sizeof(uint32_t)) {3383warnx(".hash section too small");3384return;3385}3386buf = d->d_buf;3387nbucket = buf[0];3388nchain = buf[1];3389if (nbucket <= 0 || nchain <= 0) {3390warnx("Malformed .hash section");3391return;3392}3393if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) {3394warnx("Malformed .hash section");3395return;3396}3397bucket = &buf[2];3398chain = &buf[2 + nbucket];33993400maxl = 0;3401if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)3402errx(EXIT_FAILURE, "calloc failed");3403for (i = 0; (uint32_t)i < nbucket; i++)3404for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j])3405if (++bl[i] > maxl)3406maxl = bl[i];3407if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)3408errx(EXIT_FAILURE, "calloc failed");3409for (i = 0; (uint32_t)i < nbucket; i++)3410c[bl[i]]++;3411printf("\nHistogram for bucket list length (total of %u buckets):\n",3412nbucket);3413printf(" Length\tNumber\t\t%% of total\tCoverage\n");3414total = 0;3415for (i = 0; (uint32_t)i <= maxl; i++) {3416total += c[i] * i;3417printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i],3418c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));3419}3420free(c);3421free(bl);3422}34233424static void3425dump_svr4_hash64(struct readelf *re, struct section *s)3426{3427Elf_Data *d, dst;3428uint64_t *buf;3429uint64_t nbucket, nchain;3430uint64_t *bucket, *chain;3431uint64_t *bl, *c, maxl, total;3432int elferr, i, j;34333434/*3435* ALPHA uses 64-bit hash entries. Since libelf assumes that3436* .hash section contains only 32-bit entry, an explicit3437* gelf_xlatetom is needed here.3438*/3439(void) elf_errno();3440if ((d = elf_rawdata(s->scn, NULL)) == NULL) {3441elferr = elf_errno();3442if (elferr != 0)3443warnx("elf_rawdata failed: %s",3444elf_errmsg(elferr));3445return;3446}3447d->d_type = ELF_T_XWORD;3448memcpy(&dst, d, sizeof(Elf_Data));3449if (gelf_xlatetom(re->elf, &dst, d,3450re->ehdr.e_ident[EI_DATA]) != &dst) {3451warnx("gelf_xlatetom failed: %s", elf_errmsg(-1));3452return;3453}3454if (dst.d_size < 2 * sizeof(uint64_t)) {3455warnx(".hash section too small");3456return;3457}3458buf = dst.d_buf;3459nbucket = buf[0];3460nchain = buf[1];3461if (nbucket <= 0 || nchain <= 0) {3462warnx("Malformed .hash section");3463return;3464}3465if (d->d_size != (nbucket + nchain + 2) * sizeof(uint32_t)) {3466warnx("Malformed .hash section");3467return;3468}3469bucket = &buf[2];3470chain = &buf[2 + nbucket];34713472maxl = 0;3473if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)3474errx(EXIT_FAILURE, "calloc failed");3475for (i = 0; (uint32_t)i < nbucket; i++)3476for (j = bucket[i]; j > 0 && (uint32_t)j < nchain; j = chain[j])3477if (++bl[i] > maxl)3478maxl = bl[i];3479if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)3480errx(EXIT_FAILURE, "calloc failed");3481for (i = 0; (uint64_t)i < nbucket; i++)3482c[bl[i]]++;3483printf("Histogram for bucket list length (total of %ju buckets):\n",3484(uintmax_t)nbucket);3485printf(" Length\tNumber\t\t%% of total\tCoverage\n");3486total = 0;3487for (i = 0; (uint64_t)i <= maxl; i++) {3488total += c[i] * i;3489printf("%7u\t%-10ju\t(%5.1f%%)\t%5.1f%%\n", i, (uintmax_t)c[i],3490c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));3491}3492free(c);3493free(bl);3494}34953496static void3497dump_gnu_hash(struct readelf *re, struct section *s)3498{3499struct section *ds;3500Elf_Data *d;3501uint32_t *buf;3502uint32_t *bucket, *chain;3503uint32_t nbucket, nchain, symndx, maskwords;3504uint32_t *bl, *c, maxl, total;3505int elferr, dynsymcount, i, j;35063507(void) elf_errno();3508if ((d = elf_getdata(s->scn, NULL)) == NULL) {3509elferr = elf_errno();3510if (elferr != 0)3511warnx("elf_getdata failed: %s",3512elf_errmsg(elferr));3513return;3514}3515if (d->d_size < 4 * sizeof(uint32_t)) {3516warnx(".gnu.hash section too small");3517return;3518}3519buf = d->d_buf;3520nbucket = buf[0];3521symndx = buf[1];3522maskwords = buf[2];3523buf += 4;3524if (s->link >= re->shnum)3525return;3526ds = &re->sl[s->link];3527if (!get_ent_count(ds, &dynsymcount))3528return;3529if (symndx >= (uint32_t)dynsymcount) {3530warnx("Malformed .gnu.hash section (symndx out of range)");3531return;3532}3533nchain = dynsymcount - symndx;3534if (d->d_size != 4 * sizeof(uint32_t) + maskwords *3535(re->ec == ELFCLASS32 ? sizeof(uint32_t) : sizeof(uint64_t)) +3536(nbucket + nchain) * sizeof(uint32_t)) {3537warnx("Malformed .gnu.hash section");3538return;3539}3540bucket = buf + (re->ec == ELFCLASS32 ? maskwords : maskwords * 2);3541chain = bucket + nbucket;35423543maxl = 0;3544if ((bl = calloc(nbucket, sizeof(*bl))) == NULL)3545errx(EXIT_FAILURE, "calloc failed");3546for (i = 0; (uint32_t)i < nbucket; i++)3547for (j = bucket[i]; j > 0 && (uint32_t)j - symndx < nchain;3548j++) {3549if (++bl[i] > maxl)3550maxl = bl[i];3551if (chain[j - symndx] & 1)3552break;3553}3554if ((c = calloc(maxl + 1, sizeof(*c))) == NULL)3555errx(EXIT_FAILURE, "calloc failed");3556for (i = 0; (uint32_t)i < nbucket; i++)3557c[bl[i]]++;3558printf("Histogram for bucket list length (total of %u buckets):\n",3559nbucket);3560printf(" Length\tNumber\t\t%% of total\tCoverage\n");3561total = 0;3562for (i = 0; (uint32_t)i <= maxl; i++) {3563total += c[i] * i;3564printf("%7u\t%-10u\t(%5.1f%%)\t%5.1f%%\n", i, c[i],3565c[i] * 100.0 / nbucket, total * 100.0 / (nchain - 1));3566}3567free(c);3568free(bl);3569}35703571static struct flag_desc gnu_property_aarch64_feature_1_and_bits[] = {3572{ GNU_PROPERTY_AARCH64_FEATURE_1_BTI, "BTI" },3573{ GNU_PROPERTY_AARCH64_FEATURE_1_PAC, "PAC" },3574{ 0, NULL }3575};35763577static struct flag_desc_list gnu_property_aarch64[] = {3578{3579GNU_PROPERTY_AARCH64_FEATURE_1_AND,3580"AArch64 features",3581gnu_property_aarch64_feature_1_and_bits3582},3583{ 0, NULL, NULL }3584};35853586static struct flag_desc gnu_property_x86_feature_1_and_bits[] = {3587{ GNU_PROPERTY_X86_FEATURE_1_IBT, "IBT" },3588{ GNU_PROPERTY_X86_FEATURE_1_SHSTK, "SHSTK" },3589{ 0, NULL }3590};35913592static struct flag_desc_list gnu_property_x86[] = {3593{3594GNU_PROPERTY_X86_FEATURE_1_AND,3595"x64 features",3596gnu_property_x86_feature_1_and_bits3597},3598{ 0, NULL, NULL }3599};36003601static struct {3602unsigned int emachine;3603struct flag_desc_list *flag_list;3604} gnu_property_archs[] = {3605{ EM_AARCH64, gnu_property_aarch64 },3606{ EM_X86_64, gnu_property_x86 },3607{ 0, NULL }3608};36093610static void3611dump_gnu_property_type_0(struct readelf *re, const char *buf, size_t sz)3612{3613struct flag_desc_list *desc_list;3614struct flag_desc *desc;3615size_t i;3616uint32_t type, prop_sz;36173618printf(" Properties: ");3619while (sz > 0) {3620if (sz < 8)3621goto bad;36223623type = *(const uint32_t *)(const void *)buf;3624prop_sz = *(const uint32_t *)(const void *)(buf + 4);3625buf += 8;3626sz -= 8;36273628if (prop_sz > sz)3629goto bad;36303631if (type >= GNU_PROPERTY_LOPROC &&3632type <= GNU_PROPERTY_HIPROC) {3633desc_list = NULL;3634for (i = 0; gnu_property_archs[i].flag_list != NULL;3635i++) {3636if (gnu_property_archs[i].emachine ==3637re->ehdr.e_machine) {3638desc_list =3639gnu_property_archs[i].flag_list;3640break;3641}3642}3643if (desc_list == NULL) {3644printf("machine type %x unknown\n",3645re->ehdr.e_machine);3646goto unknown;3647}36483649desc = NULL;3650for (i = 0; desc_list[i].desc != NULL; i++) {3651if (desc_list[i].type == type) {3652desc = desc_list[i].desc;3653break;3654}3655}3656if (desc != NULL) {3657printf("%s:", desc_list[i].desc_str);3658if (prop_sz != 4)3659goto bad;3660dump_flags(desc,3661*(const uint32_t *)(const void *)buf);3662}3663}36643665buf += roundup2(prop_sz, 8);3666sz -= roundup2(prop_sz, 8);3667}3668return;3669bad:3670printf("corrupt GNU property\n");3671unknown:3672printf("remaining description data:");3673for (i = 0; i < sz; i++)3674printf(" %02x", (unsigned char)buf[i]);3675printf("\n");3676}36773678static void3679dump_hash(struct readelf *re)3680{3681struct section *s;3682int i;36833684for (i = 0; (size_t) i < re->shnum; i++) {3685s = &re->sl[i];3686if (s->type == SHT_HASH || s->type == SHT_GNU_HASH) {3687if (s->type == SHT_GNU_HASH)3688dump_gnu_hash(re, s);3689else if (re->ehdr.e_machine == EM_ALPHA &&3690s->entsize == 8)3691dump_svr4_hash64(re, s);3692else3693dump_svr4_hash(s);3694}3695}3696}36973698static void3699dump_notes(struct readelf *re)3700{3701struct section *s;3702const char *rawfile;3703GElf_Phdr phdr;3704Elf_Data *d;3705size_t filesize, phnum;3706int i, elferr;37073708if (re->ehdr.e_type == ET_CORE) {3709/*3710* Search program headers in the core file for3711* PT_NOTE entry.3712*/3713if (elf_getphnum(re->elf, &phnum) == 0) {3714warnx("elf_getphnum failed: %s", elf_errmsg(-1));3715return;3716}3717if (phnum == 0)3718return;3719if ((rawfile = elf_rawfile(re->elf, &filesize)) == NULL) {3720warnx("elf_rawfile failed: %s", elf_errmsg(-1));3721return;3722}3723for (i = 0; (size_t) i < phnum; i++) {3724if (gelf_getphdr(re->elf, i, &phdr) != &phdr) {3725warnx("gelf_getphdr failed: %s",3726elf_errmsg(-1));3727continue;3728}3729if (phdr.p_type == PT_NOTE) {3730if (phdr.p_offset >= filesize ||3731phdr.p_filesz > filesize - phdr.p_offset) {3732warnx("invalid PHDR offset");3733continue;3734}3735dump_notes_content(re, rawfile + phdr.p_offset,3736phdr.p_filesz, phdr.p_offset);3737}3738}37393740} else {3741/*3742* For objects other than core files, Search for3743* SHT_NOTE sections.3744*/3745for (i = 0; (size_t) i < re->shnum; i++) {3746s = &re->sl[i];3747if (s->type == SHT_NOTE) {3748(void) elf_errno();3749if ((d = elf_getdata(s->scn, NULL)) == NULL) {3750elferr = elf_errno();3751if (elferr != 0)3752warnx("elf_getdata failed: %s",3753elf_errmsg(elferr));3754continue;3755}3756dump_notes_content(re, d->d_buf, d->d_size,3757s->off);3758}3759}3760}3761}37623763static struct flag_desc note_feature_ctl_flags[] = {3764{ NT_FREEBSD_FCTL_ASLR_DISABLE, "ASLR_DISABLE" },3765{ NT_FREEBSD_FCTL_PROTMAX_DISABLE, "PROTMAX_DISABLE" },3766{ NT_FREEBSD_FCTL_STKGAP_DISABLE, "STKGAP_DISABLE" },3767{ NT_FREEBSD_FCTL_WXNEEDED, "WXNEEDED" },3768{ NT_FREEBSD_FCTL_LA48, "LA48" },3769{ 0, NULL }3770};37713772static bool3773dump_note_string(const char *description, const char *s, size_t len)3774{3775size_t i;37763777if (len == 0 || s[--len] != '\0') {3778return (false);3779} else {3780for (i = 0; i < len; i++)3781if (!isprint(s[i]))3782return (false);3783}37843785printf(" %s: %s\n", description, s);3786return (true);3787}37883789struct note_desc {3790uint32_t type;3791const char *description;3792bool (*fp)(const char *, const char *, size_t);3793};37943795static struct note_desc xen_notes[] = {3796{ 5, "Xen version", dump_note_string },3797{ 6, "Guest OS", dump_note_string },3798{ 7, "Guest version", dump_note_string },3799{ 8, "Loader", dump_note_string },3800{ 9, "PAE mode", dump_note_string },3801{ 10, "Features", dump_note_string },3802{ 11, "BSD symtab", dump_note_string },3803{ 0, NULL, NULL }3804};38053806static void3807dump_notes_data(struct readelf *re, const char *name, uint32_t type,3808const char *buf, size_t sz)3809{3810struct note_desc *nd;3811size_t i;3812const uint32_t *ubuf;38133814/* Note data is at least 4-byte aligned. */3815if (((uintptr_t)buf & 3) != 0) {3816warnx("bad note data alignment");3817goto unknown;3818}3819ubuf = (const uint32_t *)(const void *)buf;38203821if (strcmp(name, "FreeBSD") == 0) {3822switch (type) {3823case NT_FREEBSD_ABI_TAG:3824if (sz != 4)3825goto unknown;3826printf(" ABI tag: %u\n", ubuf[0]);3827return;3828/* NT_FREEBSD_NOINIT_TAG carries no data, treat as unknown. */3829case NT_FREEBSD_ARCH_TAG:3830printf(" Arch tag: %s\n", buf);3831return;3832case NT_FREEBSD_FEATURE_CTL:3833if (sz != 4)3834goto unknown;3835printf(" Features:");3836dump_flags(note_feature_ctl_flags, ubuf[0]);3837return;3838}3839} else if (strcmp(name, "Go") == 0) {3840if (type == 4) {3841printf(" Build ID: ");3842for (i = 0; i < sz; i++) {3843printf(isprint(buf[i]) ? "%c" : "<%02x>",3844buf[i]);3845}3846printf("\n");3847return;3848}3849} else if (strcmp(name, "GNU") == 0) {3850switch (type) {3851case NT_GNU_PROPERTY_TYPE_0:3852dump_gnu_property_type_0(re, buf, sz);3853return;3854case NT_GNU_BUILD_ID:3855printf(" Build ID: ");3856for (i = 0; i < sz; i++)3857printf("%02x", (unsigned char)buf[i]);3858printf("\n");3859return;3860}3861} else if (strcmp(name, "Xen") == 0) {3862for (nd = xen_notes; nd->description != NULL; nd++) {3863if (nd->type == type) {3864if (nd->fp(nd->description, buf, sz))3865return;3866else3867break;3868}3869}3870}3871unknown:3872printf(" description data:");3873for (i = 0; i < sz; i++)3874printf(" %02x", (unsigned char)buf[i]);3875printf("\n");3876}38773878static void3879dump_notes_content(struct readelf *re, const char *buf, size_t sz, off_t off)3880{3881Elf_Note *note;3882const char *end, *name;3883uint32_t namesz, descsz;38843885printf("\nNotes at offset %#010jx with length %#010jx:\n",3886(uintmax_t) off, (uintmax_t) sz);3887printf(" %-13s %-15s %s\n", "Owner", "Data size", "Description");3888end = buf + sz;3889while (buf < end) {3890if (buf + sizeof(*note) > end) {3891warnx("invalid note header");3892return;3893}3894note = (Elf_Note *)(uintptr_t) buf;3895namesz = roundup2(note->n_namesz, 4);3896descsz = roundup2(note->n_descsz, 4);3897if (namesz < note->n_namesz || descsz < note->n_descsz ||3898buf + namesz + descsz > end) {3899warnx("invalid note header");3900return;3901}3902buf += sizeof(Elf_Note);3903name = buf;3904buf += namesz;3905/*3906* The name field is required to be nul-terminated, and3907* n_namesz includes the terminating nul in observed3908* implementations (contrary to the ELF-64 spec). A special3909* case is needed for cores generated by some older Linux3910* versions, which write a note named "CORE" without a nul3911* terminator and n_namesz = 4.3912*/3913if (note->n_namesz == 0)3914name = "";3915else if (note->n_namesz == 4 && strncmp(name, "CORE", 4) == 0)3916name = "CORE";3917else if (strnlen(name, note->n_namesz) >= note->n_namesz)3918name = "<invalid>";3919printf(" %-13s %#010jx", name, (uintmax_t) note->n_descsz);3920printf(" %s\n", note_type(name, re->ehdr.e_type,3921note->n_type));3922dump_notes_data(re, name, note->n_type, buf, note->n_descsz);3923buf += descsz;3924}3925}39263927/*3928* Symbol versioning sections are the same for 32bit and 64bit3929* ELF objects.3930*/3931#define Elf_Verdef Elf32_Verdef3932#define Elf_Verdaux Elf32_Verdaux3933#define Elf_Verneed Elf32_Verneed3934#define Elf_Vernaux Elf32_Vernaux39353936#define SAVE_VERSION_NAME(x, n, t) \3937do { \3938while (x >= re->ver_sz) { \3939nv = realloc(re->ver, \3940sizeof(*re->ver) * re->ver_sz * 2); \3941if (nv == NULL) { \3942warn("realloc failed"); \3943free(re->ver); \3944return; \3945} \3946re->ver = nv; \3947for (i = re->ver_sz; i < re->ver_sz * 2; i++) { \3948re->ver[i].name = NULL; \3949re->ver[i].type = 0; \3950} \3951re->ver_sz *= 2; \3952} \3953if (x > 1) { \3954re->ver[x].name = n; \3955re->ver[x].type = t; \3956} \3957} while (0)395839593960static void3961dump_verdef(struct readelf *re, int dump)3962{3963struct section *s;3964struct symver *nv;3965Elf_Data *d;3966Elf_Verdef *vd;3967Elf_Verdaux *vda;3968uint8_t *buf, *end, *buf2;3969const char *name;3970int elferr, i, j;39713972if ((s = re->vd_s) == NULL)3973return;3974if (s->link >= re->shnum)3975return;39763977if (re->ver == NULL) {3978re->ver_sz = 16;3979if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) ==3980NULL) {3981warn("calloc failed");3982return;3983}3984re->ver[0].name = "*local*";3985re->ver[1].name = "*global*";3986}39873988if (dump)3989printf("\nVersion definition section (%s):\n", s->name);3990(void) elf_errno();3991if ((d = elf_getdata(s->scn, NULL)) == NULL) {3992elferr = elf_errno();3993if (elferr != 0)3994warnx("elf_getdata failed: %s", elf_errmsg(elferr));3995return;3996}3997if (d->d_size == 0)3998return;39994000buf = d->d_buf;4001end = buf + d->d_size;4002while (buf + sizeof(Elf_Verdef) <= end) {4003vd = (Elf_Verdef *) (uintptr_t) buf;4004if (dump) {4005printf(" 0x%4.4lx", (unsigned long)4006(buf - (uint8_t *)d->d_buf));4007printf(" vd_version: %u vd_flags: %d"4008" vd_ndx: %u vd_cnt: %u", vd->vd_version,4009vd->vd_flags, vd->vd_ndx, vd->vd_cnt);4010}4011buf2 = buf + vd->vd_aux;4012j = 0;4013while (buf2 + sizeof(Elf_Verdaux) <= end && j < vd->vd_cnt) {4014vda = (Elf_Verdaux *) (uintptr_t) buf2;4015name = get_string(re, s->link, vda->vda_name);4016if (j == 0) {4017if (dump)4018printf(" vda_name: %s\n", name);4019SAVE_VERSION_NAME((int)vd->vd_ndx, name, 1);4020} else if (dump)4021printf(" 0x%4.4lx parent: %s\n",4022(unsigned long) (buf2 -4023(uint8_t *)d->d_buf), name);4024if (vda->vda_next == 0)4025break;4026buf2 += vda->vda_next;4027j++;4028}4029if (vd->vd_next == 0)4030break;4031buf += vd->vd_next;4032}4033}40344035static void4036dump_verneed(struct readelf *re, int dump)4037{4038struct section *s;4039struct symver *nv;4040Elf_Data *d;4041Elf_Verneed *vn;4042Elf_Vernaux *vna;4043uint8_t *buf, *end, *buf2;4044const char *name;4045int elferr, i, j;40464047if ((s = re->vn_s) == NULL)4048return;4049if (s->link >= re->shnum)4050return;40514052if (re->ver == NULL) {4053re->ver_sz = 16;4054if ((re->ver = calloc(re->ver_sz, sizeof(*re->ver))) ==4055NULL) {4056warn("calloc failed");4057return;4058}4059re->ver[0].name = "*local*";4060re->ver[1].name = "*global*";4061}40624063if (dump)4064printf("\nVersion needed section (%s):\n", s->name);4065(void) elf_errno();4066if ((d = elf_getdata(s->scn, NULL)) == NULL) {4067elferr = elf_errno();4068if (elferr != 0)4069warnx("elf_getdata failed: %s", elf_errmsg(elferr));4070return;4071}4072if (d->d_size == 0)4073return;40744075buf = d->d_buf;4076end = buf + d->d_size;4077while (buf + sizeof(Elf_Verneed) <= end) {4078vn = (Elf_Verneed *) (uintptr_t) buf;4079if (dump) {4080printf(" 0x%4.4lx", (unsigned long)4081(buf - (uint8_t *)d->d_buf));4082printf(" vn_version: %u vn_file: %s vn_cnt: %u\n",4083vn->vn_version,4084get_string(re, s->link, vn->vn_file),4085vn->vn_cnt);4086}4087buf2 = buf + vn->vn_aux;4088j = 0;4089while (buf2 + sizeof(Elf_Vernaux) <= end && j < vn->vn_cnt) {4090vna = (Elf32_Vernaux *) (uintptr_t) buf2;4091if (dump)4092printf(" 0x%4.4lx", (unsigned long)4093(buf2 - (uint8_t *)d->d_buf));4094name = get_string(re, s->link, vna->vna_name);4095if (dump)4096printf(" vna_name: %s vna_flags: %u"4097" vna_other: %u\n", name,4098vna->vna_flags, vna->vna_other);4099SAVE_VERSION_NAME((int)vna->vna_other, name, 0);4100if (vna->vna_next == 0)4101break;4102buf2 += vna->vna_next;4103j++;4104}4105if (vn->vn_next == 0)4106break;4107buf += vn->vn_next;4108}4109}41104111static void4112dump_versym(struct readelf *re)4113{4114int i;4115uint16_t vs;41164117if (re->vs_s == NULL || re->ver == NULL || re->vs == NULL)4118return;4119printf("\nVersion symbol section (%s):\n", re->vs_s->name);4120for (i = 0; i < re->vs_sz; i++) {4121if ((i & 3) == 0) {4122if (i > 0)4123putchar('\n');4124printf(" %03x:", i);4125}4126vs = re->vs[i] & VERSYM_VERSION;4127if (vs >= re->ver_sz || re->ver[vs].name == NULL) {4128warnx("invalid versym version index %u", re->vs[i]);4129break;4130}4131if (re->vs[i] & VERSYM_HIDDEN)4132printf(" %3xh %-12s ", vs,4133re->ver[re->vs[i] & VERSYM_VERSION].name);4134else4135printf(" %3x %-12s ", vs, re->ver[re->vs[i]].name);4136}4137putchar('\n');4138}41394140static void4141dump_ver(struct readelf *re)4142{41434144if (re->vs_s && re->ver && re->vs)4145dump_versym(re);4146if (re->vd_s)4147dump_verdef(re, 1);4148if (re->vn_s)4149dump_verneed(re, 1);4150}41514152static void4153search_ver(struct readelf *re)4154{4155struct section *s;4156Elf_Data *d;4157int elferr, i;41584159for (i = 0; (size_t) i < re->shnum; i++) {4160s = &re->sl[i];4161if (s->type == SHT_SUNW_versym)4162re->vs_s = s;4163if (s->type == SHT_SUNW_verneed)4164re->vn_s = s;4165if (s->type == SHT_SUNW_verdef)4166re->vd_s = s;4167}4168if (re->vd_s)4169dump_verdef(re, 0);4170if (re->vn_s)4171dump_verneed(re, 0);4172if (re->vs_s && re->ver != NULL) {4173(void) elf_errno();4174if ((d = elf_getdata(re->vs_s->scn, NULL)) == NULL) {4175elferr = elf_errno();4176if (elferr != 0)4177warnx("elf_getdata failed: %s",4178elf_errmsg(elferr));4179return;4180}4181if (d->d_size == 0)4182return;4183re->vs = d->d_buf;4184re->vs_sz = d->d_size / sizeof(Elf32_Half);4185}4186}41874188#undef Elf_Verdef4189#undef Elf_Verdaux4190#undef Elf_Verneed4191#undef Elf_Vernaux4192#undef SAVE_VERSION_NAME41934194/*4195* Elf32_Lib and Elf64_Lib are identical.4196*/4197#define Elf_Lib Elf32_Lib41984199static void4200dump_liblist(struct readelf *re)4201{4202struct section *s;4203struct tm *t;4204time_t ti;4205char tbuf[20];4206Elf_Data *d;4207Elf_Lib *lib;4208int i, j, k, elferr, first, len;42094210for (i = 0; (size_t) i < re->shnum; i++) {4211s = &re->sl[i];4212if (s->type != SHT_GNU_LIBLIST)4213continue;4214if (s->link >= re->shnum)4215continue;4216(void) elf_errno();4217if ((d = elf_getdata(s->scn, NULL)) == NULL) {4218elferr = elf_errno();4219if (elferr != 0)4220warnx("elf_getdata failed: %s",4221elf_errmsg(elferr));4222continue;4223}4224if (d->d_size <= 0)4225continue;4226lib = d->d_buf;4227if (!get_ent_count(s, &len))4228continue;4229printf("\nLibrary list section '%s' ", s->name);4230printf("contains %d entries:\n", len);4231printf("%12s%24s%18s%10s%6s\n", "Library", "Time Stamp",4232"Checksum", "Version", "Flags");4233for (j = 0; (uint64_t) j < s->sz / s->entsize; j++) {4234printf("%3d: ", j);4235printf("%-20.20s ",4236get_string(re, s->link, lib->l_name));4237ti = lib->l_time_stamp;4238t = gmtime(&ti);4239snprintf(tbuf, sizeof(tbuf), "%04d-%02d-%02dT%02d:%02d"4240":%2d", t->tm_year + 1900, t->tm_mon + 1,4241t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);4242printf("%-19.19s ", tbuf);4243printf("0x%08x ", lib->l_checksum);4244printf("%-7d %#x", lib->l_version, lib->l_flags);4245if (lib->l_flags != 0) {4246first = 1;4247putchar('(');4248for (k = 0; l_flag[k].name != NULL; k++) {4249if ((l_flag[k].value & lib->l_flags) ==42500)4251continue;4252if (!first)4253putchar(',');4254else4255first = 0;4256printf("%s", l_flag[k].name);4257}4258putchar(')');4259}4260putchar('\n');4261lib++;4262}4263}4264}42654266#undef Elf_Lib42674268static void4269dump_section_groups(struct readelf *re)4270{4271struct section *s;4272const char *symname;4273Elf_Data *d;4274uint32_t *w;4275int i, j, elferr;4276size_t n;42774278for (i = 0; (size_t) i < re->shnum; i++) {4279s = &re->sl[i];4280if (s->type != SHT_GROUP)4281continue;4282if (s->link >= re->shnum)4283continue;4284(void) elf_errno();4285if ((d = elf_getdata(s->scn, NULL)) == NULL) {4286elferr = elf_errno();4287if (elferr != 0)4288warnx("elf_getdata failed: %s",4289elf_errmsg(elferr));4290continue;4291}4292if (d->d_size <= 0)4293continue;42944295w = d->d_buf;42964297/* We only support COMDAT section. */4298#ifndef GRP_COMDAT4299#define GRP_COMDAT 0x14300#endif4301if ((*w++ & GRP_COMDAT) == 0)4302return;43034304if (s->entsize == 0)4305s->entsize = 4;43064307symname = get_symbol_name(re, s->link, s->info);4308n = s->sz / s->entsize;4309if (n-- < 1)4310return;43114312printf("\nCOMDAT group section [%5d] `%s' [%s] contains %ju"4313" sections:\n", i, s->name, symname, (uintmax_t)n);4314printf(" %-10.10s %s\n", "[Index]", "Name");4315for (j = 0; (size_t) j < n; j++, w++) {4316if (*w >= re->shnum) {4317warnx("invalid section index: %u", *w);4318continue;4319}4320printf(" [%5u] %s\n", *w, re->sl[*w].name);4321}4322}4323}43244325static uint8_t *4326dump_unknown_tag(uint64_t tag, uint8_t *p, uint8_t *pe)4327{4328uint64_t val;43294330/*4331* According to ARM EABI: For tags > 32, even numbered tags have4332* a ULEB128 param and odd numbered ones have NUL-terminated4333* string param. This rule probably also applies for tags <= 324334* if the object arch is not ARM.4335*/43364337printf(" Tag_unknown_%ju: ", (uintmax_t) tag);43384339if (tag & 1) {4340printf("%s\n", (char *) p);4341p += strlen((char *) p) + 1;4342} else {4343val = _decode_uleb128(&p, pe);4344printf("%ju\n", (uintmax_t) val);4345}43464347return (p);4348}43494350static uint8_t *4351dump_compatibility_tag(uint8_t *p, uint8_t *pe)4352{4353uint64_t val;43544355val = _decode_uleb128(&p, pe);4356printf("flag = %ju, vendor = %s\n", (uintmax_t) val, p);4357p += strlen((char *) p) + 1;43584359return (p);4360}43614362static void4363dump_arm_attributes(struct readelf *re, uint8_t *p, uint8_t *pe)4364{4365uint64_t tag, val;4366size_t i;4367int found, desc;43684369(void) re;43704371while (p < pe) {4372tag = _decode_uleb128(&p, pe);4373found = desc = 0;4374for (i = 0; i < sizeof(aeabi_tags) / sizeof(aeabi_tags[0]);4375i++) {4376if (tag == aeabi_tags[i].tag) {4377found = 1;4378printf(" %s: ", aeabi_tags[i].s_tag);4379if (aeabi_tags[i].get_desc) {4380desc = 1;4381val = _decode_uleb128(&p, pe);4382printf("%s\n",4383aeabi_tags[i].get_desc(val));4384}4385break;4386}4387if (tag < aeabi_tags[i].tag)4388break;4389}4390if (!found) {4391p = dump_unknown_tag(tag, p, pe);4392continue;4393}4394if (desc)4395continue;43964397switch (tag) {4398case 4: /* Tag_CPU_raw_name */4399case 5: /* Tag_CPU_name */4400case 67: /* Tag_conformance */4401printf("%s\n", (char *) p);4402p += strlen((char *) p) + 1;4403break;4404case 32: /* Tag_compatibility */4405p = dump_compatibility_tag(p, pe);4406break;4407case 64: /* Tag_nodefaults */4408/* ignored, written as 0. */4409(void) _decode_uleb128(&p, pe);4410printf("True\n");4411break;4412case 65: /* Tag_also_compatible_with */4413val = _decode_uleb128(&p, pe);4414/* Must be Tag_CPU_arch */4415if (val != 6) {4416printf("unknown\n");4417break;4418}4419val = _decode_uleb128(&p, pe);4420printf("%s\n", aeabi_cpu_arch(val));4421/* Skip NUL terminator. */4422p++;4423break;4424default:4425putchar('\n');4426break;4427}4428}4429}44304431#ifndef Tag_GNU_MIPS_ABI_FP4432#define Tag_GNU_MIPS_ABI_FP 44433#endif44344435static void4436dump_mips_attributes(struct readelf *re, uint8_t *p, uint8_t *pe)4437{4438uint64_t tag, val;44394440(void) re;44414442while (p < pe) {4443tag = _decode_uleb128(&p, pe);4444switch (tag) {4445case Tag_GNU_MIPS_ABI_FP:4446val = _decode_uleb128(&p, pe);4447printf(" Tag_GNU_MIPS_ABI_FP: %s\n", mips_abi_fp(val));4448break;4449case 32: /* Tag_compatibility */4450p = dump_compatibility_tag(p, pe);4451break;4452default:4453p = dump_unknown_tag(tag, p, pe);4454break;4455}4456}4457}44584459#ifndef Tag_GNU_Power_ABI_FP4460#define Tag_GNU_Power_ABI_FP 44461#endif44624463#ifndef Tag_GNU_Power_ABI_Vector4464#define Tag_GNU_Power_ABI_Vector 84465#endif44664467static void4468dump_ppc_attributes(uint8_t *p, uint8_t *pe)4469{4470uint64_t tag, val;44714472while (p < pe) {4473tag = _decode_uleb128(&p, pe);4474switch (tag) {4475case Tag_GNU_Power_ABI_FP:4476val = _decode_uleb128(&p, pe);4477printf(" Tag_GNU_Power_ABI_FP: %s\n", ppc_abi_fp(val));4478break;4479case Tag_GNU_Power_ABI_Vector:4480val = _decode_uleb128(&p, pe);4481printf(" Tag_GNU_Power_ABI_Vector: %s\n",4482ppc_abi_vector(val));4483break;4484case 32: /* Tag_compatibility */4485p = dump_compatibility_tag(p, pe);4486break;4487default:4488p = dump_unknown_tag(tag, p, pe);4489break;4490}4491}4492}44934494static void4495dump_attributes(struct readelf *re)4496{4497struct section *s;4498Elf_Data *d;4499uint8_t *p, *pe, *sp;4500size_t len, seclen, nlen, sublen;4501uint64_t val;4502int tag, i, elferr;45034504for (i = 0; (size_t) i < re->shnum; i++) {4505s = &re->sl[i];4506if (s->type != SHT_GNU_ATTRIBUTES &&4507(re->ehdr.e_machine != EM_ARM || s->type != SHT_LOPROC + 3))4508continue;4509(void) elf_errno();4510if ((d = elf_rawdata(s->scn, NULL)) == NULL) {4511elferr = elf_errno();4512if (elferr != 0)4513warnx("elf_rawdata failed: %s",4514elf_errmsg(elferr));4515continue;4516}4517if (d->d_size <= 0)4518continue;4519p = d->d_buf;4520pe = p + d->d_size;4521if (*p != 'A') {4522printf("Unknown Attribute Section Format: %c\n",4523(char) *p);4524continue;4525}4526len = d->d_size - 1;4527p++;4528while (len > 0) {4529if (len < 4) {4530warnx("truncated attribute section length");4531return;4532}4533seclen = re->dw_decode(&p, 4);4534if (seclen > len) {4535warnx("invalid attribute section length");4536return;4537}4538len -= seclen;4539nlen = strlen((char *) p) + 1;4540if (nlen + 4 > seclen) {4541warnx("invalid attribute section name");4542return;4543}4544printf("Attribute Section: %s\n", (char *) p);4545p += nlen;4546seclen -= nlen + 4;4547while (seclen > 0) {4548sp = p;4549tag = *p++;4550sublen = re->dw_decode(&p, 4);4551if (sublen > seclen) {4552warnx("invalid attribute sub-section"4553" length");4554return;4555}4556seclen -= sublen;4557printf("%s", top_tag(tag));4558if (tag == 2 || tag == 3) {4559putchar(':');4560for (;;) {4561val = _decode_uleb128(&p, pe);4562if (val == 0)4563break;4564printf(" %ju", (uintmax_t) val);4565}4566}4567putchar('\n');4568if (re->ehdr.e_machine == EM_ARM &&4569s->type == SHT_LOPROC + 3)4570dump_arm_attributes(re, p, sp + sublen);4571else if (re->ehdr.e_machine == EM_MIPS ||4572re->ehdr.e_machine == EM_MIPS_RS3_LE)4573dump_mips_attributes(re, p,4574sp + sublen);4575else if (re->ehdr.e_machine == EM_PPC)4576dump_ppc_attributes(p, sp + sublen);4577p = sp + sublen;4578}4579}4580}4581}45824583static void4584dump_mips_specific_info(struct readelf *re)4585{4586struct section *s;4587int i;45884589s = NULL;4590for (i = 0; (size_t) i < re->shnum; i++) {4591s = &re->sl[i];4592if (s->name != NULL && (!strcmp(s->name, ".MIPS.options") ||4593(s->type == SHT_MIPS_OPTIONS))) {4594dump_mips_options(re, s);4595}4596}45974598if (s->name != NULL && (!strcmp(s->name, ".MIPS.abiflags") ||4599(s->type == SHT_MIPS_ABIFLAGS)))4600dump_mips_abiflags(re, s);46014602/*4603* Dump .reginfo if present (although it will be ignored by an OS if a4604* .MIPS.options section is present, according to SGI mips64 spec).4605*/4606for (i = 0; (size_t) i < re->shnum; i++) {4607s = &re->sl[i];4608if (s->name != NULL && (!strcmp(s->name, ".reginfo") ||4609(s->type == SHT_MIPS_REGINFO)))4610dump_mips_reginfo(re, s);4611}4612}46134614static void4615dump_mips_abiflags(struct readelf *re, struct section *s)4616{4617Elf_Data *d;4618uint8_t *p;4619int elferr;4620uint32_t isa_ext, ases, flags1, flags2;4621uint16_t version;4622uint8_t isa_level, isa_rev, gpr_size, cpr1_size, cpr2_size, fp_abi;46234624if ((d = elf_rawdata(s->scn, NULL)) == NULL) {4625elferr = elf_errno();4626if (elferr != 0)4627warnx("elf_rawdata failed: %s",4628elf_errmsg(elferr));4629return;4630}4631if (d->d_size != 24) {4632warnx("invalid MIPS abiflags section size");4633return;4634}46354636p = d->d_buf;4637version = re->dw_decode(&p, 2);4638printf("MIPS ABI Flags Version: %u", version);4639if (version != 0) {4640printf(" (unknown)\n\n");4641return;4642}4643printf("\n\n");46444645isa_level = re->dw_decode(&p, 1);4646isa_rev = re->dw_decode(&p, 1);4647gpr_size = re->dw_decode(&p, 1);4648cpr1_size = re->dw_decode(&p, 1);4649cpr2_size = re->dw_decode(&p, 1);4650fp_abi = re->dw_decode(&p, 1);4651isa_ext = re->dw_decode(&p, 4);4652ases = re->dw_decode(&p, 4);4653flags1 = re->dw_decode(&p, 4);4654flags2 = re->dw_decode(&p, 4);46554656printf("ISA: ");4657if (isa_rev <= 1)4658printf("MIPS%u\n", isa_level);4659else4660printf("MIPS%ur%u\n", isa_level, isa_rev);4661printf("GPR size: %d\n", get_mips_register_size(gpr_size));4662printf("CPR1 size: %d\n", get_mips_register_size(cpr1_size));4663printf("CPR2 size: %d\n", get_mips_register_size(cpr2_size));4664printf("FP ABI: ");4665switch (fp_abi) {4666case 3:4667printf("Soft float");4668break;4669default:4670printf("%u", fp_abi);4671break;4672}4673printf("\nISA Extension: %u\n", isa_ext);4674printf("ASEs: %u\n", ases);4675printf("FLAGS 1: %08x\n", flags1);4676printf("FLAGS 2: %08x\n", flags2);4677}46784679static int4680get_mips_register_size(uint8_t flag)4681{4682switch (flag) {4683case 0: return 0;4684case 1: return 32;4685case 2: return 64;4686case 3: return 128;4687default: return -1;4688}4689}4690static void4691dump_mips_reginfo(struct readelf *re, struct section *s)4692{4693Elf_Data *d;4694int elferr, len;46954696(void) elf_errno();4697if ((d = elf_rawdata(s->scn, NULL)) == NULL) {4698elferr = elf_errno();4699if (elferr != 0)4700warnx("elf_rawdata failed: %s",4701elf_errmsg(elferr));4702return;4703}4704if (d->d_size <= 0)4705return;4706if (!get_ent_count(s, &len))4707return;47084709printf("\nSection '%s' contains %d entries:\n", s->name, len);4710dump_mips_odk_reginfo(re, d->d_buf, d->d_size);4711}47124713static void4714dump_mips_options(struct readelf *re, struct section *s)4715{4716Elf_Data *d;4717uint32_t info;4718uint16_t sndx;4719uint8_t *p, *pe;4720uint8_t kind, size;4721int elferr;47224723(void) elf_errno();4724if ((d = elf_rawdata(s->scn, NULL)) == NULL) {4725elferr = elf_errno();4726if (elferr != 0)4727warnx("elf_rawdata failed: %s",4728elf_errmsg(elferr));4729return;4730}4731if (d->d_size == 0)4732return;47334734printf("\nSection %s contains:\n", s->name);4735p = d->d_buf;4736pe = p + d->d_size;4737while (p < pe) {4738if (pe - p < 8) {4739warnx("Truncated MIPS option header");4740return;4741}4742kind = re->dw_decode(&p, 1);4743size = re->dw_decode(&p, 1);4744sndx = re->dw_decode(&p, 2);4745info = re->dw_decode(&p, 4);4746if (size < 8 || size - 8 > pe - p) {4747warnx("Malformed MIPS option header");4748return;4749}4750size -= 8;4751switch (kind) {4752case ODK_REGINFO:4753dump_mips_odk_reginfo(re, p, size);4754break;4755case ODK_EXCEPTIONS:4756printf(" EXCEPTIONS FPU_MIN: %#x\n",4757info & OEX_FPU_MIN);4758printf("%11.11s FPU_MAX: %#x\n", "",4759info & OEX_FPU_MAX);4760dump_mips_option_flags("", mips_exceptions_option,4761info);4762break;4763case ODK_PAD:4764printf(" %-10.10s section: %ju\n", "OPAD",4765(uintmax_t) sndx);4766dump_mips_option_flags("", mips_pad_option, info);4767break;4768case ODK_HWPATCH:4769dump_mips_option_flags("HWPATCH", mips_hwpatch_option,4770info);4771break;4772case ODK_HWAND:4773dump_mips_option_flags("HWAND", mips_hwa_option, info);4774break;4775case ODK_HWOR:4776dump_mips_option_flags("HWOR", mips_hwo_option, info);4777break;4778case ODK_FILL:4779printf(" %-10.10s %#jx\n", "FILL", (uintmax_t) info);4780break;4781case ODK_TAGS:4782printf(" %-10.10s\n", "TAGS");4783break;4784case ODK_GP_GROUP:4785printf(" %-10.10s GP group number: %#x\n", "GP_GROUP",4786info & 0xFFFF);4787if (info & 0x10000)4788printf(" %-10.10s GP group is "4789"self-contained\n", "");4790break;4791case ODK_IDENT:4792printf(" %-10.10s default GP group number: %#x\n",4793"IDENT", info & 0xFFFF);4794if (info & 0x10000)4795printf(" %-10.10s default GP group is "4796"self-contained\n", "");4797break;4798case ODK_PAGESIZE:4799printf(" %-10.10s\n", "PAGESIZE");4800break;4801default:4802break;4803}4804p += size;4805}4806}48074808static void4809dump_mips_option_flags(const char *name, struct mips_option *opt, uint64_t info)4810{4811int first;48124813first = 1;4814for (; opt->desc != NULL; opt++) {4815if (info & opt->flag) {4816printf(" %-10.10s %s\n", first ? name : "",4817opt->desc);4818first = 0;4819}4820}4821}48224823static void4824dump_mips_odk_reginfo(struct readelf *re, uint8_t *p, size_t sz)4825{4826uint32_t ri_gprmask;4827uint32_t ri_cprmask[4];4828uint64_t ri_gp_value;4829uint8_t *pe;4830int i;48314832pe = p + sz;4833while (p < pe) {4834ri_gprmask = re->dw_decode(&p, 4);4835/* Skip ri_pad padding field for mips64. */4836if (re->ec == ELFCLASS64)4837re->dw_decode(&p, 4);4838for (i = 0; i < 4; i++)4839ri_cprmask[i] = re->dw_decode(&p, 4);4840if (re->ec == ELFCLASS32)4841ri_gp_value = re->dw_decode(&p, 4);4842else4843ri_gp_value = re->dw_decode(&p, 8);4844printf(" %s ", option_kind(ODK_REGINFO));4845printf("ri_gprmask: 0x%08jx\n", (uintmax_t) ri_gprmask);4846for (i = 0; i < 4; i++)4847printf("%11.11s ri_cprmask[%d]: 0x%08jx\n", "", i,4848(uintmax_t) ri_cprmask[i]);4849printf("%12.12s", "");4850printf("ri_gp_value: %#jx\n", (uintmax_t) ri_gp_value);4851}4852}48534854static void4855dump_arch_specific_info(struct readelf *re)4856{48574858dump_liblist(re);4859dump_attributes(re);48604861switch (re->ehdr.e_machine) {4862case EM_MIPS:4863case EM_MIPS_RS3_LE:4864dump_mips_specific_info(re);4865default:4866break;4867}4868}48694870static const char *4871dwarf_regname(struct readelf *re, unsigned int num)4872{4873static char rx[32];4874const char *rn;48754876if ((rn = dwarf_reg(re->ehdr.e_machine, num)) != NULL)4877return (rn);48784879snprintf(rx, sizeof(rx), "r%u", num);48804881return (rx);4882}48834884static void4885dump_dwarf_line(struct readelf *re)4886{4887struct section *s;4888Dwarf_Die die;4889Dwarf_Error de;4890Dwarf_Half tag, version, pointer_size;4891Dwarf_Unsigned offset, endoff, length, hdrlen, dirndx, mtime, fsize;4892Dwarf_Small minlen, defstmt, lrange, opbase, oplen;4893Elf_Data *d;4894char *pn;4895uint64_t address, file, line, column, isa, opsize, udelta;4896int64_t sdelta;4897uint8_t *p, *pe;4898int8_t lbase;4899int i, is_stmt, dwarf_size, elferr, ret;49004901printf("\nDump of debug contents of section .debug_line:\n");49024903s = NULL;4904for (i = 0; (size_t) i < re->shnum; i++) {4905s = &re->sl[i];4906if (s->name != NULL && !strcmp(s->name, ".debug_line"))4907break;4908}4909if ((size_t) i >= re->shnum)4910return;49114912(void) elf_errno();4913if ((d = elf_getdata(s->scn, NULL)) == NULL) {4914elferr = elf_errno();4915if (elferr != 0)4916warnx("elf_getdata failed: %s", elf_errmsg(-1));4917return;4918}4919if (d->d_size <= 0)4920return;49214922while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,4923NULL, &de)) == DW_DLV_OK) {4924die = NULL;4925while (dwarf_siblingof(re->dbg, die, &die, &de) == DW_DLV_OK) {4926if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {4927warnx("dwarf_tag failed: %s",4928dwarf_errmsg(de));4929return;4930}4931/* XXX: What about DW_TAG_partial_unit? */4932if (tag == DW_TAG_compile_unit)4933break;4934}4935if (die == NULL) {4936warnx("could not find DW_TAG_compile_unit die");4937return;4938}4939if (dwarf_attrval_unsigned(die, DW_AT_stmt_list, &offset,4940&de) != DW_DLV_OK) {4941dwarf_dealloc(re->dbg, die, DW_DLA_DIE);4942continue;4943}49444945length = re->dw_read(d, &offset, 4);4946if (length == 0xffffffff) {4947dwarf_size = 8;4948length = re->dw_read(d, &offset, 8);4949} else4950dwarf_size = 4;49514952if (length > d->d_size - offset) {4953warnx("invalid .dwarf_line section");4954dwarf_dealloc(re->dbg, die, DW_DLA_DIE);4955continue;4956}49574958endoff = offset + length;4959pe = (uint8_t *) d->d_buf + endoff;4960version = re->dw_read(d, &offset, 2);4961hdrlen = re->dw_read(d, &offset, dwarf_size);4962minlen = re->dw_read(d, &offset, 1);4963defstmt = re->dw_read(d, &offset, 1);4964lbase = re->dw_read(d, &offset, 1);4965lrange = re->dw_read(d, &offset, 1);4966opbase = re->dw_read(d, &offset, 1);49674968printf("\n");4969printf(" Length:\t\t\t%ju\n", (uintmax_t) length);4970printf(" DWARF version:\t\t%u\n", version);4971printf(" Prologue Length:\t\t%ju\n", (uintmax_t) hdrlen);4972printf(" Minimum Instruction Length:\t%u\n", minlen);4973printf(" Initial value of 'is_stmt':\t%u\n", defstmt);4974printf(" Line Base:\t\t\t%d\n", lbase);4975printf(" Line Range:\t\t\t%u\n", lrange);4976printf(" Opcode Base:\t\t\t%u\n", opbase);4977(void) dwarf_get_address_size(re->dbg, &pointer_size, &de);4978printf(" (Pointer size:\t\t%u)\n", pointer_size);49794980printf("\n");4981printf(" Opcodes:\n");4982for (i = 1; i < opbase; i++) {4983oplen = re->dw_read(d, &offset, 1);4984printf(" Opcode %d has %u args\n", i, oplen);4985}49864987printf("\n");4988printf(" The Directory Table:\n");4989p = (uint8_t *) d->d_buf + offset;4990while (*p != '\0') {4991printf(" %s\n", (char *) p);4992p += strlen((char *) p) + 1;4993}49944995p++;4996printf("\n");4997printf(" The File Name Table:\n");4998printf(" Entry\tDir\tTime\tSize\tName\n");4999i = 0;5000while (*p != '\0') {5001i++;5002pn = (char *) p;5003p += strlen(pn) + 1;5004dirndx = _decode_uleb128(&p, pe);5005mtime = _decode_uleb128(&p, pe);5006fsize = _decode_uleb128(&p, pe);5007printf(" %d\t%ju\t%ju\t%ju\t%s\n", i,5008(uintmax_t) dirndx, (uintmax_t) mtime,5009(uintmax_t) fsize, pn);5010}50115012#define RESET_REGISTERS \5013do { \5014address = 0; \5015file = 1; \5016line = 1; \5017column = 0; \5018is_stmt = defstmt; \5019} while(0)50205021#define LINE(x) (lbase + (((x) - opbase) % lrange))5022#define ADDRESS(x) ((((x) - opbase) / lrange) * minlen)50235024p++;5025printf("\n");5026printf(" Line Number Statements:\n");50275028RESET_REGISTERS;50295030while (p < pe) {50315032if (*p == 0) {5033/*5034* Extended Opcodes.5035*/5036p++;5037opsize = _decode_uleb128(&p, pe);5038printf(" Extended opcode %u: ", *p);5039switch (*p) {5040case DW_LNE_end_sequence:5041p++;5042RESET_REGISTERS;5043printf("End of Sequence\n");5044break;5045case DW_LNE_set_address:5046p++;5047address = re->dw_decode(&p,5048pointer_size);5049printf("set Address to %#jx\n",5050(uintmax_t) address);5051break;5052case DW_LNE_define_file:5053p++;5054pn = (char *) p;5055p += strlen(pn) + 1;5056dirndx = _decode_uleb128(&p, pe);5057mtime = _decode_uleb128(&p, pe);5058fsize = _decode_uleb128(&p, pe);5059printf("define new file: %s\n", pn);5060break;5061default:5062/* Unrecognized extened opcodes. */5063p += opsize;5064printf("unknown opcode\n");5065}5066} else if (*p > 0 && *p < opbase) {5067/*5068* Standard Opcodes.5069*/5070switch(*p++) {5071case DW_LNS_copy:5072printf(" Copy\n");5073break;5074case DW_LNS_advance_pc:5075udelta = _decode_uleb128(&p, pe) *5076minlen;5077address += udelta;5078printf(" Advance PC by %ju to %#jx\n",5079(uintmax_t) udelta,5080(uintmax_t) address);5081break;5082case DW_LNS_advance_line:5083sdelta = _decode_sleb128(&p, pe);5084line += sdelta;5085printf(" Advance Line by %jd to %ju\n",5086(intmax_t) sdelta,5087(uintmax_t) line);5088break;5089case DW_LNS_set_file:5090file = _decode_uleb128(&p, pe);5091printf(" Set File to %ju\n",5092(uintmax_t) file);5093break;5094case DW_LNS_set_column:5095column = _decode_uleb128(&p, pe);5096printf(" Set Column to %ju\n",5097(uintmax_t) column);5098break;5099case DW_LNS_negate_stmt:5100is_stmt = !is_stmt;5101printf(" Set is_stmt to %d\n", is_stmt);5102break;5103case DW_LNS_set_basic_block:5104printf(" Set basic block flag\n");5105break;5106case DW_LNS_const_add_pc:5107address += ADDRESS(255);5108printf(" Advance PC by constant %ju"5109" to %#jx\n",5110(uintmax_t) ADDRESS(255),5111(uintmax_t) address);5112break;5113case DW_LNS_fixed_advance_pc:5114udelta = re->dw_decode(&p, 2);5115address += udelta;5116printf(" Advance PC by fixed value "5117"%ju to %#jx\n",5118(uintmax_t) udelta,5119(uintmax_t) address);5120break;5121case DW_LNS_set_prologue_end:5122printf(" Set prologue end flag\n");5123break;5124case DW_LNS_set_epilogue_begin:5125printf(" Set epilogue begin flag\n");5126break;5127case DW_LNS_set_isa:5128isa = _decode_uleb128(&p, pe);5129printf(" Set isa to %ju\n",5130(uintmax_t) isa);5131break;5132default:5133/* Unrecognized extended opcodes. */5134printf(" Unknown extended opcode %u\n",5135*(p - 1));5136break;5137}51385139} else {5140/*5141* Special Opcodes.5142*/5143line += LINE(*p);5144address += ADDRESS(*p);5145printf(" Special opcode %u: advance Address "5146"by %ju to %#jx and Line by %jd to %ju\n",5147*p - opbase, (uintmax_t) ADDRESS(*p),5148(uintmax_t) address, (intmax_t) LINE(*p),5149(uintmax_t) line);5150p++;5151}5152}5153dwarf_dealloc(re->dbg, die, DW_DLA_DIE);5154}5155if (ret == DW_DLV_ERROR)5156warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));51575158#undef RESET_REGISTERS5159#undef LINE5160#undef ADDRESS5161}51625163static void5164dump_dwarf_line_decoded(struct readelf *re)5165{5166Dwarf_Die die;5167Dwarf_Line *linebuf, ln;5168Dwarf_Addr lineaddr;5169Dwarf_Signed linecount, srccount;5170Dwarf_Unsigned lineno, fn;5171Dwarf_Error de;5172const char *dir, *file;5173char **srcfiles;5174int i, ret;51755176printf("Decoded dump of debug contents of section .debug_line:\n\n");5177while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,5178NULL, &de)) == DW_DLV_OK) {5179if (dwarf_siblingof(re->dbg, NULL, &die, &de) != DW_DLV_OK)5180continue;5181if (dwarf_attrval_string(die, DW_AT_name, &file, &de) !=5182DW_DLV_OK)5183file = NULL;5184if (dwarf_attrval_string(die, DW_AT_comp_dir, &dir, &de) !=5185DW_DLV_OK)5186dir = NULL;5187printf("CU: ");5188if (dir && file && file[0] != '/')5189printf("%s/", dir);5190if (file)5191printf("%s", file);5192putchar('\n');5193printf("%-37s %11s %s\n", "Filename", "Line Number",5194"Starting Address");5195if (dwarf_srclines(die, &linebuf, &linecount, &de) != DW_DLV_OK)5196goto done;5197if (dwarf_srcfiles(die, &srcfiles, &srccount, &de) != DW_DLV_OK)5198goto done;5199for (i = 0; i < linecount; i++) {5200ln = linebuf[i];5201if (dwarf_line_srcfileno(ln, &fn, &de) != DW_DLV_OK)5202continue;5203if (dwarf_lineno(ln, &lineno, &de) != DW_DLV_OK)5204continue;5205if (dwarf_lineaddr(ln, &lineaddr, &de) != DW_DLV_OK)5206continue;5207printf("%-37s %11ju %#18jx\n",5208basename(srcfiles[fn - 1]), (uintmax_t) lineno,5209(uintmax_t) lineaddr);5210}5211putchar('\n');5212done:5213dwarf_dealloc(re->dbg, die, DW_DLA_DIE);5214}5215}52165217static void5218dump_dwarf_die(struct readelf *re, Dwarf_Die die, int level)5219{5220Dwarf_Attribute *attr_list;5221Dwarf_Die ret_die;5222Dwarf_Off dieoff, cuoff, culen, attroff;5223Dwarf_Unsigned ate, lang, v_udata, v_sig;5224Dwarf_Signed attr_count, v_sdata;5225Dwarf_Off v_off;5226Dwarf_Addr v_addr;5227Dwarf_Half tag, attr, form;5228Dwarf_Block *v_block;5229Dwarf_Bool v_bool, is_info;5230Dwarf_Sig8 v_sig8;5231Dwarf_Error de;5232Dwarf_Ptr v_expr;5233const char *tag_str, *attr_str, *ate_str, *lang_str;5234char unk_tag[32], unk_attr[32];5235char *v_str;5236uint8_t *b, *p;5237int i, j, abc, ret;52385239if (dwarf_dieoffset(die, &dieoff, &de) != DW_DLV_OK) {5240warnx("dwarf_dieoffset failed: %s", dwarf_errmsg(de));5241goto cont_search;5242}52435244printf(" <%d><%jx>: ", level, (uintmax_t) dieoff);52455246if (dwarf_die_CU_offset_range(die, &cuoff, &culen, &de) != DW_DLV_OK) {5247warnx("dwarf_die_CU_offset_range failed: %s",5248dwarf_errmsg(de));5249cuoff = 0;5250}52515252abc = dwarf_die_abbrev_code(die);5253if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {5254warnx("dwarf_tag failed: %s", dwarf_errmsg(de));5255goto cont_search;5256}5257if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) {5258snprintf(unk_tag, sizeof(unk_tag), "[Unknown Tag: %#x]", tag);5259tag_str = unk_tag;5260}52615262printf("Abbrev Number: %d (%s)\n", abc, tag_str);52635264if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=5265DW_DLV_OK) {5266if (ret == DW_DLV_ERROR)5267warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));5268goto cont_search;5269}52705271for (i = 0; i < attr_count; i++) {5272if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) {5273warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));5274continue;5275}5276if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {5277warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));5278continue;5279}5280if (dwarf_get_AT_name(attr, &attr_str) != DW_DLV_OK) {5281snprintf(unk_attr, sizeof(unk_attr),5282"[Unknown AT: %#x]", attr);5283attr_str = unk_attr;5284}5285if (dwarf_attroffset(attr_list[i], &attroff, &de) !=5286DW_DLV_OK) {5287warnx("dwarf_attroffset failed: %s", dwarf_errmsg(de));5288attroff = 0;5289}5290printf(" <%jx> %-18s: ", (uintmax_t) attroff, attr_str);5291switch (form) {5292case DW_FORM_ref_addr:5293case DW_FORM_sec_offset:5294if (dwarf_global_formref(attr_list[i], &v_off, &de) !=5295DW_DLV_OK) {5296warnx("dwarf_global_formref failed: %s",5297dwarf_errmsg(de));5298continue;5299}5300if (form == DW_FORM_ref_addr)5301printf("<0x%jx>", (uintmax_t) v_off);5302else5303printf("0x%jx", (uintmax_t) v_off);5304break;53055306case DW_FORM_ref1:5307case DW_FORM_ref2:5308case DW_FORM_ref4:5309case DW_FORM_ref8:5310case DW_FORM_ref_udata:5311if (dwarf_formref(attr_list[i], &v_off, &de) !=5312DW_DLV_OK) {5313warnx("dwarf_formref failed: %s",5314dwarf_errmsg(de));5315continue;5316}5317v_off += cuoff;5318printf("<0x%jx>", (uintmax_t) v_off);5319break;53205321case DW_FORM_addr:5322if (dwarf_formaddr(attr_list[i], &v_addr, &de) !=5323DW_DLV_OK) {5324warnx("dwarf_formaddr failed: %s",5325dwarf_errmsg(de));5326continue;5327}5328printf("%#jx", (uintmax_t) v_addr);5329break;53305331case DW_FORM_data1:5332case DW_FORM_data2:5333case DW_FORM_data4:5334case DW_FORM_data8:5335case DW_FORM_udata:5336if (dwarf_formudata(attr_list[i], &v_udata, &de) !=5337DW_DLV_OK) {5338warnx("dwarf_formudata failed: %s",5339dwarf_errmsg(de));5340continue;5341}5342if (attr == DW_AT_high_pc)5343printf("0x%jx", (uintmax_t) v_udata);5344else5345printf("%ju", (uintmax_t) v_udata);5346break;53475348case DW_FORM_sdata:5349if (dwarf_formsdata(attr_list[i], &v_sdata, &de) !=5350DW_DLV_OK) {5351warnx("dwarf_formudata failed: %s",5352dwarf_errmsg(de));5353continue;5354}5355printf("%jd", (intmax_t) v_sdata);5356break;53575358case DW_FORM_flag:5359if (dwarf_formflag(attr_list[i], &v_bool, &de) !=5360DW_DLV_OK) {5361warnx("dwarf_formflag failed: %s",5362dwarf_errmsg(de));5363continue;5364}5365printf("%jd", (intmax_t) v_bool);5366break;53675368case DW_FORM_flag_present:5369putchar('1');5370break;53715372case DW_FORM_string:5373case DW_FORM_strp:5374if (dwarf_formstring(attr_list[i], &v_str, &de) !=5375DW_DLV_OK) {5376warnx("dwarf_formstring failed: %s",5377dwarf_errmsg(de));5378continue;5379}5380if (form == DW_FORM_string)5381printf("%s", v_str);5382else5383printf("(indirect string) %s", v_str);5384break;53855386case DW_FORM_block:5387case DW_FORM_block1:5388case DW_FORM_block2:5389case DW_FORM_block4:5390if (dwarf_formblock(attr_list[i], &v_block, &de) !=5391DW_DLV_OK) {5392warnx("dwarf_formblock failed: %s",5393dwarf_errmsg(de));5394continue;5395}5396printf("%ju byte block:", (uintmax_t) v_block->bl_len);5397b = v_block->bl_data;5398for (j = 0; (Dwarf_Unsigned) j < v_block->bl_len; j++)5399printf(" %x", b[j]);5400printf("\t(");5401dump_dwarf_block(re, v_block->bl_data, v_block->bl_len);5402putchar(')');5403break;54045405case DW_FORM_exprloc:5406if (dwarf_formexprloc(attr_list[i], &v_udata, &v_expr,5407&de) != DW_DLV_OK) {5408warnx("dwarf_formexprloc failed: %s",5409dwarf_errmsg(de));5410continue;5411}5412printf("%ju byte block:", (uintmax_t) v_udata);5413b = v_expr;5414for (j = 0; (Dwarf_Unsigned) j < v_udata; j++)5415printf(" %x", b[j]);5416printf("\t(");5417dump_dwarf_block(re, v_expr, v_udata);5418putchar(')');5419break;54205421case DW_FORM_ref_sig8:5422if (dwarf_formsig8(attr_list[i], &v_sig8, &de) !=5423DW_DLV_OK) {5424warnx("dwarf_formsig8 failed: %s",5425dwarf_errmsg(de));5426continue;5427}5428p = (uint8_t *)(uintptr_t) &v_sig8.signature[0];5429v_sig = re->dw_decode(&p, 8);5430printf("signature: 0x%jx", (uintmax_t) v_sig);5431}5432switch (attr) {5433case DW_AT_encoding:5434if (dwarf_attrval_unsigned(die, attr, &ate, &de) !=5435DW_DLV_OK)5436break;5437if (dwarf_get_ATE_name(ate, &ate_str) != DW_DLV_OK)5438ate_str = "DW_ATE_UNKNOWN";5439printf("\t(%s)", &ate_str[strlen("DW_ATE_")]);5440break;54415442case DW_AT_language:5443if (dwarf_attrval_unsigned(die, attr, &lang, &de) !=5444DW_DLV_OK)5445break;5446if (dwarf_get_LANG_name(lang, &lang_str) != DW_DLV_OK)5447break;5448printf("\t(%s)", &lang_str[strlen("DW_LANG_")]);5449break;54505451case DW_AT_location:5452case DW_AT_string_length:5453case DW_AT_return_addr:5454case DW_AT_data_member_location:5455case DW_AT_frame_base:5456case DW_AT_segment:5457case DW_AT_static_link:5458case DW_AT_use_location:5459case DW_AT_vtable_elem_location:5460switch (form) {5461case DW_FORM_data4:5462case DW_FORM_data8:5463case DW_FORM_sec_offset:5464printf("\t(location list)");5465break;5466default:5467break;5468}54695470default:5471break;5472}5473putchar('\n');5474}547554765477cont_search:5478/* Search children. */5479ret = dwarf_child(die, &ret_die, &de);5480if (ret == DW_DLV_ERROR)5481warnx("dwarf_child: %s", dwarf_errmsg(de));5482else if (ret == DW_DLV_OK)5483dump_dwarf_die(re, ret_die, level + 1);54845485/* Search sibling. */5486is_info = dwarf_get_die_infotypes_flag(die);5487ret = dwarf_siblingof_b(re->dbg, die, &ret_die, is_info, &de);5488if (ret == DW_DLV_ERROR)5489warnx("dwarf_siblingof: %s", dwarf_errmsg(de));5490else if (ret == DW_DLV_OK)5491dump_dwarf_die(re, ret_die, level);54925493dwarf_dealloc(re->dbg, die, DW_DLA_DIE);5494}54955496static void5497set_cu_context(struct readelf *re, Dwarf_Half psize, Dwarf_Half osize,5498Dwarf_Half ver)5499{55005501re->cu_psize = psize;5502re->cu_osize = osize;5503re->cu_ver = ver;5504}55055506static void5507dump_dwarf_info(struct readelf *re, Dwarf_Bool is_info)5508{5509struct section *s;5510Dwarf_Die die;5511Dwarf_Error de;5512Dwarf_Half tag, version, pointer_size, off_size;5513Dwarf_Off cu_offset, cu_length;5514Dwarf_Off aboff;5515Dwarf_Unsigned typeoff;5516Dwarf_Sig8 sig8;5517Dwarf_Unsigned sig;5518uint8_t *p;5519const char *sn;5520int i, ret;55215522sn = is_info ? ".debug_info" : ".debug_types";55235524s = NULL;5525for (i = 0; (size_t) i < re->shnum; i++) {5526s = &re->sl[i];5527if (s->name != NULL && !strcmp(s->name, sn))5528break;5529}5530if ((size_t) i >= re->shnum)5531return;55325533do {5534printf("\nDump of debug contents of section %s:\n", sn);55355536while ((ret = dwarf_next_cu_header_c(re->dbg, is_info, NULL,5537&version, &aboff, &pointer_size, &off_size, NULL, &sig8,5538&typeoff, NULL, &de)) == DW_DLV_OK) {5539set_cu_context(re, pointer_size, off_size, version);5540die = NULL;5541while (dwarf_siblingof_b(re->dbg, die, &die, is_info,5542&de) == DW_DLV_OK) {5543if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {5544warnx("dwarf_tag failed: %s",5545dwarf_errmsg(de));5546continue;5547}5548/* XXX: What about DW_TAG_partial_unit? */5549if ((is_info && tag == DW_TAG_compile_unit) ||5550(!is_info && tag == DW_TAG_type_unit))5551break;5552}5553if (die == NULL && is_info) {5554warnx("could not find DW_TAG_compile_unit "5555"die");5556continue;5557} else if (die == NULL && !is_info) {5558warnx("could not find DW_TAG_type_unit die");5559continue;5560}55615562if (dwarf_die_CU_offset_range(die, &cu_offset,5563&cu_length, &de) != DW_DLV_OK) {5564warnx("dwarf_die_CU_offset failed: %s",5565dwarf_errmsg(de));5566continue;5567}55685569cu_length -= off_size == 4 ? 4 : 12;55705571sig = 0;5572if (!is_info) {5573p = (uint8_t *)(uintptr_t) &sig8.signature[0];5574sig = re->dw_decode(&p, 8);5575}55765577printf("\n Type Unit @ offset 0x%jx:\n",5578(uintmax_t) cu_offset);5579printf(" Length:\t\t%#jx (%d-bit)\n",5580(uintmax_t) cu_length, off_size == 4 ? 32 : 64);5581printf(" Version:\t\t%u\n", version);5582printf(" Abbrev Offset:\t0x%jx\n",5583(uintmax_t) aboff);5584printf(" Pointer Size:\t%u\n", pointer_size);5585if (!is_info) {5586printf(" Signature:\t\t0x%016jx\n",5587(uintmax_t) sig);5588printf(" Type Offset:\t0x%jx\n",5589(uintmax_t) typeoff);5590}55915592dump_dwarf_die(re, die, 0);5593}5594if (ret == DW_DLV_ERROR)5595warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));5596if (is_info)5597break;5598} while (dwarf_next_types_section(re->dbg, &de) == DW_DLV_OK);5599}56005601static void5602dump_dwarf_abbrev(struct readelf *re)5603{5604Dwarf_Abbrev ab;5605Dwarf_Off aboff, atoff;5606Dwarf_Unsigned length, attr_count;5607Dwarf_Signed flag, form;5608Dwarf_Half tag, attr;5609Dwarf_Error de;5610const char *tag_str, *attr_str, *form_str;5611char unk_tag[32], unk_attr[32], unk_form[32];5612int i, j, ret;56135614printf("\nContents of section .debug_abbrev:\n\n");56155616while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, &aboff,5617NULL, NULL, &de)) == DW_DLV_OK) {5618printf(" Number TAG\n");5619i = 0;5620while ((ret = dwarf_get_abbrev(re->dbg, aboff, &ab, &length,5621&attr_count, &de)) == DW_DLV_OK) {5622if (length == 1) {5623dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV);5624break;5625}5626aboff += length;5627printf("%4d", ++i);5628if (dwarf_get_abbrev_tag(ab, &tag, &de) != DW_DLV_OK) {5629warnx("dwarf_get_abbrev_tag failed: %s",5630dwarf_errmsg(de));5631goto next_abbrev;5632}5633if (dwarf_get_TAG_name(tag, &tag_str) != DW_DLV_OK) {5634snprintf(unk_tag, sizeof(unk_tag),5635"[Unknown Tag: %#x]", tag);5636tag_str = unk_tag;5637}5638if (dwarf_get_abbrev_children_flag(ab, &flag, &de) !=5639DW_DLV_OK) {5640warnx("dwarf_get_abbrev_children_flag failed:"5641" %s", dwarf_errmsg(de));5642goto next_abbrev;5643}5644printf(" %s %s\n", tag_str,5645flag ? "[has children]" : "[no children]");5646for (j = 0; (Dwarf_Unsigned) j < attr_count; j++) {5647if (dwarf_get_abbrev_entry(ab, (Dwarf_Signed) j,5648&attr, &form, &atoff, &de) != DW_DLV_OK) {5649warnx("dwarf_get_abbrev_entry failed:"5650" %s", dwarf_errmsg(de));5651continue;5652}5653if (dwarf_get_AT_name(attr, &attr_str) !=5654DW_DLV_OK) {5655snprintf(unk_attr, sizeof(unk_attr),5656"[Unknown AT: %#x]", attr);5657attr_str = unk_attr;5658}5659if (dwarf_get_FORM_name(form, &form_str) !=5660DW_DLV_OK) {5661snprintf(unk_form, sizeof(unk_form),5662"[Unknown Form: %#x]",5663(Dwarf_Half) form);5664form_str = unk_form;5665}5666printf(" %-18s %s\n", attr_str, form_str);5667}5668next_abbrev:5669dwarf_dealloc(re->dbg, ab, DW_DLA_ABBREV);5670}5671if (ret != DW_DLV_OK)5672warnx("dwarf_get_abbrev: %s", dwarf_errmsg(de));5673}5674if (ret == DW_DLV_ERROR)5675warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));5676}56775678static void5679dump_dwarf_pubnames(struct readelf *re)5680{5681struct section *s;5682Dwarf_Off die_off;5683Dwarf_Unsigned offset, length, nt_cu_offset, nt_cu_length;5684Dwarf_Signed cnt;5685Dwarf_Global *globs;5686Dwarf_Half nt_version;5687Dwarf_Error de;5688Elf_Data *d;5689char *glob_name;5690int i, dwarf_size, elferr;56915692printf("\nContents of the .debug_pubnames section:\n");56935694s = NULL;5695for (i = 0; (size_t) i < re->shnum; i++) {5696s = &re->sl[i];5697if (s->name != NULL && !strcmp(s->name, ".debug_pubnames"))5698break;5699}5700if ((size_t) i >= re->shnum)5701return;57025703(void) elf_errno();5704if ((d = elf_getdata(s->scn, NULL)) == NULL) {5705elferr = elf_errno();5706if (elferr != 0)5707warnx("elf_getdata failed: %s", elf_errmsg(-1));5708return;5709}5710if (d->d_size <= 0)5711return;57125713/* Read in .debug_pubnames section table header. */5714offset = 0;5715length = re->dw_read(d, &offset, 4);5716if (length == 0xffffffff) {5717dwarf_size = 8;5718length = re->dw_read(d, &offset, 8);5719} else5720dwarf_size = 4;57215722if (length > d->d_size - offset) {5723warnx("invalid .dwarf_pubnames section");5724return;5725}57265727nt_version = re->dw_read(d, &offset, 2);5728nt_cu_offset = re->dw_read(d, &offset, dwarf_size);5729nt_cu_length = re->dw_read(d, &offset, dwarf_size);5730printf(" Length:\t\t\t\t%ju\n", (uintmax_t) length);5731printf(" Version:\t\t\t\t%u\n", nt_version);5732printf(" Offset into .debug_info section:\t%ju\n",5733(uintmax_t) nt_cu_offset);5734printf(" Size of area in .debug_info section:\t%ju\n",5735(uintmax_t) nt_cu_length);57365737if (dwarf_get_globals(re->dbg, &globs, &cnt, &de) != DW_DLV_OK) {5738warnx("dwarf_get_globals failed: %s", dwarf_errmsg(de));5739return;5740}57415742printf("\n Offset Name\n");5743for (i = 0; i < cnt; i++) {5744if (dwarf_globname(globs[i], &glob_name, &de) != DW_DLV_OK) {5745warnx("dwarf_globname failed: %s", dwarf_errmsg(de));5746continue;5747}5748if (dwarf_global_die_offset(globs[i], &die_off, &de) !=5749DW_DLV_OK) {5750warnx("dwarf_global_die_offset failed: %s",5751dwarf_errmsg(de));5752continue;5753}5754printf(" %-11ju %s\n", (uintmax_t) die_off, glob_name);5755}5756}57575758static void5759dump_dwarf_aranges(struct readelf *re)5760{5761struct section *s;5762Dwarf_Arange *aranges;5763Dwarf_Addr start;5764Dwarf_Unsigned offset, length, as_cu_offset;5765Dwarf_Off die_off;5766Dwarf_Signed cnt;5767Dwarf_Half as_version, as_addrsz, as_segsz;5768Dwarf_Error de;5769Elf_Data *d;5770int i, dwarf_size, elferr;57715772printf("\nContents of section .debug_aranges:\n");57735774s = NULL;5775for (i = 0; (size_t) i < re->shnum; i++) {5776s = &re->sl[i];5777if (s->name != NULL && !strcmp(s->name, ".debug_aranges"))5778break;5779}5780if ((size_t) i >= re->shnum)5781return;57825783(void) elf_errno();5784if ((d = elf_getdata(s->scn, NULL)) == NULL) {5785elferr = elf_errno();5786if (elferr != 0)5787warnx("elf_getdata failed: %s", elf_errmsg(-1));5788return;5789}5790if (d->d_size <= 0)5791return;57925793/* Read in the .debug_aranges section table header. */5794offset = 0;5795length = re->dw_read(d, &offset, 4);5796if (length == 0xffffffff) {5797dwarf_size = 8;5798length = re->dw_read(d, &offset, 8);5799} else5800dwarf_size = 4;58015802if (length > d->d_size - offset) {5803warnx("invalid .dwarf_aranges section");5804return;5805}58065807as_version = re->dw_read(d, &offset, 2);5808as_cu_offset = re->dw_read(d, &offset, dwarf_size);5809as_addrsz = re->dw_read(d, &offset, 1);5810as_segsz = re->dw_read(d, &offset, 1);58115812printf(" Length:\t\t\t%ju\n", (uintmax_t) length);5813printf(" Version:\t\t\t%u\n", as_version);5814printf(" Offset into .debug_info:\t%ju\n", (uintmax_t) as_cu_offset);5815printf(" Pointer Size:\t\t\t%u\n", as_addrsz);5816printf(" Segment Size:\t\t\t%u\n", as_segsz);58175818if (dwarf_get_aranges(re->dbg, &aranges, &cnt, &de) != DW_DLV_OK) {5819warnx("dwarf_get_aranges failed: %s", dwarf_errmsg(de));5820return;5821}58225823printf("\n Address Length\n");5824for (i = 0; i < cnt; i++) {5825if (dwarf_get_arange_info(aranges[i], &start, &length,5826&die_off, &de) != DW_DLV_OK) {5827warnx("dwarf_get_arange_info failed: %s",5828dwarf_errmsg(de));5829continue;5830}5831printf(" %08jx %ju\n", (uintmax_t) start,5832(uintmax_t) length);5833}5834}58355836static void5837dump_dwarf_ranges_foreach(struct readelf *re, Dwarf_Die die, Dwarf_Addr base)5838{5839Dwarf_Attribute *attr_list;5840Dwarf_Ranges *ranges;5841Dwarf_Die ret_die;5842Dwarf_Error de;5843Dwarf_Addr base0;5844Dwarf_Half attr;5845Dwarf_Signed attr_count, cnt;5846Dwarf_Unsigned bytecnt;5847Dwarf_Off off;5848int i, j, ret;58495850if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=5851DW_DLV_OK) {5852if (ret == DW_DLV_ERROR)5853warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));5854goto cont_search;5855}58565857for (i = 0; i < attr_count; i++) {5858if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {5859warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));5860continue;5861}5862if (attr != DW_AT_ranges)5863continue;5864if (dwarf_global_formref(attr_list[i], &off, &de) != DW_DLV_OK) {5865warnx("dwarf_global_formref failed: %s",5866dwarf_errmsg(de));5867continue;5868}5869if (dwarf_get_ranges(re->dbg, off, &ranges, &cnt,5870&bytecnt, &de) != DW_DLV_OK)5871continue;5872base0 = base;5873for (j = 0; j < cnt; j++) {5874printf(" %08jx ", (uintmax_t) off);5875if (ranges[j].dwr_type == DW_RANGES_END) {5876printf("%s\n", "<End of list>");5877continue;5878} else if (ranges[j].dwr_type ==5879DW_RANGES_ADDRESS_SELECTION) {5880base0 = ranges[j].dwr_addr2;5881continue;5882}5883if (re->ec == ELFCLASS32)5884printf("%08jx %08jx\n",5885(uintmax_t) (ranges[j].dwr_addr1 + base0),5886(uintmax_t) (ranges[j].dwr_addr2 + base0));5887else5888printf("%016jx %016jx\n",5889(uintmax_t) (ranges[j].dwr_addr1 + base0),5890(uintmax_t) (ranges[j].dwr_addr2 + base0));5891}5892}58935894cont_search:5895/* Search children. */5896ret = dwarf_child(die, &ret_die, &de);5897if (ret == DW_DLV_ERROR)5898warnx("dwarf_child: %s", dwarf_errmsg(de));5899else if (ret == DW_DLV_OK)5900dump_dwarf_ranges_foreach(re, ret_die, base);59015902/* Search sibling. */5903ret = dwarf_siblingof(re->dbg, die, &ret_die, &de);5904if (ret == DW_DLV_ERROR)5905warnx("dwarf_siblingof: %s", dwarf_errmsg(de));5906else if (ret == DW_DLV_OK)5907dump_dwarf_ranges_foreach(re, ret_die, base);59085909dwarf_dealloc(re->dbg, die, DW_DLA_DIE);5910}59115912static void5913dump_dwarf_ranges(struct readelf *re)5914{5915Dwarf_Ranges *ranges;5916Dwarf_Die die;5917Dwarf_Signed cnt;5918Dwarf_Unsigned bytecnt;5919Dwarf_Half tag;5920Dwarf_Error de;5921Dwarf_Unsigned lowpc;5922int ret;59235924if (dwarf_get_ranges(re->dbg, 0, &ranges, &cnt, &bytecnt, &de) !=5925DW_DLV_OK)5926return;59275928printf("Contents of the .debug_ranges section:\n\n");5929if (re->ec == ELFCLASS32)5930printf(" %-8s %-8s %s\n", "Offset", "Begin", "End");5931else5932printf(" %-8s %-16s %s\n", "Offset", "Begin", "End");59335934while ((ret = dwarf_next_cu_header(re->dbg, NULL, NULL, NULL, NULL,5935NULL, &de)) == DW_DLV_OK) {5936die = NULL;5937if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK)5938continue;5939if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {5940warnx("dwarf_tag failed: %s", dwarf_errmsg(de));5941continue;5942}5943/* XXX: What about DW_TAG_partial_unit? */5944lowpc = 0;5945if (tag == DW_TAG_compile_unit) {5946if (dwarf_attrval_unsigned(die, DW_AT_low_pc, &lowpc,5947&de) != DW_DLV_OK)5948lowpc = 0;5949}59505951dump_dwarf_ranges_foreach(re, die, (Dwarf_Addr) lowpc);5952}5953putchar('\n');5954}59555956static void5957dump_dwarf_macinfo(struct readelf *re)5958{5959Dwarf_Unsigned offset;5960Dwarf_Signed cnt;5961Dwarf_Macro_Details *md;5962Dwarf_Error de;5963const char *mi_str;5964char unk_mi[32];5965int i;59665967#define _MAX_MACINFO_ENTRY 6553559685969printf("\nContents of section .debug_macinfo:\n\n");59705971offset = 0;5972while (dwarf_get_macro_details(re->dbg, offset, _MAX_MACINFO_ENTRY,5973&cnt, &md, &de) == DW_DLV_OK) {5974for (i = 0; i < cnt; i++) {5975offset = md[i].dmd_offset + 1;5976if (md[i].dmd_type == 0)5977break;5978if (dwarf_get_MACINFO_name(md[i].dmd_type, &mi_str) !=5979DW_DLV_OK) {5980snprintf(unk_mi, sizeof(unk_mi),5981"[Unknown MACINFO: %#x]", md[i].dmd_type);5982mi_str = unk_mi;5983}5984printf(" %s", mi_str);5985switch (md[i].dmd_type) {5986case DW_MACINFO_define:5987case DW_MACINFO_undef:5988printf(" - lineno : %jd macro : %s\n",5989(intmax_t) md[i].dmd_lineno,5990md[i].dmd_macro);5991break;5992case DW_MACINFO_start_file:5993printf(" - lineno : %jd filenum : %jd\n",5994(intmax_t) md[i].dmd_lineno,5995(intmax_t) md[i].dmd_fileindex);5996break;5997default:5998putchar('\n');5999break;6000}6001}6002}60036004#undef _MAX_MACINFO_ENTRY6005}60066007static void6008dump_dwarf_frame_inst(struct readelf *re, Dwarf_Cie cie, uint8_t *insts,6009Dwarf_Unsigned len, Dwarf_Unsigned caf, Dwarf_Signed daf, Dwarf_Addr pc,6010Dwarf_Debug dbg)6011{6012Dwarf_Frame_Op *oplist;6013Dwarf_Signed opcnt, delta;6014Dwarf_Small op;6015Dwarf_Error de;6016const char *op_str;6017char unk_op[32];6018int i;60196020if (dwarf_expand_frame_instructions(cie, insts, len, &oplist,6021&opcnt, &de) != DW_DLV_OK) {6022warnx("dwarf_expand_frame_instructions failed: %s",6023dwarf_errmsg(de));6024return;6025}60266027for (i = 0; i < opcnt; i++) {6028if (oplist[i].fp_base_op != 0)6029op = oplist[i].fp_base_op << 6;6030else6031op = oplist[i].fp_extended_op;6032if (dwarf_get_CFA_name(op, &op_str) != DW_DLV_OK) {6033snprintf(unk_op, sizeof(unk_op), "[Unknown CFA: %#x]",6034op);6035op_str = unk_op;6036}6037printf(" %s", op_str);6038switch (op) {6039case DW_CFA_advance_loc:6040delta = oplist[i].fp_offset * caf;6041pc += delta;6042printf(": %ju to %08jx", (uintmax_t) delta,6043(uintmax_t) pc);6044break;6045case DW_CFA_offset:6046case DW_CFA_offset_extended:6047case DW_CFA_offset_extended_sf:6048delta = oplist[i].fp_offset * daf;6049printf(": r%u (%s) at cfa%+jd", oplist[i].fp_register,6050dwarf_regname(re, oplist[i].fp_register),6051(intmax_t) delta);6052break;6053case DW_CFA_restore:6054printf(": r%u (%s)", oplist[i].fp_register,6055dwarf_regname(re, oplist[i].fp_register));6056break;6057case DW_CFA_set_loc:6058pc = oplist[i].fp_offset;6059printf(": to %08jx", (uintmax_t) pc);6060break;6061case DW_CFA_advance_loc1:6062case DW_CFA_advance_loc2:6063case DW_CFA_advance_loc4:6064pc += oplist[i].fp_offset;6065printf(": %jd to %08jx", (intmax_t) oplist[i].fp_offset,6066(uintmax_t) pc);6067break;6068case DW_CFA_def_cfa:6069printf(": r%u (%s) ofs %ju", oplist[i].fp_register,6070dwarf_regname(re, oplist[i].fp_register),6071(uintmax_t) oplist[i].fp_offset);6072break;6073case DW_CFA_def_cfa_sf:6074printf(": r%u (%s) ofs %jd", oplist[i].fp_register,6075dwarf_regname(re, oplist[i].fp_register),6076(intmax_t) (oplist[i].fp_offset * daf));6077break;6078case DW_CFA_def_cfa_register:6079printf(": r%u (%s)", oplist[i].fp_register,6080dwarf_regname(re, oplist[i].fp_register));6081break;6082case DW_CFA_def_cfa_offset:6083printf(": %ju", (uintmax_t) oplist[i].fp_offset);6084break;6085case DW_CFA_def_cfa_offset_sf:6086printf(": %jd", (intmax_t) (oplist[i].fp_offset * daf));6087break;6088default:6089break;6090}6091putchar('\n');6092}60936094dwarf_dealloc(dbg, oplist, DW_DLA_FRAME_BLOCK);6095}60966097static char *6098get_regoff_str(struct readelf *re, Dwarf_Half reg, Dwarf_Addr off)6099{6100static char rs[16];61016102if (reg == DW_FRAME_UNDEFINED_VAL || reg == DW_FRAME_REG_INITIAL_VALUE)6103snprintf(rs, sizeof(rs), "%c", 'u');6104else if (reg == DW_FRAME_CFA_COL)6105snprintf(rs, sizeof(rs), "c%+jd", (intmax_t) off);6106else6107snprintf(rs, sizeof(rs), "%s%+jd", dwarf_regname(re, reg),6108(intmax_t) off);61096110return (rs);6111}61126113static int6114dump_dwarf_frame_regtable(struct readelf *re, Dwarf_Fde fde, Dwarf_Addr pc,6115Dwarf_Unsigned func_len, Dwarf_Half cie_ra)6116{6117Dwarf_Regtable rt;6118Dwarf_Addr row_pc, end_pc, pre_pc, cur_pc;6119Dwarf_Error de;6120char *vec;6121int i;61226123#define BIT_SET(v, n) (v[(n)>>3] |= 1U << ((n) & 7))6124#define BIT_CLR(v, n) (v[(n)>>3] &= ~(1U << ((n) & 7)))6125#define BIT_ISSET(v, n) (v[(n)>>3] & (1U << ((n) & 7)))6126#define RT(x) rt.rules[(x)]61276128vec = calloc((DW_REG_TABLE_SIZE + 7) / 8, 1);6129if (vec == NULL)6130err(EXIT_FAILURE, "calloc failed");61316132pre_pc = ~((Dwarf_Addr) 0);6133cur_pc = pc;6134end_pc = pc + func_len;6135for (; cur_pc < end_pc; cur_pc++) {6136if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc,6137&de) != DW_DLV_OK) {6138free(vec);6139warnx("dwarf_get_fde_info_for_all_regs failed: %s\n",6140dwarf_errmsg(de));6141return (-1);6142}6143if (row_pc == pre_pc)6144continue;6145pre_pc = row_pc;6146for (i = 1; i < DW_REG_TABLE_SIZE; i++) {6147if (rt.rules[i].dw_regnum != DW_FRAME_REG_INITIAL_VALUE)6148BIT_SET(vec, i);6149}6150}61516152printf(" LOC CFA ");6153for (i = 1; i < DW_REG_TABLE_SIZE; i++) {6154if (BIT_ISSET(vec, i)) {6155if ((Dwarf_Half) i == cie_ra)6156printf("ra ");6157else6158printf("%-5s",6159dwarf_regname(re, (unsigned int) i));6160}6161}6162putchar('\n');61636164pre_pc = ~((Dwarf_Addr) 0);6165cur_pc = pc;6166end_pc = pc + func_len;6167for (; cur_pc < end_pc; cur_pc++) {6168if (dwarf_get_fde_info_for_all_regs(fde, cur_pc, &rt, &row_pc,6169&de) != DW_DLV_OK) {6170free(vec);6171warnx("dwarf_get_fde_info_for_all_regs failed: %s\n",6172dwarf_errmsg(de));6173return (-1);6174}6175if (row_pc == pre_pc)6176continue;6177pre_pc = row_pc;6178printf("%08jx ", (uintmax_t) row_pc);6179printf("%-8s ", get_regoff_str(re, RT(0).dw_regnum,6180RT(0).dw_offset));6181for (i = 1; i < DW_REG_TABLE_SIZE; i++) {6182if (BIT_ISSET(vec, i)) {6183printf("%-5s", get_regoff_str(re,6184RT(i).dw_regnum, RT(i).dw_offset));6185}6186}6187putchar('\n');6188}61896190free(vec);61916192return (0);61936194#undef BIT_SET6195#undef BIT_CLR6196#undef BIT_ISSET6197#undef RT6198}61996200static void6201dump_dwarf_frame_section(struct readelf *re, struct section *s, int alt)6202{6203Dwarf_Cie *cie_list, cie, pre_cie;6204Dwarf_Fde *fde_list, fde;6205Dwarf_Off cie_offset, fde_offset;6206Dwarf_Unsigned cie_length, fde_instlen;6207Dwarf_Unsigned cie_caf, cie_daf, cie_instlen, func_len, fde_length;6208Dwarf_Signed cie_count, fde_count, cie_index;6209Dwarf_Addr low_pc;6210Dwarf_Half cie_ra;6211Dwarf_Small cie_version;6212Dwarf_Ptr fde_addr, fde_inst, cie_inst;6213char *cie_aug, c;6214int i, ret, eh_frame;6215Dwarf_Error de;62166217printf("\nThe section %s contains:\n\n", s->name);62186219if (!strcmp(s->name, ".debug_frame")) {6220eh_frame = 0;6221if (dwarf_get_fde_list(re->dbg, &cie_list, &cie_count,6222&fde_list, &fde_count, &de) != DW_DLV_OK) {6223warnx("dwarf_get_fde_list failed: %s",6224dwarf_errmsg(de));6225return;6226}6227} else if (!strcmp(s->name, ".eh_frame")) {6228eh_frame = 1;6229ret = dwarf_get_fde_list_eh(re->dbg, &cie_list, &cie_count,6230&fde_list, &fde_count, &de);6231if (ret != DW_DLV_OK) {6232if (ret == DW_DLV_ERROR) {6233warnx("dwarf_get_fde_list_eh failed: %s",6234dwarf_errmsg(de));6235}6236return;6237}6238} else6239return;62406241pre_cie = NULL;6242for (i = 0; i < fde_count; i++) {6243if (dwarf_get_fde_n(fde_list, i, &fde, &de) != DW_DLV_OK) {6244warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de));6245continue;6246}6247if (dwarf_get_cie_of_fde(fde, &cie, &de) != DW_DLV_OK) {6248warnx("dwarf_get_fde_n failed: %s", dwarf_errmsg(de));6249continue;6250}6251if (dwarf_get_fde_range(fde, &low_pc, &func_len, &fde_addr,6252&fde_length, &cie_offset, &cie_index, &fde_offset,6253&de) != DW_DLV_OK) {6254warnx("dwarf_get_fde_range failed: %s",6255dwarf_errmsg(de));6256continue;6257}6258if (dwarf_get_fde_instr_bytes(fde, &fde_inst, &fde_instlen,6259&de) != DW_DLV_OK) {6260warnx("dwarf_get_fde_instr_bytes failed: %s",6261dwarf_errmsg(de));6262continue;6263}6264if (pre_cie == NULL || cie != pre_cie) {6265pre_cie = cie;6266if (dwarf_get_cie_info(cie, &cie_length, &cie_version,6267&cie_aug, &cie_caf, &cie_daf, &cie_ra,6268&cie_inst, &cie_instlen, &de) != DW_DLV_OK) {6269warnx("dwarf_get_cie_info failed: %s",6270dwarf_errmsg(de));6271continue;6272}6273printf("%08jx %08jx %8.8jx CIE",6274(uintmax_t) cie_offset,6275(uintmax_t) cie_length,6276(uintmax_t) (eh_frame ? 0 : ~0U));6277if (!alt) {6278putchar('\n');6279printf(" Version:\t\t\t%u\n", cie_version);6280printf(" Augmentation:\t\t\t\"");6281while ((c = *cie_aug++) != '\0')6282putchar(c);6283printf("\"\n");6284printf(" Code alignment factor:\t%ju\n",6285(uintmax_t) cie_caf);6286printf(" Data alignment factor:\t%jd\n",6287(intmax_t) cie_daf);6288printf(" Return address column:\t%ju\n",6289(uintmax_t) cie_ra);6290putchar('\n');6291dump_dwarf_frame_inst(re, cie, cie_inst,6292cie_instlen, cie_caf, cie_daf, 0,6293re->dbg);6294putchar('\n');6295} else {6296printf(" \"");6297while ((c = *cie_aug++) != '\0')6298putchar(c);6299putchar('"');6300printf(" cf=%ju df=%jd ra=%ju\n",6301(uintmax_t) cie_caf,6302(uintmax_t) cie_daf,6303(uintmax_t) cie_ra);6304dump_dwarf_frame_regtable(re, fde, low_pc, 1,6305cie_ra);6306putchar('\n');6307}6308}6309printf("%08jx %08jx %08jx FDE cie=%08jx pc=%08jx..%08jx\n",6310(uintmax_t) fde_offset, (uintmax_t) fde_length,6311(uintmax_t) cie_offset,6312(uintmax_t) (eh_frame ? fde_offset + 4 - cie_offset :6313cie_offset),6314(uintmax_t) low_pc, (uintmax_t) (low_pc + func_len));6315if (!alt)6316dump_dwarf_frame_inst(re, cie, fde_inst, fde_instlen,6317cie_caf, cie_daf, low_pc, re->dbg);6318else6319dump_dwarf_frame_regtable(re, fde, low_pc, func_len,6320cie_ra);6321putchar('\n');6322}6323}63246325static void6326dump_dwarf_frame(struct readelf *re, int alt)6327{6328struct section *s;6329int i;63306331(void) dwarf_set_frame_cfa_value(re->dbg, DW_FRAME_CFA_COL);63326333for (i = 0; (size_t) i < re->shnum; i++) {6334s = &re->sl[i];6335if (s->name != NULL && (!strcmp(s->name, ".debug_frame") ||6336!strcmp(s->name, ".eh_frame")))6337dump_dwarf_frame_section(re, s, alt);6338}6339}63406341static void6342dump_dwarf_str(struct readelf *re)6343{6344struct section *s;6345Elf_Data *d;6346unsigned char *p;6347int elferr, end, i, j;63486349printf("\nContents of section .debug_str:\n");63506351s = NULL;6352for (i = 0; (size_t) i < re->shnum; i++) {6353s = &re->sl[i];6354if (s->name != NULL && !strcmp(s->name, ".debug_str"))6355break;6356}6357if ((size_t) i >= re->shnum)6358return;63596360(void) elf_errno();6361if ((d = elf_getdata(s->scn, NULL)) == NULL) {6362elferr = elf_errno();6363if (elferr != 0)6364warnx("elf_getdata failed: %s", elf_errmsg(-1));6365return;6366}6367if (d->d_size <= 0)6368return;63696370for (i = 0, p = d->d_buf; (size_t) i < d->d_size; i += 16) {6371printf(" 0x%08x", (unsigned int) i);6372if ((size_t) i + 16 > d->d_size)6373end = d->d_size;6374else6375end = i + 16;6376for (j = i; j < i + 16; j++) {6377if ((j - i) % 4 == 0)6378putchar(' ');6379if (j >= end) {6380printf(" ");6381continue;6382}6383printf("%02x", (uint8_t) p[j]);6384}6385putchar(' ');6386for (j = i; j < end; j++) {6387if (isprint(p[j]))6388putchar(p[j]);6389else if (p[j] == 0)6390putchar('.');6391else6392putchar(' ');6393}6394putchar('\n');6395}6396}63976398static int6399loc_at_comparator(const void *la1, const void *la2)6400{6401const struct loc_at *left, *right;64026403left = (const struct loc_at *)la1;6404right = (const struct loc_at *)la2;64056406if (left->la_off > right->la_off)6407return (1);6408else if (left->la_off < right->la_off)6409return (-1);6410else6411return (0);6412}64136414static void6415search_loclist_at(struct readelf *re, Dwarf_Die die, Dwarf_Unsigned lowpc,6416struct loc_at **la_list, size_t *la_list_len, size_t *la_list_cap)6417{6418struct loc_at *la;6419Dwarf_Attribute *attr_list;6420Dwarf_Die ret_die;6421Dwarf_Unsigned off;6422Dwarf_Off ref;6423Dwarf_Signed attr_count;6424Dwarf_Half attr, form;6425Dwarf_Bool is_info;6426Dwarf_Error de;6427int i, ret;64286429is_info = dwarf_get_die_infotypes_flag(die);64306431if ((ret = dwarf_attrlist(die, &attr_list, &attr_count, &de)) !=6432DW_DLV_OK) {6433if (ret == DW_DLV_ERROR)6434warnx("dwarf_attrlist failed: %s", dwarf_errmsg(de));6435goto cont_search;6436}6437for (i = 0; i < attr_count; i++) {6438if (dwarf_whatattr(attr_list[i], &attr, &de) != DW_DLV_OK) {6439warnx("dwarf_whatattr failed: %s", dwarf_errmsg(de));6440continue;6441}6442if (attr != DW_AT_location &&6443attr != DW_AT_string_length &&6444attr != DW_AT_return_addr &&6445attr != DW_AT_data_member_location &&6446attr != DW_AT_frame_base &&6447attr != DW_AT_segment &&6448attr != DW_AT_static_link &&6449attr != DW_AT_use_location &&6450attr != DW_AT_vtable_elem_location)6451continue;6452if (dwarf_whatform(attr_list[i], &form, &de) != DW_DLV_OK) {6453warnx("dwarf_whatform failed: %s", dwarf_errmsg(de));6454continue;6455}6456if (form == DW_FORM_data4 || form == DW_FORM_data8) {6457if (dwarf_formudata(attr_list[i], &off, &de) !=6458DW_DLV_OK) {6459warnx("dwarf_formudata failed: %s",6460dwarf_errmsg(de));6461continue;6462}6463} else if (form == DW_FORM_sec_offset) {6464if (dwarf_global_formref(attr_list[i], &ref, &de) !=6465DW_DLV_OK) {6466warnx("dwarf_global_formref failed: %s",6467dwarf_errmsg(de));6468continue;6469}6470off = ref;6471} else6472continue;64736474if (*la_list_cap == *la_list_len) {6475*la_list = realloc(*la_list,6476*la_list_cap * 2 * sizeof(**la_list));6477if (*la_list == NULL)6478err(EXIT_FAILURE, "realloc failed");6479*la_list_cap *= 2;6480}6481la = &((*la_list)[*la_list_len]);6482la->la_at = attr_list[i];6483la->la_off = off;6484la->la_lowpc = lowpc;6485la->la_cu_psize = re->cu_psize;6486la->la_cu_osize = re->cu_osize;6487la->la_cu_ver = re->cu_ver;6488(*la_list_len)++;6489}64906491cont_search:6492/* Search children. */6493ret = dwarf_child(die, &ret_die, &de);6494if (ret == DW_DLV_ERROR)6495warnx("dwarf_child: %s", dwarf_errmsg(de));6496else if (ret == DW_DLV_OK)6497search_loclist_at(re, ret_die, lowpc, la_list,6498la_list_len, la_list_cap);64996500/* Search sibling. */6501ret = dwarf_siblingof_b(re->dbg, die, &ret_die, is_info, &de);6502if (ret == DW_DLV_ERROR)6503warnx("dwarf_siblingof: %s", dwarf_errmsg(de));6504else if (ret == DW_DLV_OK)6505search_loclist_at(re, ret_die, lowpc, la_list,6506la_list_len, la_list_cap);6507}65086509static void6510dump_dwarf_loc(struct readelf *re, Dwarf_Loc *lr)6511{6512const char *op_str;6513char unk_op[32];6514uint8_t *b, n;6515int i;65166517if (dwarf_get_OP_name(lr->lr_atom, &op_str) !=6518DW_DLV_OK) {6519snprintf(unk_op, sizeof(unk_op),6520"[Unknown OP: %#x]", lr->lr_atom);6521op_str = unk_op;6522}65236524printf("%s", op_str);65256526switch (lr->lr_atom) {6527case DW_OP_reg0:6528case DW_OP_reg1:6529case DW_OP_reg2:6530case DW_OP_reg3:6531case DW_OP_reg4:6532case DW_OP_reg5:6533case DW_OP_reg6:6534case DW_OP_reg7:6535case DW_OP_reg8:6536case DW_OP_reg9:6537case DW_OP_reg10:6538case DW_OP_reg11:6539case DW_OP_reg12:6540case DW_OP_reg13:6541case DW_OP_reg14:6542case DW_OP_reg15:6543case DW_OP_reg16:6544case DW_OP_reg17:6545case DW_OP_reg18:6546case DW_OP_reg19:6547case DW_OP_reg20:6548case DW_OP_reg21:6549case DW_OP_reg22:6550case DW_OP_reg23:6551case DW_OP_reg24:6552case DW_OP_reg25:6553case DW_OP_reg26:6554case DW_OP_reg27:6555case DW_OP_reg28:6556case DW_OP_reg29:6557case DW_OP_reg30:6558case DW_OP_reg31:6559printf(" (%s)", dwarf_regname(re, lr->lr_atom - DW_OP_reg0));6560break;65616562case DW_OP_deref:6563case DW_OP_lit0:6564case DW_OP_lit1:6565case DW_OP_lit2:6566case DW_OP_lit3:6567case DW_OP_lit4:6568case DW_OP_lit5:6569case DW_OP_lit6:6570case DW_OP_lit7:6571case DW_OP_lit8:6572case DW_OP_lit9:6573case DW_OP_lit10:6574case DW_OP_lit11:6575case DW_OP_lit12:6576case DW_OP_lit13:6577case DW_OP_lit14:6578case DW_OP_lit15:6579case DW_OP_lit16:6580case DW_OP_lit17:6581case DW_OP_lit18:6582case DW_OP_lit19:6583case DW_OP_lit20:6584case DW_OP_lit21:6585case DW_OP_lit22:6586case DW_OP_lit23:6587case DW_OP_lit24:6588case DW_OP_lit25:6589case DW_OP_lit26:6590case DW_OP_lit27:6591case DW_OP_lit28:6592case DW_OP_lit29:6593case DW_OP_lit30:6594case DW_OP_lit31:6595case DW_OP_dup:6596case DW_OP_drop:6597case DW_OP_over:6598case DW_OP_swap:6599case DW_OP_rot:6600case DW_OP_xderef:6601case DW_OP_abs:6602case DW_OP_and:6603case DW_OP_div:6604case DW_OP_minus:6605case DW_OP_mod:6606case DW_OP_mul:6607case DW_OP_neg:6608case DW_OP_not:6609case DW_OP_or:6610case DW_OP_plus:6611case DW_OP_shl:6612case DW_OP_shr:6613case DW_OP_shra:6614case DW_OP_xor:6615case DW_OP_eq:6616case DW_OP_ge:6617case DW_OP_gt:6618case DW_OP_le:6619case DW_OP_lt:6620case DW_OP_ne:6621case DW_OP_nop:6622case DW_OP_push_object_address:6623case DW_OP_form_tls_address:6624case DW_OP_call_frame_cfa:6625case DW_OP_stack_value:6626case DW_OP_GNU_push_tls_address:6627case DW_OP_GNU_uninit:6628break;66296630case DW_OP_const1u:6631case DW_OP_pick:6632case DW_OP_deref_size:6633case DW_OP_xderef_size:6634case DW_OP_const2u:6635case DW_OP_bra:6636case DW_OP_skip:6637case DW_OP_const4u:6638case DW_OP_const8u:6639case DW_OP_constu:6640case DW_OP_plus_uconst:6641case DW_OP_regx:6642case DW_OP_piece:6643printf(": %ju", (uintmax_t)6644lr->lr_number);6645break;66466647case DW_OP_const1s:6648case DW_OP_const2s:6649case DW_OP_const4s:6650case DW_OP_const8s:6651case DW_OP_consts:6652printf(": %jd", (intmax_t)6653lr->lr_number);6654break;66556656case DW_OP_breg0:6657case DW_OP_breg1:6658case DW_OP_breg2:6659case DW_OP_breg3:6660case DW_OP_breg4:6661case DW_OP_breg5:6662case DW_OP_breg6:6663case DW_OP_breg7:6664case DW_OP_breg8:6665case DW_OP_breg9:6666case DW_OP_breg10:6667case DW_OP_breg11:6668case DW_OP_breg12:6669case DW_OP_breg13:6670case DW_OP_breg14:6671case DW_OP_breg15:6672case DW_OP_breg16:6673case DW_OP_breg17:6674case DW_OP_breg18:6675case DW_OP_breg19:6676case DW_OP_breg20:6677case DW_OP_breg21:6678case DW_OP_breg22:6679case DW_OP_breg23:6680case DW_OP_breg24:6681case DW_OP_breg25:6682case DW_OP_breg26:6683case DW_OP_breg27:6684case DW_OP_breg28:6685case DW_OP_breg29:6686case DW_OP_breg30:6687case DW_OP_breg31:6688printf(" (%s): %jd",6689dwarf_regname(re, lr->lr_atom - DW_OP_breg0),6690(intmax_t) lr->lr_number);6691break;66926693case DW_OP_fbreg:6694printf(": %jd", (intmax_t)6695lr->lr_number);6696break;66976698case DW_OP_bregx:6699printf(": %ju (%s) %jd",6700(uintmax_t) lr->lr_number,6701dwarf_regname(re, (unsigned int) lr->lr_number),6702(intmax_t) lr->lr_number2);6703break;67046705case DW_OP_addr:6706case DW_OP_GNU_encoded_addr:6707printf(": %#jx", (uintmax_t)6708lr->lr_number);6709break;67106711case DW_OP_GNU_implicit_pointer:6712printf(": <0x%jx> %jd", (uintmax_t) lr->lr_number,6713(intmax_t) lr->lr_number2);6714break;67156716case DW_OP_implicit_value:6717printf(": %ju byte block:", (uintmax_t) lr->lr_number);6718b = (uint8_t *)(uintptr_t) lr->lr_number2;6719for (i = 0; (Dwarf_Unsigned) i < lr->lr_number; i++)6720printf(" %x", b[i]);6721break;67226723case DW_OP_GNU_entry_value:6724printf(": (");6725dump_dwarf_block(re, (uint8_t *)(uintptr_t) lr->lr_number2,6726lr->lr_number);6727putchar(')');6728break;67296730case DW_OP_GNU_const_type:6731printf(": <0x%jx> ", (uintmax_t) lr->lr_number);6732b = (uint8_t *)(uintptr_t) lr->lr_number2;6733n = *b;6734for (i = 1; (uint8_t) i < n; i++)6735printf(" %x", b[i]);6736break;67376738case DW_OP_GNU_regval_type:6739printf(": %ju (%s) <0x%jx>", (uintmax_t) lr->lr_number,6740dwarf_regname(re, (unsigned int) lr->lr_number),6741(uintmax_t) lr->lr_number2);6742break;67436744case DW_OP_GNU_convert:6745case DW_OP_GNU_deref_type:6746case DW_OP_GNU_parameter_ref:6747case DW_OP_GNU_reinterpret:6748printf(": <0x%jx>", (uintmax_t) lr->lr_number);6749break;67506751default:6752break;6753}6754}67556756static void6757dump_dwarf_block(struct readelf *re, uint8_t *b, Dwarf_Unsigned len)6758{6759Dwarf_Locdesc *llbuf;6760Dwarf_Signed lcnt;6761Dwarf_Error de;6762int i;67636764if (dwarf_loclist_from_expr_b(re->dbg, b, len, re->cu_psize,6765re->cu_osize, re->cu_ver, &llbuf, &lcnt, &de) != DW_DLV_OK) {6766warnx("dwarf_loclist_form_expr_b: %s", dwarf_errmsg(de));6767return;6768}67696770for (i = 0; (Dwarf_Half) i < llbuf->ld_cents; i++) {6771dump_dwarf_loc(re, &llbuf->ld_s[i]);6772if (i < llbuf->ld_cents - 1)6773printf("; ");6774}67756776dwarf_dealloc(re->dbg, llbuf->ld_s, DW_DLA_LOC_BLOCK);6777dwarf_dealloc(re->dbg, llbuf, DW_DLA_LOCDESC);6778}67796780static void6781dump_dwarf_loclist(struct readelf *re)6782{6783Dwarf_Die die;6784Dwarf_Locdesc **llbuf;6785Dwarf_Unsigned lowpc;6786Dwarf_Signed lcnt;6787Dwarf_Half tag, version, pointer_size, off_size;6788Dwarf_Error de;6789struct loc_at *la_list, *left, *right, *la;6790size_t la_list_len, la_list_cap;6791unsigned int duplicates, k;6792int i, j, ret, has_content;67936794la_list_len = 0;6795la_list_cap = 200;6796if ((la_list = calloc(la_list_cap, sizeof(struct loc_at))) == NULL)6797errx(EXIT_FAILURE, "calloc failed");6798/* Search .debug_info section. */6799while ((ret = dwarf_next_cu_header_b(re->dbg, NULL, &version, NULL,6800&pointer_size, &off_size, NULL, NULL, &de)) == DW_DLV_OK) {6801set_cu_context(re, pointer_size, off_size, version);6802die = NULL;6803if (dwarf_siblingof(re->dbg, die, &die, &de) != DW_DLV_OK)6804continue;6805if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {6806warnx("dwarf_tag failed: %s", dwarf_errmsg(de));6807continue;6808}6809/* XXX: What about DW_TAG_partial_unit? */6810lowpc = 0;6811if (tag == DW_TAG_compile_unit) {6812if (dwarf_attrval_unsigned(die, DW_AT_low_pc,6813&lowpc, &de) != DW_DLV_OK)6814lowpc = 0;6815}68166817/* Search attributes for reference to .debug_loc section. */6818search_loclist_at(re, die, lowpc, &la_list,6819&la_list_len, &la_list_cap);6820}6821if (ret == DW_DLV_ERROR)6822warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));68236824/* Search .debug_types section. */6825do {6826while ((ret = dwarf_next_cu_header_c(re->dbg, 0, NULL,6827&version, NULL, &pointer_size, &off_size, NULL, NULL,6828NULL, NULL, &de)) == DW_DLV_OK) {6829set_cu_context(re, pointer_size, off_size, version);6830die = NULL;6831if (dwarf_siblingof(re->dbg, die, &die, &de) !=6832DW_DLV_OK)6833continue;6834if (dwarf_tag(die, &tag, &de) != DW_DLV_OK) {6835warnx("dwarf_tag failed: %s",6836dwarf_errmsg(de));6837continue;6838}68396840lowpc = 0;6841if (tag == DW_TAG_type_unit) {6842if (dwarf_attrval_unsigned(die, DW_AT_low_pc,6843&lowpc, &de) != DW_DLV_OK)6844lowpc = 0;6845}68466847/*6848* Search attributes for reference to .debug_loc6849* section.6850*/6851search_loclist_at(re, die, lowpc, &la_list,6852&la_list_len, &la_list_cap);6853}6854if (ret == DW_DLV_ERROR)6855warnx("dwarf_next_cu_header: %s", dwarf_errmsg(de));6856} while (dwarf_next_types_section(re->dbg, &de) == DW_DLV_OK);68576858if (la_list_len == 0) {6859free(la_list);6860return;6861}68626863/* Sort la_list using loc_at_comparator. */6864qsort(la_list, la_list_len, sizeof(struct loc_at), loc_at_comparator);68656866/* Get rid of the duplicates in la_list. */6867duplicates = 0;6868for (k = 1; k < la_list_len; ++k) {6869left = &la_list[k - 1 - duplicates];6870right = &la_list[k];68716872if (left->la_off == right->la_off)6873duplicates++;6874else6875la_list[k - duplicates] = *right;6876}6877la_list_len -= duplicates;68786879has_content = 0;6880for (k = 0; k < la_list_len; ++k) {6881la = &la_list[k];6882if ((ret = dwarf_loclist_n(la->la_at, &llbuf, &lcnt, &de)) !=6883DW_DLV_OK) {6884if (ret != DW_DLV_NO_ENTRY)6885warnx("dwarf_loclist_n failed: %s",6886dwarf_errmsg(de));6887continue;6888}6889if (!has_content) {6890has_content = 1;6891printf("\nContents of section .debug_loc:\n");6892printf(" Offset Begin End Expression\n");6893}6894set_cu_context(re, la->la_cu_psize, la->la_cu_osize,6895la->la_cu_ver);6896for (i = 0; i < lcnt; i++) {6897printf(" %8.8jx ", (uintmax_t) la->la_off);6898if (llbuf[i]->ld_lopc == 0 && llbuf[i]->ld_hipc == 0) {6899printf("<End of list>\n");6900continue;6901}69026903/* TODO: handle base selection entry. */69046905printf("%8.8jx %8.8jx ",6906(uintmax_t) (la->la_lowpc + llbuf[i]->ld_lopc),6907(uintmax_t) (la->la_lowpc + llbuf[i]->ld_hipc));69086909putchar('(');6910for (j = 0; (Dwarf_Half) j < llbuf[i]->ld_cents; j++) {6911dump_dwarf_loc(re, &llbuf[i]->ld_s[j]);6912if (j < llbuf[i]->ld_cents - 1)6913printf("; ");6914}6915putchar(')');69166917if (llbuf[i]->ld_lopc == llbuf[i]->ld_hipc)6918printf(" (start == end)");6919putchar('\n');6920}6921for (i = 0; i < lcnt; i++) {6922dwarf_dealloc(re->dbg, llbuf[i]->ld_s,6923DW_DLA_LOC_BLOCK);6924dwarf_dealloc(re->dbg, llbuf[i], DW_DLA_LOCDESC);6925}6926dwarf_dealloc(re->dbg, llbuf, DW_DLA_LIST);6927}69286929if (!has_content)6930printf("\nSection '.debug_loc' has no debugging data.\n");69316932free(la_list);6933}69346935/*6936* Retrieve a string using string table section index and the string offset.6937*/6938static const char*6939get_string(struct readelf *re, int strtab, size_t off)6940{6941const char *name;69426943if ((name = elf_strptr(re->elf, strtab, off)) == NULL)6944return ("");69456946return (name);6947}69486949/*6950* Retrieve the name of a symbol using the section index of the symbol6951* table and the index of the symbol within that table.6952*/6953static const char *6954get_symbol_name(struct readelf *re, int symtab, int i)6955{6956struct section *s;6957const char *name;6958GElf_Sym sym;6959Elf_Data *data;6960int elferr;69616962s = &re->sl[symtab];6963if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM)6964return ("");6965(void) elf_errno();6966if ((data = elf_getdata(s->scn, NULL)) == NULL) {6967elferr = elf_errno();6968if (elferr != 0)6969warnx("elf_getdata failed: %s", elf_errmsg(elferr));6970return ("");6971}6972if (gelf_getsym(data, i, &sym) != &sym)6973return ("");6974/* Return section name for STT_SECTION symbol. */6975if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {6976if (sym.st_shndx < re->shnum &&6977re->sl[sym.st_shndx].name != NULL)6978return (re->sl[sym.st_shndx].name);6979return ("");6980}6981if (s->link >= re->shnum ||6982(name = elf_strptr(re->elf, s->link, sym.st_name)) == NULL)6983return ("");69846985return (name);6986}69876988static uint64_t6989get_symbol_value(struct readelf *re, int symtab, int i)6990{6991struct section *s;6992GElf_Sym sym;6993Elf_Data *data;6994int elferr;69956996s = &re->sl[symtab];6997if (s->type != SHT_SYMTAB && s->type != SHT_DYNSYM)6998return (0);6999(void) elf_errno();7000if ((data = elf_getdata(s->scn, NULL)) == NULL) {7001elferr = elf_errno();7002if (elferr != 0)7003warnx("elf_getdata failed: %s", elf_errmsg(elferr));7004return (0);7005}7006if (gelf_getsym(data, i, &sym) != &sym)7007return (0);70087009return (sym.st_value);7010}70117012/*7013* Decompress a data section if needed (using ZLIB).7014* Returns true if sucessful, false otherwise.7015*/7016static bool decompress_section(struct section *s,7017unsigned char *compressed_data_buffer, size_t compressed_size,7018unsigned char **ret_buf, size_t *ret_sz)7019{7020GElf_Shdr sh;70217022if (gelf_getshdr(s->scn, &sh) == NULL)7023errx(EXIT_FAILURE, "gelf_getshdr() failed: %s", elf_errmsg(-1));70247025if (sh.sh_flags & SHF_COMPRESSED) {7026int ret;7027GElf_Chdr chdr;7028Elf64_Xword inflated_size;7029unsigned char *uncompressed_data_buffer = NULL;7030Elf64_Xword uncompressed_size;7031z_stream strm;70327033if (gelf_getchdr(s->scn, &chdr) == NULL)7034errx(EXIT_FAILURE, "gelf_getchdr() failed: %s", elf_errmsg(-1));7035if (chdr.ch_type != ELFCOMPRESS_ZLIB) {7036warnx("unknown compression type: %d", chdr.ch_type);7037return (false);7038}70397040inflated_size = 0;7041uncompressed_size = chdr.ch_size;7042uncompressed_data_buffer = malloc(uncompressed_size);7043compressed_data_buffer += sizeof(chdr);7044compressed_size -= sizeof(chdr);70457046strm.zalloc = Z_NULL;7047strm.zfree = Z_NULL;7048strm.opaque = Z_NULL;7049strm.avail_in = compressed_size;7050strm.avail_out = uncompressed_size;7051ret = inflateInit(&strm);70527053if (ret != Z_OK)7054goto fail;7055/*7056* The section can contain several compressed buffers,7057* so decompress in a loop until all data is inflated.7058*/7059while (inflated_size < compressed_size) {7060strm.next_in = compressed_data_buffer + inflated_size;7061strm.next_out = uncompressed_data_buffer + inflated_size;7062ret = inflate(&strm, Z_FINISH);7063if (ret != Z_STREAM_END)7064goto fail;7065inflated_size = uncompressed_size - strm.avail_out;7066ret = inflateReset(&strm);7067if (ret != Z_OK)7068goto fail;7069}7070if (strm.avail_out != 0)7071warnx("Warning: wrong info in compression header.");7072ret = inflateEnd(&strm);7073if (ret != Z_OK)7074goto fail;7075*ret_buf = uncompressed_data_buffer;7076*ret_sz = uncompressed_size;7077return (true);7078fail:7079inflateEnd(&strm);7080if (strm.msg)7081warnx("%s", strm.msg);7082else7083warnx("ZLIB error: %d", ret);7084free(uncompressed_data_buffer);7085return (false);7086}7087return (false);7088}70897090static void7091hex_dump(struct readelf *re)7092{7093struct section *s;7094Elf_Data *d;7095uint8_t *buf, *new_buf;7096size_t sz, nbytes;7097uint64_t addr;7098int elferr, i, j;70997100for (i = 1; (size_t) i < re->shnum; i++) {7101new_buf = NULL;7102s = &re->sl[i];7103if (find_dumpop(re, (size_t) i, s->name, HEX_DUMP, -1) == NULL)7104continue;7105(void) elf_errno();7106if ((d = elf_getdata(s->scn, NULL)) == NULL &&7107(d = elf_rawdata(s->scn, NULL)) == NULL) {7108elferr = elf_errno();7109if (elferr != 0)7110warnx("elf_getdata failed: %s",7111elf_errmsg(elferr));7112continue;7113}7114(void) elf_errno();7115if (d->d_size <= 0 || d->d_buf == NULL) {7116printf("\nSection '%s' has no data to dump.\n",7117s->name);7118continue;7119}7120buf = d->d_buf;7121sz = d->d_size;7122addr = s->addr;7123if (re->options & RE_Z) {7124if (decompress_section(s, d->d_buf, d->d_size,7125&new_buf, &sz))7126buf = new_buf;7127}7128printf("\nHex dump of section '%s':\n", s->name);7129while (sz > 0) {7130printf(" 0x%8.8jx ", (uintmax_t)addr);7131nbytes = sz > 16? 16 : sz;7132for (j = 0; j < 16; j++) {7133if ((size_t)j < nbytes)7134printf("%2.2x", buf[j]);7135else7136printf(" ");7137if ((j & 3) == 3)7138printf(" ");7139}7140for (j = 0; (size_t)j < nbytes; j++) {7141if (isprint(buf[j]))7142printf("%c", buf[j]);7143else7144printf(".");7145}7146printf("\n");7147buf += nbytes;7148addr += nbytes;7149sz -= nbytes;7150}7151free(new_buf);7152}7153}71547155static void7156str_dump(struct readelf *re)7157{7158struct section *s;7159Elf_Data *d;7160unsigned char *start, *end, *buf_end, *new_buf;7161unsigned int len;7162size_t sz;7163int i, j, elferr, found;71647165for (i = 1; (size_t) i < re->shnum; i++) {7166new_buf = NULL;7167s = &re->sl[i];7168if (find_dumpop(re, (size_t) i, s->name, STR_DUMP, -1) == NULL)7169continue;7170(void) elf_errno();7171if ((d = elf_getdata(s->scn, NULL)) == NULL &&7172(d = elf_rawdata(s->scn, NULL)) == NULL) {7173elferr = elf_errno();7174if (elferr != 0)7175warnx("elf_getdata failed: %s",7176elf_errmsg(elferr));7177continue;7178}7179(void) elf_errno();7180if (d->d_size <= 0 || d->d_buf == NULL) {7181printf("\nSection '%s' has no data to dump.\n",7182s->name);7183continue;7184}7185found = 0;7186start = d->d_buf;7187sz = d->d_size;7188if (re->options & RE_Z) {7189if (decompress_section(s, d->d_buf, d->d_size,7190&new_buf, &sz))7191start = new_buf;7192}7193buf_end = start + sz;7194printf("\nString dump of section '%s':\n", s->name);7195for (;;) {7196while (start < buf_end && !isprint(*start))7197start++;7198if (start >= buf_end)7199break;7200end = start + 1;7201while (end < buf_end && isprint(*end))7202end++;7203printf(" [%6lx] ",7204(long) (start - (unsigned char *) d->d_buf));7205len = end - start;7206for (j = 0; (unsigned int) j < len; j++)7207putchar(start[j]);7208putchar('\n');7209found = 1;7210if (end >= buf_end)7211break;7212start = end + 1;7213}7214free(new_buf);7215if (!found)7216printf(" No strings found in this section.");7217putchar('\n');7218}7219}72207221static void7222load_sections(struct readelf *re)7223{7224struct section *s;7225const char *name;7226Elf_Scn *scn;7227GElf_Shdr sh;7228size_t shstrndx, ndx;7229int elferr;72307231/* Allocate storage for internal section list. */7232if (!elf_getshnum(re->elf, &re->shnum)) {7233warnx("elf_getshnum failed: %s", elf_errmsg(-1));7234return;7235}7236if (re->sl != NULL)7237free(re->sl);7238if ((re->sl = calloc(re->shnum, sizeof(*re->sl))) == NULL)7239err(EXIT_FAILURE, "calloc failed");72407241/* Get the index of .shstrtab section. */7242if (!elf_getshstrndx(re->elf, &shstrndx)) {7243warnx("elf_getshstrndx failed: %s", elf_errmsg(-1));7244return;7245}72467247if ((scn = elf_getscn(re->elf, 0)) == NULL)7248return;72497250(void) elf_errno();7251do {7252if (gelf_getshdr(scn, &sh) == NULL) {7253warnx("gelf_getshdr failed: %s", elf_errmsg(-1));7254(void) elf_errno();7255continue;7256}7257if ((name = elf_strptr(re->elf, shstrndx, sh.sh_name)) == NULL) {7258(void) elf_errno();7259name = "<no-name>";7260}7261if ((ndx = elf_ndxscn(scn)) == SHN_UNDEF) {7262if ((elferr = elf_errno()) != 0) {7263warnx("elf_ndxscn failed: %s",7264elf_errmsg(elferr));7265continue;7266}7267}7268if (ndx >= re->shnum) {7269warnx("section index of '%s' out of range", name);7270continue;7271}7272if (sh.sh_link >= re->shnum)7273warnx("section link %llu of '%s' out of range",7274(unsigned long long)sh.sh_link, name);7275s = &re->sl[ndx];7276s->name = name;7277s->scn = scn;7278s->off = sh.sh_offset;7279s->sz = sh.sh_size;7280s->entsize = sh.sh_entsize;7281s->align = sh.sh_addralign;7282s->type = sh.sh_type;7283s->flags = sh.sh_flags;7284s->addr = sh.sh_addr;7285s->link = sh.sh_link;7286s->info = sh.sh_info;7287} while ((scn = elf_nextscn(re->elf, scn)) != NULL);7288elferr = elf_errno();7289if (elferr != 0)7290warnx("elf_nextscn failed: %s", elf_errmsg(elferr));7291}72927293static void7294unload_sections(struct readelf *re)7295{72967297if (re->sl != NULL) {7298free(re->sl);7299re->sl = NULL;7300}7301re->shnum = 0;7302re->vd_s = NULL;7303re->vn_s = NULL;7304re->vs_s = NULL;7305re->vs = NULL;7306re->vs_sz = 0;7307if (re->ver != NULL) {7308free(re->ver);7309re->ver = NULL;7310re->ver_sz = 0;7311}7312}73137314static bool7315dump_elf(struct readelf *re)7316{73177318/* Fetch ELF header. No need to continue if it fails. */7319if (gelf_getehdr(re->elf, &re->ehdr) == NULL) {7320warnx("gelf_getehdr failed: %s", elf_errmsg(-1));7321return (false);7322}7323if ((re->ec = gelf_getclass(re->elf)) == ELFCLASSNONE) {7324warnx("gelf_getclass failed: %s", elf_errmsg(-1));7325return (false);7326}7327if (re->ehdr.e_ident[EI_DATA] == ELFDATA2MSB) {7328re->dw_read = _read_msb;7329re->dw_decode = _decode_msb;7330} else {7331re->dw_read = _read_lsb;7332re->dw_decode = _decode_lsb;7333}73347335if (re->options & ~RE_H)7336load_sections(re);7337if ((re->options & RE_VV) || (re->options & RE_S))7338search_ver(re);7339if (re->options & RE_H)7340dump_ehdr(re);7341if (re->options & RE_L)7342dump_phdr(re);7343if (re->options & RE_SS)7344dump_shdr(re);7345if (re->options & RE_G)7346dump_section_groups(re);7347if (re->options & RE_D)7348dump_dynamic(re);7349if (re->options & RE_R)7350dump_reloc(re);7351if (re->options & RE_S)7352dump_symtabs(re);7353if (re->options & RE_N)7354dump_notes(re);7355if (re->options & RE_II)7356dump_hash(re);7357if (re->options & RE_X)7358hex_dump(re);7359if (re->options & RE_P)7360str_dump(re);7361if (re->options & RE_VV)7362dump_ver(re);7363if (re->options & RE_AA)7364dump_arch_specific_info(re);7365if (re->options & RE_W)7366dump_dwarf(re);7367if (re->options & ~RE_H)7368unload_sections(re);7369return (true);7370}73717372static void7373dump_dwarf(struct readelf *re)7374{7375Dwarf_Error de;7376int error;73777378if (dwarf_elf_init(re->elf, DW_DLC_READ, NULL, NULL, &re->dbg, &de)) {7379if ((error = dwarf_errno(de)) != DW_DLE_DEBUG_INFO_NULL)7380errx(EXIT_FAILURE, "dwarf_elf_init failed: %s",7381dwarf_errmsg(de));7382return;7383}73847385if (re->dop & DW_A)7386dump_dwarf_abbrev(re);7387if (re->dop & DW_L)7388dump_dwarf_line(re);7389if (re->dop & DW_LL)7390dump_dwarf_line_decoded(re);7391if (re->dop & DW_I) {7392dump_dwarf_info(re, 0);7393dump_dwarf_info(re, 1);7394}7395if (re->dop & DW_P)7396dump_dwarf_pubnames(re);7397if (re->dop & DW_R)7398dump_dwarf_aranges(re);7399if (re->dop & DW_RR)7400dump_dwarf_ranges(re);7401if (re->dop & DW_M)7402dump_dwarf_macinfo(re);7403if (re->dop & DW_F)7404dump_dwarf_frame(re, 0);7405else if (re->dop & DW_FF)7406dump_dwarf_frame(re, 1);7407if (re->dop & DW_S)7408dump_dwarf_str(re);7409if (re->dop & DW_O)7410dump_dwarf_loclist(re);74117412dwarf_finish(re->dbg, &de);7413}74147415static bool7416dump_ar(struct readelf *re, int fd)7417{7418Elf_Arsym *arsym;7419Elf_Arhdr *arhdr;7420Elf_Cmd cmd;7421Elf *e;7422size_t sz;7423off_t off;7424int i;74257426re->ar = re->elf;74277428if (re->options & RE_C) {7429if ((arsym = elf_getarsym(re->ar, &sz)) == NULL) {7430warnx("elf_getarsym() failed: %s", elf_errmsg(-1));7431goto process_members;7432}7433printf("Index of archive %s: (%ju entries)\n", re->filename,7434(uintmax_t) sz - 1);7435off = 0;7436for (i = 0; (size_t) i < sz; i++) {7437if (arsym[i].as_name == NULL)7438break;7439if (arsym[i].as_off != off) {7440off = arsym[i].as_off;7441if (elf_rand(re->ar, off) != off) {7442warnx("elf_rand() failed: %s",7443elf_errmsg(-1));7444continue;7445}7446if ((e = elf_begin(fd, ELF_C_READ, re->ar)) ==7447NULL) {7448warnx("elf_begin() failed: %s",7449elf_errmsg(-1));7450continue;7451}7452if ((arhdr = elf_getarhdr(e)) == NULL) {7453warnx("elf_getarhdr() failed: %s",7454elf_errmsg(-1));7455elf_end(e);7456continue;7457}7458printf("Binary %s(%s) contains:\n",7459re->filename, arhdr->ar_name);7460elf_end(e);7461}7462printf("\t%s\n", arsym[i].as_name);7463}7464if (elf_rand(re->ar, SARMAG) != SARMAG) {7465warnx("elf_rand() failed: %s", elf_errmsg(-1));7466return (false);7467}7468}74697470process_members:74717472if ((re->options & ~RE_C) == 0)7473return (true);74747475cmd = ELF_C_READ;7476while ((re->elf = elf_begin(fd, cmd, re->ar)) != NULL) {7477if ((arhdr = elf_getarhdr(re->elf)) == NULL) {7478warnx("elf_getarhdr() failed: %s", elf_errmsg(-1));7479goto next_member;7480}7481if (strcmp(arhdr->ar_name, "/") == 0 ||7482strcmp(arhdr->ar_name, "//") == 0 ||7483strcmp(arhdr->ar_name, "__.SYMDEF") == 0)7484goto next_member;7485printf("\nFile: %s(%s)\n", re->filename, arhdr->ar_name);7486dump_elf(re);74877488next_member:7489cmd = elf_next(re->elf);7490elf_end(re->elf);7491}7492re->elf = re->ar;7493return (true);7494}74957496static bool7497dump_object(struct readelf *re, int fd)7498{7499bool rv = false;75007501if ((re->flags & DISPLAY_FILENAME) != 0)7502printf("\nFile: %s\n", re->filename);75037504if ((re->elf = elf_begin(fd, ELF_C_READ, NULL)) == NULL) {7505warnx("elf_begin() failed: %s", elf_errmsg(-1));7506goto done;7507}75087509switch (elf_kind(re->elf)) {7510case ELF_K_NONE:7511warnx("Not an ELF file.");7512goto done;7513case ELF_K_ELF:7514rv = dump_elf(re);7515break;7516case ELF_K_AR:7517rv = dump_ar(re, fd);7518break;7519default:7520warnx("Internal: libelf returned unknown elf kind.");7521}75227523done:7524elf_end(re->elf);7525return (rv);7526}75277528static void7529add_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t)7530{7531struct dumpop *d;75327533if ((d = find_dumpop(re, si, sn, -1, t)) == NULL) {7534if ((d = calloc(1, sizeof(*d))) == NULL)7535err(EXIT_FAILURE, "calloc failed");7536if (t == DUMP_BY_INDEX)7537d->u.si = si;7538else7539d->u.sn = sn;7540d->type = t;7541d->op = op;7542STAILQ_INSERT_TAIL(&re->v_dumpop, d, dumpop_list);7543} else7544d->op |= op;7545}75467547static struct dumpop *7548find_dumpop(struct readelf *re, size_t si, const char *sn, int op, int t)7549{7550struct dumpop *d;75517552STAILQ_FOREACH(d, &re->v_dumpop, dumpop_list) {7553if ((op == -1 || op & d->op) &&7554(t == -1 || (unsigned) t == d->type)) {7555if ((d->type == DUMP_BY_INDEX && d->u.si == si) ||7556(d->type == DUMP_BY_NAME && !strcmp(d->u.sn, sn)))7557return (d);7558}7559}75607561return (NULL);7562}75637564static struct {7565const char *ln;7566char sn;7567int value;7568} dwarf_op[] = {7569{"rawline", 'l', DW_L},7570{"decodedline", 'L', DW_LL},7571{"info", 'i', DW_I},7572{"abbrev", 'a', DW_A},7573{"pubnames", 'p', DW_P},7574{"aranges", 'r', DW_R},7575{"ranges", 'r', DW_R},7576{"Ranges", 'R', DW_RR},7577{"macro", 'm', DW_M},7578{"frames", 'f', DW_F},7579{"frames-interp", 'F', DW_FF},7580{"str", 's', DW_S},7581{"loc", 'o', DW_O},7582{NULL, 0, 0}7583};75847585static void7586parse_dwarf_op_short(struct readelf *re, const char *op)7587{7588int i;75897590if (op == NULL) {7591re->dop |= DW_DEFAULT_OPTIONS;7592return;7593}75947595for (; *op != '\0'; op++) {7596for (i = 0; dwarf_op[i].ln != NULL; i++) {7597if (dwarf_op[i].sn == *op) {7598re->dop |= dwarf_op[i].value;7599break;7600}7601}7602}7603}76047605static void7606parse_dwarf_op_long(struct readelf *re, const char *op)7607{7608char *p, *token, *bp;7609int i;76107611if (op == NULL) {7612re->dop |= DW_DEFAULT_OPTIONS;7613return;7614}76157616if ((p = strdup(op)) == NULL)7617err(EXIT_FAILURE, "strdup failed");7618bp = p;76197620while ((token = strsep(&p, ",")) != NULL) {7621for (i = 0; dwarf_op[i].ln != NULL; i++) {7622if (!strcmp(token, dwarf_op[i].ln)) {7623re->dop |= dwarf_op[i].value;7624break;7625}7626}7627}76287629free(bp);7630}76317632static uint64_t7633_read_lsb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read)7634{7635uint64_t ret;7636uint8_t *src;76377638src = (uint8_t *) d->d_buf + *offsetp;76397640ret = 0;7641switch (bytes_to_read) {7642case 8:7643ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;7644ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;7645/* FALLTHROUGH */7646case 4:7647ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;7648/* FALLTHROUGH */7649case 2:7650ret |= ((uint64_t) src[1]) << 8;7651/* FALLTHROUGH */7652case 1:7653ret |= src[0];7654break;7655default:7656return (0);7657}76587659*offsetp += bytes_to_read;76607661return (ret);7662}76637664static uint64_t7665_read_msb(Elf_Data *d, uint64_t *offsetp, int bytes_to_read)7666{7667uint64_t ret;7668uint8_t *src;76697670src = (uint8_t *) d->d_buf + *offsetp;76717672switch (bytes_to_read) {7673case 1:7674ret = src[0];7675break;7676case 2:7677ret = src[1] | ((uint64_t) src[0]) << 8;7678break;7679case 4:7680ret = src[3] | ((uint64_t) src[2]) << 8;7681ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;7682break;7683case 8:7684ret = src[7] | ((uint64_t) src[6]) << 8;7685ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;7686ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;7687ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;7688break;7689default:7690return (0);7691}76927693*offsetp += bytes_to_read;76947695return (ret);7696}76977698static uint64_t7699_decode_lsb(uint8_t **data, int bytes_to_read)7700{7701uint64_t ret;7702uint8_t *src;77037704src = *data;77057706ret = 0;7707switch (bytes_to_read) {7708case 8:7709ret |= ((uint64_t) src[4]) << 32 | ((uint64_t) src[5]) << 40;7710ret |= ((uint64_t) src[6]) << 48 | ((uint64_t) src[7]) << 56;7711/* FALLTHROUGH */7712case 4:7713ret |= ((uint64_t) src[2]) << 16 | ((uint64_t) src[3]) << 24;7714/* FALLTHROUGH */7715case 2:7716ret |= ((uint64_t) src[1]) << 8;7717/* FALLTHROUGH */7718case 1:7719ret |= src[0];7720break;7721default:7722return (0);7723}77247725*data += bytes_to_read;77267727return (ret);7728}77297730static uint64_t7731_decode_msb(uint8_t **data, int bytes_to_read)7732{7733uint64_t ret;7734uint8_t *src;77357736src = *data;77377738ret = 0;7739switch (bytes_to_read) {7740case 1:7741ret = src[0];7742break;7743case 2:7744ret = src[1] | ((uint64_t) src[0]) << 8;7745break;7746case 4:7747ret = src[3] | ((uint64_t) src[2]) << 8;7748ret |= ((uint64_t) src[1]) << 16 | ((uint64_t) src[0]) << 24;7749break;7750case 8:7751ret = src[7] | ((uint64_t) src[6]) << 8;7752ret |= ((uint64_t) src[5]) << 16 | ((uint64_t) src[4]) << 24;7753ret |= ((uint64_t) src[3]) << 32 | ((uint64_t) src[2]) << 40;7754ret |= ((uint64_t) src[1]) << 48 | ((uint64_t) src[0]) << 56;7755break;7756default:7757return (0);7758break;7759}77607761*data += bytes_to_read;77627763return (ret);7764}77657766static int64_t7767_decode_sleb128(uint8_t **dp, uint8_t *dpe)7768{7769int64_t ret = 0;7770uint8_t b = 0;7771int shift = 0;77727773uint8_t *src = *dp;77747775do {7776if (src >= dpe)7777break;7778b = *src++;7779ret |= ((b & 0x7f) << shift);7780shift += 7;7781} while ((b & 0x80) != 0);77827783if (shift < 32 && (b & 0x40) != 0)7784ret |= (-1 << shift);77857786*dp = src;77877788return (ret);7789}77907791static uint64_t7792_decode_uleb128(uint8_t **dp, uint8_t *dpe)7793{7794uint64_t ret = 0;7795uint8_t b;7796int shift = 0;77977798uint8_t *src = *dp;77997800do {7801if (src >= dpe)7802break;7803b = *src++;7804ret |= ((b & 0x7f) << shift);7805shift += 7;7806} while ((b & 0x80) != 0);78077808*dp = src;78097810return (ret);7811}78127813static void7814readelf_version(void)7815{7816(void) printf("%s (%s)\n", ELFTC_GETPROGNAME(),7817elftc_version());7818exit(EXIT_SUCCESS);7819}78207821#define USAGE_MESSAGE "\7822Usage: %s [options] file...\n\7823Display information about ELF objects and ar(1) archives.\n\n\7824Options:\n\7825-a | --all Equivalent to specifying options '-dhIlrsASV'.\n\7826-c | --archive-index Print the archive symbol table for archives.\n\7827-d | --dynamic Print the contents of SHT_DYNAMIC sections.\n\7828-e | --headers Print all headers in the object.\n\7829-g | --section-groups Print the contents of the section groups.\n\7830-h | --file-header Print the file header for the object.\n\7831-l | --program-headers Print the PHDR table for the object.\n\7832-n | --notes Print the contents of SHT_NOTE sections.\n\7833-p INDEX | --string-dump=INDEX\n\7834Print the contents of section at index INDEX.\n\7835-r | --relocs Print relocation information.\n\7836-s | --syms | --symbols Print symbol tables.\n\7837-t | --section-details Print additional information about sections.\n\7838-v | --version Print a version identifier and exit.\n\7839-w[afilmoprsFLR] | --debug-dump={abbrev,aranges,decodedline,frames,\n\7840frames-interp,info,loc,macro,pubnames,\n\7841ranges,Ranges,rawline,str}\n\7842Display DWARF information.\n\7843-x INDEX | --hex-dump=INDEX\n\7844Display contents of a section as hexadecimal.\n\7845-z | --decompress Decompress the contents of a section before displaying it.\n\7846-A | --arch-specific (accepted, but ignored)\n\7847-D | --use-dynamic Print the symbol table specified by the DT_SYMTAB\n\7848entry in the \".dynamic\" section.\n\7849-H | --help Print a help message.\n\7850-I | --histogram Print information on bucket list lengths for \n\7851hash sections.\n\7852-N | --full-section-name (accepted, but ignored)\n\7853-S | --sections | --section-headers\n\7854Print information about section headers.\n\7855-V | --version-info Print symbol versoning information.\n\7856-W | --wide Print information without wrapping long lines.\n"785778587859static void7860readelf_usage(int status)7861{7862fprintf(stderr, USAGE_MESSAGE, ELFTC_GETPROGNAME());7863exit(status);7864}78657866int7867main(int argc, char **argv)7868{7869cap_rights_t rights;7870fileargs_t *fa;7871struct readelf *re, re_storage;7872unsigned long si;7873int fd, opt, i, exit_code;7874char *ep;78757876re = &re_storage;7877memset(re, 0, sizeof(*re));7878STAILQ_INIT(&re->v_dumpop);78797880while ((opt = getopt_long(argc, argv, "AacDdegHhIi:lNnp:rSstuVvWw::x:z",7881longopts, NULL)) != -1) {7882switch(opt) {7883case '?':7884readelf_usage(EXIT_SUCCESS);7885break;7886case 'A':7887re->options |= RE_AA;7888break;7889case 'a':7890re->options |= RE_AA | RE_D | RE_G | RE_H | RE_II |7891RE_L | RE_N | RE_R | RE_SS | RE_S | RE_U | RE_VV;7892break;7893case 'c':7894re->options |= RE_C;7895break;7896case 'D':7897re->options |= RE_DD;7898break;7899case 'd':7900re->options |= RE_D;7901break;7902case 'e':7903re->options |= RE_H | RE_L | RE_SS;7904break;7905case 'g':7906re->options |= RE_G;7907break;7908case 'H':7909readelf_usage(EXIT_SUCCESS);7910break;7911case 'h':7912re->options |= RE_H;7913break;7914case 'I':7915re->options |= RE_II;7916break;7917case 'i':7918/* Not implemented yet. */7919break;7920case 'l':7921re->options |= RE_L;7922break;7923case 'N':7924re->options |= RE_NN;7925break;7926case 'n':7927re->options |= RE_N;7928break;7929case 'p':7930re->options |= RE_P;7931si = strtoul(optarg, &ep, 10);7932if (*ep == '\0')7933add_dumpop(re, (size_t) si, NULL, STR_DUMP,7934DUMP_BY_INDEX);7935else7936add_dumpop(re, 0, optarg, STR_DUMP,7937DUMP_BY_NAME);7938break;7939case 'r':7940re->options |= RE_R;7941break;7942case 'S':7943re->options |= RE_SS;7944break;7945case 's':7946re->options |= RE_S;7947break;7948case 't':7949re->options |= RE_SS | RE_T;7950break;7951case 'u':7952re->options |= RE_U;7953break;7954case 'V':7955re->options |= RE_VV;7956break;7957case 'v':7958readelf_version();7959break;7960case 'W':7961re->options |= RE_WW;7962break;7963case 'w':7964re->options |= RE_W;7965parse_dwarf_op_short(re, optarg);7966break;7967case 'x':7968re->options |= RE_X;7969si = strtoul(optarg, &ep, 10);7970if (*ep == '\0')7971add_dumpop(re, (size_t) si, NULL, HEX_DUMP,7972DUMP_BY_INDEX);7973else7974add_dumpop(re, 0, optarg, HEX_DUMP,7975DUMP_BY_NAME);7976break;7977case 'z':7978re->options |= RE_Z;7979break;7980case OPTION_DEBUG_DUMP:7981re->options |= RE_W;7982parse_dwarf_op_long(re, optarg);7983}7984}79857986argv += optind;7987argc -= optind;79887989if (argc == 0 || re->options == 0)7990readelf_usage(EXIT_FAILURE);79917992if (argc > 1)7993re->flags |= DISPLAY_FILENAME;79947995if (elf_version(EV_CURRENT) == EV_NONE)7996errx(EXIT_FAILURE, "ELF library initialization failed: %s",7997elf_errmsg(-1));79987999cap_rights_init(&rights, CAP_FCNTL, CAP_FSTAT, CAP_MMAP_R, CAP_SEEK);8000fa = fileargs_init(argc, argv, O_RDONLY, 0, &rights, FA_OPEN);8001if (fa == NULL)8002err(1, "Unable to initialize casper fileargs");80038004caph_cache_catpages();8005if (caph_limit_stdio() < 0) {8006fileargs_free(fa);8007err(1, "Unable to limit stdio rights");8008}8009if (caph_enter_casper() < 0) {8010fileargs_free(fa);8011err(1, "Unable to enter capability mode");8012}80138014exit_code = EXIT_SUCCESS;8015for (i = 0; i < argc; i++) {8016re->filename = argv[i];8017fd = fileargs_open(fa, re->filename);8018if (fd < 0) {8019warn("open %s failed", re->filename);8020exit_code = EXIT_FAILURE;8021} else {8022if (!dump_object(re, fd))8023exit_code = EXIT_FAILURE;8024close(fd);8025}8026}80278028exit(exit_code);8029}803080318032