diff options
author | Nick Clifton <nickc@redhat.com> | 1998-06-11 21:51:56 +0000 |
---|---|---|
committer | Nick Clifton <nickc@redhat.com> | 1998-06-11 21:51:56 +0000 |
commit | 764668738f19680b3b4aed04fd30a13d4368b88a (patch) | |
tree | 13cbc236bf27c53461c3a8af518d4e1ca3a8ece7 /binutils/readelf.c | |
parent | e2a15d35a88dcfc200f8d46c807b6f8287f94a6b (diff) | |
download | gdb-764668738f19680b3b4aed04fd30a13d4368b88a.zip gdb-764668738f19680b3b4aed04fd30a13d4368b88a.tar.gz gdb-764668738f19680b3b4aed04fd30a13d4368b88a.tar.bz2 |
Add 'readelf' to binutils.
Diffstat (limited to 'binutils/readelf.c')
-rw-r--r-- | binutils/readelf.c | 2254 |
1 files changed, 2254 insertions, 0 deletions
diff --git a/binutils/readelf.c b/binutils/readelf.c new file mode 100644 index 0000000..ee2f079 --- /dev/null +++ b/binutils/readelf.c @@ -0,0 +1,2254 @@ +/* readelf.c -- display contents of an ELF format file + Copyright (C) 1998 Free Software Foundation, Inc. + + Originally developed by Eric Youngdale <eric@andante.jic.com> + Modifications by Nick Clifton <nickc@cygnus.com> + + This file is part of GNU Binutils. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + 02111-1307, USA. */ + + +#include <assert.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <stdlib.h> + +#include <stdio.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/mman.h> +#include <errno.h> + +#include "readelf.h" +#include "getopt.h" +#include "bucomm.h" + +#ifdef ANSI_PROTOTYPES +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +unsigned int dynamic_addr; +unsigned int dynamic_size; +char * pint = ""; +char * program_name = "readelf"; + +int dynamic_info [DT_JMPREL + 1]; +int version_info [16]; + +int must_swap = 0; + +unsigned int rel_size; +int loadaddr = -1; + +unsigned int rela_addr; +unsigned int rela_size; +char * strtab; +int symtab_index; +int lastmapped; +char * header; + +Elf_Dyn * dpnt; +Elf_Rel * rpnt; +Elf_Shdr * elf_sections; +Elf_Ehdr * epnt; +Elf_Sym * symtab; + +int show_name; +int do_dynamic; +int do_syms; +int do_reloc; +int do_section; +int do_load; +int do_using_dynamic; +int do_header; +int do_dump; +int do_version; +long int expected_endian; + +char * dyntype[] = +{ + "NULL", "NEEDED","PLTRELSZ","PLTGOT","HASH","STRTAB","SYMTAB","RELA", + "RELASZ","RELAENT","STRSZ","SYMENT","INIT","FINI","SONAME","RPATH", + "SYMBOLIC","REL","RELSZ","RELENT","PLTREL","DEBUG","TEXTREL","JMPREL" +}; + +char * vertype[] = +{ + "VERNEEDNUM", "VERNEED", "VERDEFNUM", "VERDEF", + "", "", "", "", "", "", "", "", "", "", "", "VERSYM" +}; + +char * filtertype[] = +{ + "FILTER", "USED", "AUXILIARY" +}; + + +char * sttinfo[] = {"NOTYPE","OBJECT","FUNC","SECTION","FILE"}; +char * stbinfo[] = {"LOCAL","GLOBAL","WEAK"}; + +#define SECTION_NAME(X) (& header [lastmapped + (X)->sh_name]) + +#define NUM_DUMP_SECTS 100 +char dump_sects [NUM_DUMP_SECTS]; +#define HEX_DUMP 1 +#define DISASS_DUMP 2 + +/* Forward declarations for dumb compilers. */ +static char * get_i386_rel_type PARAMS ((bfd_vma rtype)); +static char * get_m68k_rel_type PARAMS ((bfd_vma rtype)); +static char * get_sparc_rel_type PARAMS ((bfd_vma rtype)); +static char * get_m32r_rel_type PARAMS ((bfd_vma rtype)); +static char * get_v850_rel_type PARAMS ((bfd_vma rtype)); +static char * get_d10v_rel_type PARAMS ((bfd_vma rtype)); +static char * get_d30v_rel_type PARAMS ((bfd_vma rtype)); +static char * get_sh_rel_type PARAMS ((bfd_vma rtype)); +static char * get_mn10300_rel_type PARAMS ((bfd_vma rtype)); +static char * get_mn10200_rel_type PARAMS ((bfd_vma rtype)); +static void dump_relocations PARAMS ((Elf_Rel * rpnt, int rel_size)); +static char * get_file_type PARAMS ((unsigned short e_type)); +static char * get_machine_name PARAMS ((unsigned short e_machine)); +static char * get_segment_type PARAMS ((unsigned long p_type)); +static char * get_section_type_name PARAMS ((unsigned int sh_type)); +static void usage PARAMS ((void)); +static void parse_args PARAMS ((int argc, char ** argv)); +static int process_elf_header PARAMS ((void)); +static void process_program_headers PARAMS ((void)); +static void process_section_headers PARAMS ((void)); +static void process_dynamic_segment PARAMS ((void)); +static void process_symbol_table PARAMS ((void)); +static void process_section_contents PARAMS ((void)); +static void process_file PARAMS ((char * file_name)); + + +#define SWAP2(val) ( (((val) << 8) & (0xff << 8)) \ + | (((val) >> 8) & (0xff << 0))) + +#define SWAP4(val) ( (((val) << 24) & (0xff << 24)) \ + | (((val) << 8) & (0xff << 16)) \ + | (((val) >> 8) & (0xff << 8)) \ + | (((val) >> 24) & (0xff << 0))) + +/* Warning: This macro assumes 8 bits in a char. */ +#define BYTE_SWAP(pointer, field) \ + if (sizeof ((pointer)->field) == 2) \ + { \ + unsigned short val = (pointer)->field ; \ + new_header->field = SWAP2 (val); \ + } \ + else if (sizeof ((pointer)->field) != 4) \ + abort (); \ + else \ + { \ + unsigned long val = (pointer)->field ; \ + new_header->field = SWAP4 (val); \ + } + + +#ifdef ANSI_PROTOTYPES +static void +error (const char * message, ...) +{ + va_list args; + + fprintf (stderr, _("%s: Error: "), program_name); + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + return; +} + +static void +warn (const char * message, ...) +{ + va_list args; + + fprintf (stderr, _("%s: Warning: "), program_name); + va_start (args, message); + vfprintf (stderr, message, args); + va_end (args); + return; +} +#else +static void +error (va_alist) +{ + char * message; + va_list args; + + fprintf (stderr, _("%s: Error: "), program_name); + va_start (args); + message = va_arg (args, char *); + vfprintf (stderr, message, args); + va_end (args); + return; +} + +static void +warn (va_alist) + va_dcl; +{ + char * message; + va_list args; + + fprintf (stderr, _("%s: Warning: "), program_name); + va_start (args); + message = va_arg (args, char *); + vfprintf (stderr, message, args); + va_end (args); + return; +} +#endif + + +static char * +get_i386_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_386_NONE"; + case 1: return "R_386_32"; + case 2: return "R_386_PC32"; + case 3: return "R_386_GOT32"; + case 4: return "R_386_PLT32"; + case 5: return "R_386_COPY"; + case 6: return "R_386_GLOB_DAT"; + case 7: return "R_386_JMP_SLOT"; + case 8: return "R_386_RELATIVE"; + case 9: return "R_386_GOTOFF"; + case 10: return "R_386_GOTPC"; + case 20: return "R_386_16"; + case 21: return "R_386_PC16"; + case 22: return "R_386_PC8"; + case 23: return "R_386_max"; + default: return _("*INVALID*"); + } +} + +static char * +get_m68k_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_68K_NONE"; + case 1: return "R_68K_32"; + case 2: return "R_68K_16"; + case 3: return "R_68K_8"; + case 4: return "R_68K_PC32"; + case 5: return "R_68K_PC16"; + case 6: return "R_68K_PC8"; + case 7: return "R_68K_GOT32"; + case 8: return "R_68K_GOT16"; + case 9: return "R_68K_GOT8"; + case 10: return "R_68K_GOT32O"; + case 11: return "R_68K_GOT16O"; + case 12: return "R_68K_GOT8O"; + case 13: return "R_68K_PLT32"; + case 14: return "R_68K_PLT16"; + case 15: return "R_68K_PLT8"; + case 16: return "R_68K_PLT32O"; + case 17: return "R_68K_PLT16O"; + case 18: return "R_68K_PLT8O"; + case 19: return "R_68K_COPY"; + case 20: return "R_68K_GLOB_DAT"; + case 21: return "R_68K_JMP_SLOT"; + case 22: return "R_68K_RELATIVE"; + default: return _("*INVALID*"); + } +} + + +static char * +get_sparc_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_SPARC_NONE"; + case 1: return "R_SPARC_8"; + case 2: return "R_SPARC_16"; + case 3: return "R_SPARC_32"; + case 4: return "R_SPARC_DISP8"; + case 5: return "R_SPARC_DISP16"; + case 6: return "R_SPARC_DISP32"; + case 7: return "R_SPARC_WDISP30"; + case 8: return "R_SPARC_WDISP22"; + case 9: return "R_SPARC_HI22"; + case 10: return "R_SPARC_22"; + case 11: return "R_SPARC_13"; + case 12: return "R_SPARC_LO10"; + case 13: return "R_SPARC_GOT10"; + case 14: return "R_SPARC_GOT13"; + case 15: return "R_SPARC_GOT22"; + case 16: return "R_SPARC_PC10"; + case 17: return "R_SPARC_PC22"; + case 18: return "R_SPARC_WPLT30"; + case 19: return "R_SPARC_COPY"; + case 20: return "R_SPARC_GLOB_DAT"; + case 21: return "R_SPARC_JMP_SLOT"; + case 22: return "R_SPARC_RELATIVE"; + case 23: return "R_SPARC_UA32"; + case 24: return "R_SPARC_10"; + case 25: return "R_SPARC_11"; + case 26: return "R_SPARC_64"; + case 27: return "R_SPARC_OLO10"; + case 28: return "R_SPARC_HH22"; + case 29: return "R_SPARC_HM10"; + case 30: return "R_SPARC_LM22"; + case 31: return "R_SPARC_PC_HH22"; + case 32: return "R_SPARC_PC_HM10"; + case 33: return "R_SPARC_PC_LM22"; + case 34: return "R_SPARC_WDISP16"; + case 35: return "R_SPARC_WDISP19"; + case 36: return "R_SPARC_UNUSED_42"; + case 37: return "R_SPARC_7"; + case 38: return "R_SPARC_5"; + case 39: return "R_SPARC_6"; + case 40: return "R_SPARC_DISP64"; + case 41: return "R_SPARC_PLT64"; + case 42: return "R_SPARC_HIX22"; + case 43: return "R_SPARC_LOX10"; + case 44: return "R_SPARC_H44"; + case 45: return "R_SPARC_M44"; + case 46: return "R_SPARC_L44"; + case 47: return "R_SPARC_REGISTER"; + case 48: return "R_SPARC_UA64"; + case 49: return "R_SPARC_UA16"; + case 50: return "R_SPARC_32LE"; + default: return _("*INVALID*"); + } +} + + +static char * +get_m32r_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_M32R_NONE"; + case 1: return "R_M32R_16"; + case 2: return "R_M32R_32"; + case 3: return "R_M32R_24"; + case 4: return "R_M32R_10_PCREL"; + case 5: return "R_M32R_18_PCREL"; + case 6: return "R_M32R_26_PCREL"; + case 7: return "R_M32R_HI16_ULO"; + case 8: return "R_M32R_HI16_SLO"; + case 9: return "R_M32R_LO16"; + case 10: return "R_M32R_SDA16"; + default: return _("*INVALID*"); + } +} + + +static char * +get_v850_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_V850_NONE"; + case 1: return "R_V850_9_PCREL"; + case 2: return "R_V850_22_PCREL"; + case 3: return "R_V850_HI16_S"; + case 4: return "R_V850_HI16"; + case 5: return "R_V850_LO16"; + case 6: return "R_V850_32"; + case 7: return "R_V850_16"; + case 8: return "R_V850_8"; + case 9: return "R_V850_SDA_16_16_OFFSET"; + case 10: return "R_V850_SDA_15_16_OFFSET"; + case 11: return "R_V850_ZDA_16_16_OFFSET"; + case 12: return "R_V850_ZDA_15_16_OFFSET"; + case 13: return "R_V850_TDA_6_8_OFFSET"; + case 14: return "R_V850_TDA_7_8_OFFSET"; + case 15: return "R_V850_TDA_7_7_OFFSET"; + case 16: return "R_V850_TDA_16_16_OFFSET"; +/* start-sanitize-v850e */ + case 17: return "R_V850_TDA_4_5_OFFSET"; + case 18: return "R_V850_TDA_4_4_OFFSET"; + case 19: return "R_V850_SDA_16_16_SPLIT_OFFSET"; + case 20: return "R_V850_ZDA_16_16_SPLIT_OFFSET"; + case 21: return "R_V850_CALLT_6_7_OFFSET"; + case 22: return "R_V850_CALLT_16_16_OFFSET"; +/* end-sanitize-v850e */ + default: return _("*INVALID*"); + } +} + + +static char * +get_d10v_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_D10V_NONE"; + case 1: return "R_D10V_10_PCREL_R"; + case 2: return "R_D10V_10_PCREL_L"; + case 3: return "R_D10V_16"; + case 4: return "R_D10V_18"; + case 5: return "R_D10V_18_PCREL"; + case 6: return "R_D10V_32"; + default: return _("*INVALID*"); + } +} + + +static char * +get_d30v_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_D30V_NONE"; + case 1: return "R_D30V_6"; + case 2: return "R_D30V_9_PCREL"; + case 3: return "R_D30V_9_PCREL_R"; + case 4: return "R_D30V_15"; + case 5: return "R_D30V_15_PCREL"; + case 6: return "R_D30V_15_PCREL_R"; + case 7: return "R_D30V_21"; + case 8: return "R_D30V_21_PCREL"; + case 9: return "R_D30V_21_PCREL_R"; + case 10: return "R_D30V_32"; + case 11: return "R_D30V_32_PCREL"; + case 12: return "R_D30V_32_NORMAL"; + default: return _("*INVALID*"); + } +} + + +static char * +get_sh_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_SH_NONE"; + case 1: return "R_SH_DIR32"; + case 2: return "R_SH_REL32"; + case 3: return "R_SH_DIR8WPN"; + case 4: return "R_SH_IND12W"; + case 5: return "R_SH_DIR8WPL"; + case 6: return "R_SH_DIR8WPZ"; + case 7: return "R_SH_DIR8BP"; + case 8: return "R_SH_DIR8W"; + case 9: return "R_SH_DIR8L"; + case 25: return "R_SH_SWITCH16"; + case 26: return "R_SH_SWITCH32"; + case 27: return "R_SH_USES"; + case 28: return "R_SH_COUNT"; + case 29: return "R_SH_ALIGN"; + case 30: return "R_SH_CODE"; + case 31: return "R_SH_DATA"; + case 32: return "R_SH_LABEL"; + default: return _("*INVALID*"); + } +} + + +static char * +get_mn10300_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_MN10300_NONE"; + case 1: return "R_MN10300_32"; + case 2: return "R_MN10300_16"; + case 3: return "R_MN10300_8"; + case 4: return "R_MN10300_PCREL32"; + case 5: return "R_MN10300_PCREL16"; + case 6: return "R_MN10300_PCREL8"; + default: return _("*INVALID*"); + } +} + + +static char * +get_mn10200_rel_type (rtype) + bfd_vma rtype; +{ + switch (rtype) + { + case 0: return "R_MN10200_NONE"; + case 1: return "R_MN10200_32"; + case 2: return "R_MN10200_16"; + case 3: return "R_MN10200_8"; + case 4: return "R_MN10200_24"; + case 5: return "R_MN10200_PCREL8"; + case 6: return "R_MN10200_PCREL16"; + case 7: return "R_MN10200_PCREL24"; + default: return _("*INVALID*"); + } +} + + +static void +dump_relocations (rpnt, rel_size) + Elf_Rel * rpnt; + int rel_size; +{ + int i; + int is_rela; + Elf_Rela * rapnt; + Elf_Rela * relocs = NULL; + + + rapnt = (Elf_Rela *) rpnt; + + /* Compute number of relocations. */ + switch (epnt->e_machine) + { + case EM_386: + case EM_486: + case EM_CYGNUS_M32R: + case EM_CYGNUS_D10V: + rel_size = rel_size / sizeof (Elf_Rel); + + if (must_swap) + { + Elf_Rel * new_header = malloc (sizeof (* new_header) * rel_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, rpnt, sizeof (* new_header) * rel_size); + + rpnt = new_header; + relocs = (Elf_Rela *) new_header; + + for (i = 0; i < rel_size; i++) + { + BYTE_SWAP (rpnt + i, r_offset); + BYTE_SWAP (rpnt + i, r_info); + + new_header ++; + } + } + + is_rela = 0; + break; + + case EM_68K: + case EM_SPARC: + case EM_CYGNUS_V850: + case EM_CYGNUS_D30V: + case EM_CYGNUS_MN10200: + case EM_CYGNUS_MN10300: + case EM_SH: + rel_size = rel_size / sizeof (Elf_Rela); + + if (must_swap) + { + Elf_Rela * new_header = malloc (sizeof (* new_header) * rel_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, rpnt, sizeof (* new_header) * rel_size); + + relocs = rapnt = new_header; + + for (i = rel_size; i--;) + { + BYTE_SWAP (new_header, r_offset); + BYTE_SWAP (new_header, r_info); + BYTE_SWAP (new_header, r_addend); + + new_header ++; + } + } + + is_rela = 1; + break; + + default: + warn (_("Don't know about relocations on this machine architecture\n")); + return; + } + + if (is_rela) + printf (_(" Offset Value Type Symbol's Value Symbol Name Addend\n")); + else + printf (_(" Offset Value Type Symbol's Value Symbol Name\n")); + + for (i = 0; i < rel_size; i++) + { + char * rtype; + + if (is_rela) + rpnt = (Elf_Rel *) rapnt; + + printf (" %5.5x %5.5x ", rpnt->r_offset, rpnt->r_info); + + switch (epnt->e_machine) + { + case EM_CYGNUS_M32R: + rtype = get_m32r_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_386: + case EM_486: + rtype = get_i386_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_68K: + rtype = get_m68k_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_SPARC: + rtype = get_sparc_rel_type (ELF32_R_TYPE (rapnt->r_info)); + break; + + case EM_CYGNUS_V850: + rtype = get_v850_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_D10V: + rtype = get_d10v_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_D30V: + rtype = get_d30v_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_SH: + rtype = get_sh_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_MN10300: + rtype = get_mn10300_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + + case EM_CYGNUS_MN10200: + rtype = get_mn10200_rel_type (ELF32_R_TYPE (rpnt->r_info)); + break; + } + + printf ("%-18s", rtype); + + symtab_index = ELF32_R_SYM (rpnt->r_info); + + if (symtab_index) + { + Elf_Sym ssym; + Elf_Sym * psym; + + psym = symtab + symtab_index; + + if (must_swap) + { + Elf_Sym * new_header = & ssym; + + ssym = * psym; + + BYTE_SWAP (psym, st_name); + BYTE_SWAP (psym, st_value); + /* BYTE_SWAP (psym, st_size); */ + BYTE_SWAP (psym, st_shndx); + + psym = new_header; + } + + if (psym->st_name == 0) + printf (" %08x %-15s", psym->st_value, + SECTION_NAME (elf_sections + psym->st_shndx)); + else + printf (" %08x %-15s", psym->st_value, strtab + psym->st_name); + + if (is_rela) + printf (" + %x", rapnt->r_addend); + } + + putchar ('\n'); + rapnt ++; + rpnt ++; + } + + if (relocs != NULL) + free (relocs); +} + +static char * +get_file_type (e_type) + unsigned short e_type; +{ + static char buff [32]; + + switch (e_type) + { + case ET_NONE: return _("None"); + case ET_REL: return _("Relocatable file"); + case ET_EXEC: return _("Executable file"); + case ET_DYN: return _("Shared object file"); + case ET_CORE: return _("Core file"); + + default: + if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC)) + sprintf (buff, _("Processor Specific: (%x)"), e_type); + else + sprintf (buff, _("<unknown>: %x"), e_type); + return buff; + } +} + +static char * +get_machine_name (e_machine) + unsigned short e_machine; +{ + static char buff [32]; + + switch (e_machine) + { + case EM_NONE: return _("None"); + case EM_M32: return "WE32100"; + case EM_SPARC: return "Sparc"; + case EM_386: return "80386"; + case EM_68K: return "MC68000"; + case EM_88K: return "MC88000"; + case EM_486: return "Intel 80486"; + case EM_860: return "Intel 80860"; + case EM_MIPS: return "MIPS R3000 big-endian"; + case EM_S370: return "Amdahl"; + case EM_MIPS_RS4_BE: return "MIPS R400 big-endian"; + case EM_PARISC: return "HPPA"; + case EM_SPARC32PLUS: return "Sparc v8+" ; + case EM_PPC: return "Power PCC"; + case EM_SPARCV9: return "Sparc v9"; + case EM_ARM: return "ARM"; + case EM_SH: return "Hitachi SH"; + case EM_ALPHA: return "Alpha"; + case EM_CYGNUS_D10V: return "d10v"; + case EM_CYGNUS_D30V: return "d30v"; + case EM_CYGNUS_M32R: return "M32r"; + case EM_CYGNUS_V850: return "v850"; + case EM_CYGNUS_MN10300: return "mn10300"; + case EM_CYGNUS_MN10200: return "mn10200"; + + default: + sprintf (buff, _("<unknown>: %x"), e_machine); + return buff; + } +} + +static char * +get_segment_type (p_type) + unsigned long p_type; +{ + static char buff [32]; + + switch (p_type) + { + case PT_NULL: return _("Unused"); + case PT_LOAD: return _("Loadable"); + case PT_DYNAMIC: return _("Dynamic link info"); + case PT_INTERP: return _("Interpreter"); + case PT_NOTE: return _("Auxillary Info"); + case PT_SHLIB: return _("Shared Library"); + case PT_PHDR: return _("Program Headers"); + + default: + if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) + return _("processor specific"); + else + { + sprintf (buff, _("<unknown>: %x"), p_type); + return buff; + } + } +} + +static char * +get_section_type_name (sh_type) + unsigned int sh_type; +{ + static char buff [32]; + + switch (sh_type) + { + case SHT_NULL: return _("Unused"); + case SHT_PROGBITS: return _("Program data"); + case SHT_SYMTAB: return _("Symbol table"); + case SHT_STRTAB: return _("String table"); + case SHT_RELA: return _("Relocs, addends"); + case SHT_HASH: return _("Symbol hash table"); + case SHT_DYNAMIC: return _("Dynamic linking info"); + case SHT_NOTE: return _("Notes"); + case SHT_NOBITS: return _("Space, no data"); + case SHT_REL: return _("Relocs, no addends"); + case SHT_SHLIB: return _("Shared Library info"); + case SHT_DYNSYM: return _("Dynamic linker symbols"); + case SHT_GNU_verdef: return _("Version definition"); + case SHT_GNU_verneed: return _("Version needs"); + case SHT_GNU_versym: return _("Version symbols"); + case 0x6ffffff0: return "VERSYM"; + case 0x6ffffffc: return "VERDEF"; + case 0x7ffffffd: return "AUXILIARY"; + case 0x7fffffff: return "FILTER"; + + default: + if ((sh_type >= SHT_LOPROC) && (sh_type <= SHT_HIPROC)) + return _("processor specific"); + else if ((sh_type >= SHT_LOUSER) && (sh_type <= SHT_HIUSER)) + return _("application specific"); + else + { + sprintf (buff, _("<unknown>: %x"), sh_type); + return buff; + } + } +} + +struct option options [] = +{ + {"all", no_argument, 0, 'a'}, + {"file-header", no_argument, 0, 'h'}, + {"program-headers", no_argument, 0, 'l'}, + {"segments", no_argument, 0, 'l'}, + {"sections", no_argument, 0, 'S'}, + {"symbols", no_argument, 0, 's'}, + {"relocs", no_argument, 0, 'r'}, + {"dynamic", no_argument, 0, 'd'}, + {"version-info", no_argument, 0, 'V'}, + {"use-dynamic", no_argument, 0, 'D'}, + + {"hex-dump", required_argument, 0, 'x'}, +#ifdef SUPPORT_DISASSEMBLY + {"instruction-dump", required_argument, 0, 'i'}, +#endif + + {"version", no_argument, 0, 'v'}, + {"help", no_argument, 0, 'H'}, + + {0, no_argument, 0, 0} +}; + +static void +usage () +{ + fprintf (stderr, _("Usage: readelf {options} elf-file(s)\n")); + fprintf (stderr, _(" Options are:\n")); + fprintf (stderr, _(" -a or --all Display all the information\n")); + fprintf (stderr, _(" -h or --file-header Display the ELF file header\n")); + fprintf (stderr, _(" -l or --program-headers or --segments\n")); + fprintf (stderr, _(" Display the program headers\n")); + fprintf (stderr, _(" -S or --sections Display the sections' headers\n")); + fprintf (stderr, _(" -s or --symbols Display the symbol table\n")); + fprintf (stderr, _(" -r or --relocs Display the relocations (if present)\n")); + fprintf (stderr, _(" -d or --dynamic Display the dynamic section (if present)\n")); + fprintf (stderr, _(" -V or --version-info Display the version sections (if present)\n")); + fprintf (stderr, _(" -D or --use-dynamic Use the dynamic section info when displaying symbols\n")); + fprintf (stderr, _(" -x <number> or --hex-dump=<number>\n")); + fprintf (stderr, _(" Dump the contents of section <number>\n")); +#ifdef SUPPORT_DISASSEMBLY + fprintf (stderr, _(" -i <number> or --instruction-dump=<number>\n")); + fprintf (stderr, _(" Disassemble the contents of section <number>\n")); +#endif + fprintf (stderr, _(" -v or --version Display the version number of readelf\n")); + fprintf (stderr, _(" -H or --help Display this information\n")); + + exit (0); +} + +static void +parse_args (argc, argv) + int argc; + char ** argv; +{ + char c; + + if (argc < 2) + usage (); + + while ((c = getopt_long + (argc, argv, "rsahldSDx:i:vV", options, NULL)) != EOF) + { + char * cp; + int section; + + switch (c) + { + case 'H': + usage (); + break; + + case 'a': + do_syms++; + do_reloc++; + do_dynamic++; + do_header++; + do_section++; + do_load++; + do_version++; + break; + case 'D': + do_using_dynamic++; + break; + case 'r': + do_reloc++; + break; + case 'h': + do_header++; + break; + case 'l': + do_load++; + break; + case 's': + do_syms++; + break; + case 'S': + do_section++; + break; + case 'd': + do_dynamic++; + break; + case 'x': + do_dump ++; + section = strtoul (optarg, & cp, 0); + if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) + { + dump_sects [section] |= HEX_DUMP; + break; + } + goto oops; +#ifdef SUPPORT_DISASSEMBLY + case 'i': + do_dump ++; + section = strtoul (optarg, & cp, 0); + if (! * cp && section >= 0 && section < NUM_DUMP_SECTS) + { + dump_sects [section] |= DISASS_DUMP; + break; + } + goto oops; +#endif + case 'v': + print_version (program_name); + break; + case 'V': + do_version ++; + break; + default: + oops: + /* xgettext:c-format */ + error (_("Invalid option '-%c'\n"), c); + /* Drop through. */ + case '?': + usage (); + } + } + + if (!do_dynamic && !do_syms && !do_reloc && !do_section + && !do_load && !do_header && !do_dump && !do_version) + usage (); + else if (argc < 3) + warn (_("Nothing to do.\n")); +} + +static int +process_elf_header () +{ + if ( epnt->e_ident [EI_MAG0] != ELFMAG0 + || epnt->e_ident [EI_MAG1] != ELFMAG1 + || epnt->e_ident [EI_MAG2] != ELFMAG2 + || epnt->e_ident [EI_MAG3] != ELFMAG3) + { + error (_("Not an ELF file - it has the wrong magic bytes at the start\n")); + return 0; + } + + if (epnt->e_ident [EI_CLASS] != ELFCLASS32) + { + error (_("Not a 32 bit ELF file\n")); + return 0; + } + + if (epnt->e_ident [EI_DATA] != expected_endian) + must_swap = 1; + + if (must_swap) + { + Elf_Ehdr * new_header = malloc (sizeof (* new_header)); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return 0; + } + + memcpy (new_header, epnt, sizeof (* new_header)); + + BYTE_SWAP (epnt, e_type); + BYTE_SWAP (epnt, e_machine); + BYTE_SWAP (epnt, e_version); + BYTE_SWAP (epnt, e_entry); + BYTE_SWAP (epnt, e_phoff); + BYTE_SWAP (epnt, e_shoff); + BYTE_SWAP (epnt, e_flags); + BYTE_SWAP (epnt, e_ehsize); + BYTE_SWAP (epnt, e_phentsize); + BYTE_SWAP (epnt, e_phnum); + BYTE_SWAP (epnt, e_shentsize); + BYTE_SWAP (epnt, e_shnum); + BYTE_SWAP (epnt, e_shstrndx); + + epnt = new_header; + } + + if (do_header) + { + int i; + + printf (_("ELF Header....\n")); + printf (_(" Magic: ")); + for (i = 0; i < EI_NIDENT; i ++) + printf ("%2.2x ", epnt->e_ident [i]); + printf ("\n"); + printf (_(" Type: %s\n"), get_file_type (epnt->e_type)); + printf (_(" Machine: %s\n"), get_machine_name (epnt->e_machine)); + printf (_(" Version: %x\n"), epnt->e_version); + printf (_(" Entry point address: %x\n"), epnt->e_entry); + printf (_(" Start of program headers: %d (bytes into file)\n"), epnt->e_phoff); + printf (_(" Start of section headers: %d (bytes into file)\n"), epnt->e_shoff); + printf (_(" Flags: %x\n"), epnt->e_flags); + printf (_(" Size of this header: %d (bytes)\n"), epnt->e_ehsize); + printf (_(" Size of program headers: %d (bytes)\n"), epnt->e_phentsize); + printf (_(" Number of program headers: %d\n"), epnt->e_phnum); + printf (_(" Size of section headers: %d (bytes)\n"), epnt->e_shentsize); + printf (_(" Number of section headers: %d\n"), epnt->e_shnum); + printf (_(" Section header string table index: %d\n"), epnt->e_shstrndx); + } + + return 1; +} + + +static void +process_program_headers () +{ + Elf_Phdr * elf_segments; + Elf_Phdr * ppnt; + int i; + + if (epnt->e_phnum == 0) + { + if (do_load) + printf (_("\nThere are no program headers in this file\n")); + return; + } + + if (do_load && !do_header) + { + printf (_("\nElf file is %s\n"), get_file_type (epnt->e_type)); + printf (_("Entry point 0x%x\n"), epnt->e_entry); + printf (_("There are %d program headers, starting at offset %x:\n"), + epnt->e_phnum, epnt->e_phoff); + } + + if (must_swap) + { + Elf_Phdr * new_header = malloc (sizeof (* new_header) * epnt->e_phnum); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [epnt->e_phoff], + sizeof (* new_header) * epnt->e_phnum); + + elf_segments = ppnt = new_header; + + for (i = 0; i < epnt->e_phnum; i++) + { + BYTE_SWAP (ppnt + i, p_type); + BYTE_SWAP (ppnt + i, p_flags); + BYTE_SWAP (ppnt + i, p_offset); + BYTE_SWAP (ppnt + i, p_vaddr); + BYTE_SWAP (ppnt + i, p_paddr); + BYTE_SWAP (ppnt + i, p_filesz); + BYTE_SWAP (ppnt + i, p_memsz); + BYTE_SWAP (ppnt + i, p_align); + + new_header ++; + } + } + else + { + ppnt = (Elf_Phdr *) & header [epnt->e_phoff]; + elf_segments = NULL; + } + + if (do_load) + { + printf (_("\nProgram Header%s....\n"), epnt->e_phnum > 1 ? "s" : ""); + printf (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + } + + loadaddr = -1; + dynamic_addr = 0; + + for (i = 0; i < epnt->e_phnum; i++) + { + if (loadaddr == -1 && ppnt->p_type == PT_LOAD) + loadaddr = (ppnt->p_vaddr & 0xfffff000) + - (ppnt->p_offset & 0xfffff000); + + if (do_load) + { + printf (" %-10s ", get_segment_type (ppnt->p_type)); + printf ("0x%5.5x ",ppnt->p_offset); + printf ("0x%8.8x ",ppnt->p_vaddr); + printf ("0x%8.8x ",ppnt->p_paddr); + printf ("0x%5.5x 0x%5.5x ",ppnt->p_filesz, ppnt->p_memsz); + printf ("%c%c%c ", + (ppnt->p_flags & 4 ? 'R' : ' '), + (ppnt->p_flags & 2 ? 'W' : ' '), + (ppnt->p_flags & 1 ? 'E' : ' ')); + printf ("%#x", ppnt->p_align); + } + + if (ppnt->p_type == PT_DYNAMIC) + { + if (dynamic_addr) + error (_("more than one dynamic section\n")); + + dynamic_addr = ppnt->p_offset; + dynamic_size = ppnt->p_filesz; + } + + if (ppnt->p_type == PT_INTERP) + { + if (do_load) + printf (_("\nRequesting program interpreter [%s]"), + & header [ppnt->p_offset]); + pint = strdup (& header [ppnt->p_offset]); + } + + if (do_load) + putc ('\n', stdout); + + ppnt ++; + } + + if (do_load) + { + printf (_("\n Section to Segment mapping:\n")); + printf (_(" Segment Sections...\n")); + + if (elf_segments) + ppnt = elf_segments; + else + ppnt = (Elf_Phdr *) & header [epnt->e_phoff]; + + for (i = 0; i < epnt->e_phnum; i++, ppnt++) + { + int j; + Elf_Shdr * spnt; + + printf (" %2.2d ", i); + + spnt = (Elf_Shdr *) & header [epnt->e_shoff]; + + if (must_swap) + { + lastmapped = SWAP4 (spnt[epnt->e_shstrndx].sh_offset); + + for (j = 0; j < epnt->e_shnum; j++) + { + bfd_vma addr; + bfd_size_type size; + unsigned int name; + + addr = SWAP4 (spnt[j].sh_addr); + size = SWAP4 (spnt[j].sh_size); + name = SWAP4 (spnt[j].sh_name); + + if (size > 0 + && (addr >= ppnt->p_vaddr) + && (addr + size) <= (ppnt->p_vaddr + ppnt->p_memsz)) + printf ("%s ", header + lastmapped + name); + } + } + else + { + lastmapped = spnt[epnt->e_shstrndx].sh_offset; + + for (j = 0; j < epnt->e_shnum; j++, spnt++) + { + if (spnt->sh_size > 0 + && (spnt->sh_addr >= ppnt->p_vaddr) + && (spnt->sh_addr + spnt->sh_size) + <= (ppnt->p_vaddr + ppnt->p_memsz)) + printf ("%s ", SECTION_NAME (spnt)); + } + } + + putc ('\n',stdout); + } + } + + if (elf_segments) + free (elf_segments); +} + + +static void +process_section_headers () +{ + Elf_Shdr * spnt; + int i; + + if (must_swap) + { + Elf_Shdr * new_header = malloc (sizeof (* new_header) * epnt->e_shnum); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [epnt->e_shoff], + sizeof (* new_header) * epnt->e_shnum); + + elf_sections = spnt = new_header; + + for (i = 0; i < epnt->e_shnum; i++) + { + BYTE_SWAP (spnt + i, sh_name); + BYTE_SWAP (spnt + i, sh_type); + BYTE_SWAP (spnt + i, sh_flags); + BYTE_SWAP (spnt + i, sh_addr); + BYTE_SWAP (spnt + i, sh_offset); + BYTE_SWAP (spnt + i, sh_size); + BYTE_SWAP (spnt + i, sh_link); + BYTE_SWAP (spnt + i, sh_info); + BYTE_SWAP (spnt + i, sh_addralign); + BYTE_SWAP (spnt + i, sh_entsize); + + new_header ++; + } + } + else + { + elf_sections = spnt = (Elf_Shdr *) & header [epnt->e_shoff]; + } + + spnt += epnt->e_shstrndx; + lastmapped = spnt->sh_offset; + spnt = elf_sections; + + if (! do_section || (epnt->e_shnum == 0)) + return; + + if (! do_header) + printf (_("There are %d section headers, starting at offset %x:\n"), + epnt->e_shnum, epnt->e_shoff); + + printf (_("\nSection Header%s....\n"), epnt->e_shnum > 1 ? "s" : ""); + printf (_(" [Nr] Name Type Addr Off Size ES Flg Lk In Al\n")); + + for (i = 0; i < epnt->e_shnum; i++) + { + printf (" [%2d] %-14s", i, SECTION_NAME (spnt)); + + printf (" %-18s ",get_section_type_name (spnt->sh_type)); + printf ( "%8.8x %6.6x %6.6x %2.2x", + spnt->sh_addr, + spnt->sh_offset, + spnt->sh_size, + spnt->sh_entsize); + + printf (" %c%c%c %2d %2x %d \n", + (spnt->sh_flags & 1 ? 'W' : ' '), + (spnt->sh_flags & 2 ? 'A' : ' '), + (spnt->sh_flags & 4 ? 'X' : ' '), + spnt->sh_link, + spnt->sh_info, + spnt->sh_addralign); + spnt ++; + } +} + +/* Parse the dynamic segment */ +static void +process_dynamic_segment () +{ + Elf_Dyn * elf_dynamic; + unsigned int i; + + dynamic_size = dynamic_size / sizeof (Elf_Dyn); + + if (must_swap) + { + Elf_Dyn * new_header = malloc (sizeof (* new_header) * dynamic_size); + + if (new_header == NULL) + { + error (_("out of memory\n")); + return; + } + + memcpy (new_header, & header [dynamic_addr], + sizeof (* new_header) * dynamic_size); + + elf_dynamic = dpnt = new_header; + + for (i = 0; i < dynamic_size; i++) + { + BYTE_SWAP (dpnt + i, d_tag); + BYTE_SWAP (dpnt + i, d_un.d_ptr); + + new_header ++; + } + } + else + { + dpnt = (Elf_Dyn *) & header [dynamic_addr]; + elf_dynamic = NULL; + } + + /* Find symtab. */ + for (i = 0; i < dynamic_size; ++i, ++dpnt) + if (dpnt->d_tag == DT_SYMTAB) + { + dynamic_info [DT_SYMTAB] = dpnt->d_un.d_val; + symtab = (Elf_Sym *) (header - loadaddr + + dynamic_info[DT_SYMTAB]); + } + else if (dpnt->d_tag == DT_STRTAB) + { + dynamic_info [DT_STRTAB] = dpnt->d_un.d_val; + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + } + + if (do_dynamic && dynamic_addr) + { + printf (_("\n Dynamic section data: %x, %d entries\n"), + dynamic_addr, dynamic_size ); + } + + for (i = 0; i < dynamic_size; i++) + { + if (do_dynamic) + printf (_(" Tag: %#10x: "), dpnt->d_tag); + + switch (dpnt->d_tag) + { + case DT_AUXILIARY: + case DT_FILTER: + if (do_dynamic) + { + printf ("(%-11s)", filtertype [DT_FILTER - dpnt->d_tag]); + + if (dynamic_info [DT_STRTAB]) + { + if (dpnt->d_tag == DT_AUXILIARY) + printf (_("Auxiliary library")); + else + printf (_("Filter library")); + + printf (": [%s]\n", (dpnt->d_un.d_val + strtab)); + } + else + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + break; + + case DT_NULL : + case DT_NEEDED : + case DT_PLTRELSZ: + case DT_PLTGOT : + case DT_HASH : + case DT_STRTAB : + case DT_SYMTAB : + case DT_RELA : + case DT_RELASZ : + case DT_RELAENT : + case DT_STRSZ : + case DT_SYMENT : + case DT_INIT : + case DT_FINI : + case DT_SONAME : + case DT_RPATH : + case DT_SYMBOLIC: + case DT_REL : + case DT_RELSZ : + case DT_RELENT : + case DT_PLTREL : + case DT_DEBUG : + case DT_TEXTREL : + case DT_JMPREL : + dynamic_info [dpnt->d_tag] = dpnt->d_un.d_val; + + if (do_dynamic) + { + printf ("(%-11s)", dyntype [dpnt->d_tag]); + + if (dynamic_info [DT_STRTAB]) + { + switch (dpnt->d_tag) + { + case DT_NEEDED: + printf (_("Shared library: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + + if (strcmp (dpnt->d_un.d_val + strtab, pint)) + printf ("\n"); + else + printf (_(" program interpreter\n")); + break; + + case DT_SONAME: + printf (_("Library soname: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + break; + + case DT_RPATH: + printf (_("Library rpath: [%s]\n"), + (dpnt->d_un.d_val + strtab)); + break; + + default: + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + } + else + printf (_("Value %x\n"), dpnt->d_un.d_val); + } + break; + + default: + if ((dpnt->d_tag >= DT_VERSYM) && (dpnt->d_tag <= DT_VERNEEDNUM)) + { + version_info [DT_VERSIONTAGIDX (dpnt->d_tag)] = dpnt->d_un.d_val; + + if (do_dynamic) + printf (_("(%-11s) Value %#x\n"), + vertype [DT_VERSIONTAGIDX (dpnt->d_tag)], + dpnt->d_un.d_ptr); + } + else + warn (_("<Invalid> Value %#x\n"), dpnt->d_un.d_ptr); + break; + } + + dpnt ++; + } + + if (do_reloc) + { + if (do_using_dynamic) + { + if (dynamic_info [DT_REL]) + { + rpnt = (Elf_Rel *) (header + dynamic_info [DT_REL] - loadaddr); + rel_size = dynamic_info [DT_RELSZ]; + if (rel_size) + { + printf (_("\nRelocation section data: %x %x\n"), + dynamic_info[DT_REL], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + + if (dynamic_info[DT_RELA]) + { + rpnt = (Elf_Rel *) (header + dynamic_info[DT_RELA] - loadaddr); + rel_size = dynamic_info[DT_RELASZ]; + if (rel_size) + { + printf (_("\nRelocation section data: %x %x\n"), + dynamic_info[DT_RELA], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + + if (dynamic_info[DT_JMPREL]) + { + rpnt = (Elf_Rel *) (header + dynamic_info[DT_JMPREL] + - loadaddr); + rel_size = dynamic_info[DT_PLTRELSZ]; + if (rel_size) + { + printf (_("\nJumptable Relocation section data: %x %x\n"), + dynamic_info[DT_JMPREL], rel_size); + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + } + else + { + Elf_Shdr * spnt; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + Elf_Shdr * symsec; + + + if (spnt->sh_type != SHT_RELA && spnt->sh_type != SHT_REL) + continue; + + rpnt = (Elf_Rel *) (header + spnt->sh_offset); + + rel_size = spnt->sh_size; + + if (rel_size) + { + printf (_("\nRelocation section data: %s (%#x entries)\n"), + SECTION_NAME (spnt), rel_size / spnt->sh_entsize); + + symsec = & elf_sections [spnt->sh_link]; + symtab = (Elf_Sym *) (header + symsec->sh_offset); + strtab = (char *) (header + + elf_sections [symsec->sh_link].sh_offset); + + dump_relocations (rpnt, rel_size); + } + else + printf (_("\nNo Relocations in this file\n")); + } + } + } + + if (elf_dynamic) + free (elf_dynamic); +} + +/* Dump the symbol table */ +static void +process_symbol_table () +{ + char * pnt; + int i; + Elf_Shdr * spnt; + + if (! do_syms) + return; + + if (dynamic_info [DT_HASH] && do_using_dynamic) + { + int nbucket; + int nchain; + int * elf_buckets; + int * chains; + int hn; + int si; + int * hash_addr; + + hash_addr = (int *) (dynamic_info [DT_HASH] + header - loadaddr); + + nbucket = *hash_addr++; + nchain = *hash_addr++; + elf_buckets = hash_addr; + hash_addr += nbucket; + chains = hash_addr; + + printf (_("\n Symbol table for image\n")); + printf (_(" Num Buc: Value Size Type Bind Ot Ndx Name\n")); + + for (hn = 0; hn < nbucket; hn++) + { + if (! elf_buckets [hn]) + continue; + + for (si = elf_buckets[hn]; si; si = chains[si]) + { + pnt = strtab + symtab[si].st_name; + + printf ("%3d %3d: %8x %5d %6s %6s %2d ", si, hn, + symtab[si].st_value, + symtab[si].st_size, + sttinfo [ELF_ST_TYPE (symtab[si].st_info)], + stbinfo [ELF_ST_BIND (symtab[si].st_info)], + symtab[si].st_other); + + if (symtab[si].st_shndx == 0) + printf ("UND"); + else if ((symtab[si].st_shndx & 0xffff) == 0xfff1) + printf ("ABS"); + else if ((symtab[si].st_shndx & 0xffff) == 0xfff2) + printf ("COM"); + else + printf ("%3d", symtab[si].st_shndx); + printf (" %s\n", pnt); + } + } + } + else if (!do_using_dynamic) + { + int i; + unsigned short * vers_addr; + + spnt = elf_sections; + vers_addr = (short *) (version_info [DT_VERNEEDNUM - DT_VERSYM] + + header - loadaddr); + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + unsigned int si; + + if (spnt->sh_type != SHT_SYMTAB && spnt->sh_type != SHT_DYNSYM) + continue; + + printf (_("\nSymbol data for: %s\n"), SECTION_NAME (spnt)); + printf (_(" Num: Value Size Type Bind Ot Ndx Name\n")); + + symtab = (Elf_Sym *) (header + spnt->sh_offset); + strtab = (char *) (header + elf_sections [spnt->sh_link].sh_offset); + + for (si = 0; si < spnt->sh_size / spnt->sh_entsize; si++) + { + Elf_Sym ssym; + Elf_Sym * psym; + Elf_Sym * new_header; + + psym = symtab + si; + + if (must_swap) + { + ssym = * psym; + + new_header = & ssym; + + BYTE_SWAP (psym, st_name); + BYTE_SWAP (psym, st_value); + BYTE_SWAP (psym, st_size); + BYTE_SWAP (psym, st_shndx); + + psym = new_header; + } + + pnt = strtab + psym->st_name; + + printf (" %3d: %8x %5d %-7s %-6s %2d ", si, + psym->st_value, + psym->st_size, + sttinfo [ELF_ST_TYPE (psym->st_info)], + stbinfo [ELF_ST_BIND (psym->st_info)], + psym->st_other); + + if (psym->st_shndx == 0) + printf ("UND"); + else if ((psym->st_shndx & 0xffff) == 0xfff1) + printf ("ABS"); + else if ((psym->st_shndx & 0xffff) == 0xfff2) + printf ("COM"); + else + printf ("%3d", psym->st_shndx); + printf (" %s", pnt); + + if (spnt->sh_type == SHT_DYNSYM && + version_info [DT_VERSIONTAGIDX (DT_VERSYM)] != 0 && + ((vers_addr[si] & 0x8000) || vers_addr[si] > 1)) + { + Elf_Vernaux * a; + + if (elf_sections [psym->st_shndx].sh_type == SHT_NOBITS + || psym->st_shndx == SHN_UNDEF) + { + Elf_Verneed * v; + + /* We must test both. */ + v = (Elf_Verneed *) + (version_info [DT_VERSIONTAGIDX (DT_VERNEED)] + + header - loadaddr); + + for (;;) + { + a = (Elf_Vernaux *)((char *)v + v->vn_aux); + + while (a->vna_other != vers_addr[si] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *)a + a->vna_next); + + if (a->vna_other == vers_addr[si]) + break; + + if (v->vn_next == 0) + { + if (elf_sections [psym->st_shndx].sh_type + != SHT_NOBITS) + error (_("bad dynamic symbol")); + + a = NULL; + break; + } + + v = (Elf_Verneed *)((char *)v + v->vn_next); + } + + if (a != NULL) + printf ("@%s (%d)", strtab + a->vna_name, a->vna_other); + } + else if ((elf_sections [psym->st_shndx].sh_type + == SHT_NOBITS && a == NULL) + || psym->st_shndx != SHN_UNDEF) + { + Elf_Verdef * v; + Elf_Verdaux * b; + + v = (Elf_Verdef *) + (version_info [DT_VERSIONTAGIDX (DT_VERDEF)] + + header - loadaddr); + + if (vers_addr[si] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (vers_addr [si] & 0x7fff)) + v = (Elf_Verdef *)((char *)v + v->vd_next); + + b = (Elf_Verdaux *) ((char *)v + v->vd_aux); + + if (psym->st_name != b->vda_name) + pnt = strtab + b->vda_name; + else + pnt = NULL; + } + + if (pnt) + printf ((vers_addr [si] & 0x8000) + ? "@%s" : "@@%s", pnt); + } + } + + puts (""); + } + } + } + + if (! do_version) + return; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + if (spnt->sh_type == SHT_GNU_verdef) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + unsigned int idx; + unsigned int cnt; + + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + + printf (_("\n Version definitions:%s (%#0x entries)\n"), + SECTION_NAME(spnt), spnt->sh_info); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME(dspnt)); + + for (idx = cnt = 0; cnt < spnt->sh_info; ++cnt) + { + Elf_Verdef * ent = (Elf_Verdef *) + ((char *) header + spnt->sh_offset + idx); + Elf_Verdaux * aux = (Elf_Verdaux *) + ((char *) ent + ent->vd_aux); + int j, isum; + + printf (_("%#06x: Rev: %d Flags: "), idx, ent->vd_version); + + if (ent->vd_flags == 0) + printf (_("none")); + else + { + int f = 1; + if (ent->vd_flags & 0x1) + { + printf (_("BASE")); + f = 0; + } + if (ent->vd_flags & 0x2) + { + printf (_("%sWEAK"), f ? "" : "|"); + f = 0; + } + } + printf (_(" Index: %d Cnt: %d Name: %s\n"), + ent->vd_ndx, ent->vd_cnt, strtab + aux->vda_name); + j = 1; + isum = idx + ent->vd_aux; + while (j < ent->vd_cnt) + { + isum += aux->vda_next; + aux = (Elf_Verdaux *)((char *)aux + aux->vda_next); + printf (_(" %#06x: Parent %d: %s\n"), isum, j, + strtab + aux->vda_name); + ++j; + } + + idx += ent->vd_next; + } + } + + if (spnt->sh_type == SHT_GNU_verneed) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + unsigned int idx; + unsigned int cnt; + + strtab = (char *) (header - loadaddr + dynamic_info[DT_STRTAB]); + printf (_("\n Needed versions:%s (%#0x entries)\n"), + SECTION_NAME (spnt), spnt->sh_info); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME (dspnt)); + + for (idx = cnt = 0; cnt < spnt->sh_info; ++cnt) + { + Elf_Verneed * ent = (Elf_Verneed *) + ((char *) header + spnt->sh_offset + idx); + Elf_Vernaux * aux = (Elf_Vernaux *) + ((char *) ent + ent->vn_aux); + int j, isum; + + printf (_("%#06x: Version: %d File: %s Cnt: %d\n"), + idx, ent->vn_version, strtab + ent->vn_file,ent->vn_cnt); + + for (j = 0, isum = idx + ent->vn_aux; j < ent->vn_cnt; ++j) + { + printf (_(" %#06x: Name: %s Flags: %s Version: %d\n"), + isum, strtab+aux->vna_name, + aux->vna_flags & 0x2 ? "WEAK" : "none", + aux->vna_other); + isum += aux->vna_next; + aux = (Elf_Vernaux *)((char *) aux + aux->vna_next); + } + + idx += ent->vn_next; + } + } + + if (spnt->sh_type == SHT_GNU_versym) + { + Elf_Shdr * dspnt = &elf_sections[spnt->sh_link]; + int total = spnt->sh_size / spnt->sh_entsize; + int cnt; + unsigned short * p = (short *) + (version_info[DT_VERNEEDNUM - DT_VERSYM] + header - loadaddr); + + symtab = (Elf_Sym *) (header + dspnt->sh_offset); + strtab = (char *) (header + elf_sections[dspnt->sh_link].sh_offset); + + printf (_("\n Version symbols:%s (%#0x entries)\n"), + SECTION_NAME (spnt), total); + printf (_("Addr: %#08x Offset: %#08x Link: %x (%s)\n"), + spnt->sh_addr, spnt->sh_offset, spnt->sh_link, + SECTION_NAME (dspnt)); + + for (cnt = 0; cnt < total; cnt += 4) + { + int j, nn; + + printf ("%#08x:", cnt); + + for (j = 0; (j < 4) && (cnt + j) < total; ++j) + switch (p[cnt + j]) + { + case 0: + printf (" 0 (*local*) "); + break; + case 1: + printf (" 1 (*global*) "); + break; + default: + nn = printf ("%4x%c", p[cnt + j] & 0x7fff, + p[cnt + j] & 0x8000 ? 'h' : ' '); + if (elf_sections[symtab[cnt + j].st_shndx].sh_type + == SHT_NOBITS) + { + /* We must test both. */ + Elf_Verneed * v = (Elf_Verneed *) + (version_info [DT_VERNEEDNUM - DT_VERNEED] + + header - loadaddr); + Elf_Vernaux * a = NULL; + + for (;;) + { + a = (Elf_Vernaux *)((char *) v + v->vn_aux); + + while (a->vna_other != p[cnt + j] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *) a + a->vna_next); + + if (a->vna_other == p[cnt + j]) + break; + + if (v->vn_next == 0) + { + a = NULL; + break; + } + + v = (Elf_Verneed *)((char *)v + v->vn_next); + } + + if (a != NULL) + nn += printf ("(%s)", strtab + a->vna_name); + else + { + Elf_Verdef * v = (Elf_Verdef *) + (version_info [DT_VERNEEDNUM - DT_VERDEF] + + header - loadaddr); + Elf_Verdaux * a; + + if (p[cnt + j] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (p[cnt + j]&0x7fff)) + v = (Elf_Verdef *)((char *)v + v->vd_next); + + a = (Elf_Verdaux *) ((char *) v + v->vd_aux); + pnt = strtab + a->vda_name; + } + + if (pnt) + nn += printf ("(%s)", pnt); + } + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + else if (symtab[cnt + j].st_shndx ==SHN_UNDEF) + { + Elf_Verneed * v = (Elf_Verneed *) + (version_info [DT_VERNEEDNUM - DT_VERNEED] + + header - loadaddr); + Elf_Vernaux * a; + + for (;;) + { + a = (Elf_Vernaux *)((char *) v + v->vn_aux); + + while (a->vna_other != p[cnt + j] + && a->vna_next != 0) + a = (Elf_Vernaux *)((char *)a + a->vna_next); + + if (a->vna_other == p[cnt + j]) + break; + + v = (Elf_Verneed *)((char *) v + v->vn_next); + } + + nn += printf ("(%s)", strtab + a->vna_name); + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + else + { + Elf_Verdef * v = (Elf_Verdef *) + (version_info [DT_VERNEEDNUM - DT_VERDEF] + + header - loadaddr); + Elf_Verdaux * a; + + if (p[cnt + j] == 0x8001) + pnt = ""; + else + { + while (v->vd_ndx != (p[cnt + j] & 0x7fff)) + v = (Elf_Verdef *)((char *) v + v->vd_next); + + a = (Elf_Verdaux *) ((char *) v + v->vd_aux); + pnt = strtab + a->vda_name; + } + + if (pnt) + nn += printf ("(%s)", pnt); + + if (nn <16) + printf ("%*c", 16 - nn, ' '); + } + } + + printf ("\n"); + } + } + } +} + +static void +process_section_contents () +{ + Elf_Shdr * spnt; + int i; + + if (! do_dump) + return; + + spnt = elf_sections; + + for (i = 0; i < epnt->e_shnum; i++, spnt++) + { + int bytes; + int addr; + int lbytes; + unsigned char * my_addr; + +#ifdef SUPPORT_DISASSEMBLY + /* See if we need an assembly dump of this section */ + + if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & DISASS_DUMP)) + { + printf (_("\nAssembly dump of section %s\n"), SECTION_NAME (spnt)); + + bytes = spnt->sh_size; + addr = spnt->sh_addr; + my_addr = (unsigned char *) (header + spnt->sh_offset); + + while (bytes > 0) + { + printf ("0x%8.8x ", addr); + + switch (epnt->e_machine) + { + case EM_386: + case EM_486: + lbytes = db_disasm ((unsigned int) my_addr, 0, 0) - + ((unsigned int) my_addr); + break; + case EM_68K: + lbytes = (m68k_disass ((unsigned int) my_addr, addr) + - (unsigned int) my_addr); + break; + default: + warn (_("Unable to disassemble code for this platform\n")); + return; + } + + addr += lbytes; + my_addr += lbytes; + bytes -= lbytes; + + printf ("\n"); + } + } +#endif + + /* OK, see if we need a hex dump of this section. */ + if ((i < NUM_DUMP_SECTS) && (dump_sects[i] & HEX_DUMP)) + { + int j; + int k; + + printf (_("\nHex dump of section %s\n"), SECTION_NAME (spnt)); + + bytes = spnt->sh_size; + addr = spnt->sh_addr; + my_addr = (unsigned char *) (header + spnt->sh_offset); + + while (bytes) + { + lbytes = (bytes > 16 ? 16 : bytes); + + printf ("0x%8.8x ",addr); + + switch (epnt->e_ident [EI_DATA]) + { + case ELFDATA2LSB: + for (j = 15; j >= 0; j --) + { + if (j < lbytes) + printf ("%2.2x", my_addr[j]); + else + printf (" "); + + if (!(j & 0x3)) + printf (" "); + } + break; + + case ELFDATA2MSB: + for (j = 0; j < 16; j++) + { + if (j < lbytes) + printf ("%2.2x", my_addr[j]); + else + printf (" "); + + if ((j & 3) == 3) + printf (" "); + } + break; + } + + for (j = 0; j < lbytes; j++) + { + k = my_addr [j]; + if (k >= ' ' && k < 0x80) + printf ("%c", k); + else + printf ("."); + } + + printf ("\n"); + + my_addr += lbytes; + addr += lbytes; + bytes -= lbytes; + } + } + } +} + +static void +process_file (file_name) + char * file_name; +{ + int fd; + struct stat statbuf; + + must_swap = 0; + + fd = open (file_name, O_RDONLY); + if (fd == -1) + { + error (_("Input file %s not found.\n"), file_name); + return; + } + + if (fstat (fd, & statbuf) < 0) + { + error (_("Cannot stat input file %s.\n"), file_name); + close (fd); + return; + } + + header = mmap (0, statbuf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + + if ((header == (char *) -1) || (header == NULL)) + { + error (_("Cannot mmap %s: %s\n"), file_name, strerror (errno)); + close (fd); + return; + } + + close (fd); + + epnt = (Elf_Ehdr *) header; + + if (show_name) + printf (_("\nFile: %s\n"), file_name); + + if (! process_elf_header ()) + { + munmap (header, statbuf.st_size); + return; + } + + process_program_headers (); + + if (loadaddr == -1) + { + /* Very strange. */ + loadaddr = 0; + } + + process_section_headers (); + + process_dynamic_segment (); + + process_symbol_table (); + + process_section_contents (); + + munmap (header, statbuf.st_size); + + if (must_swap) + { + if (epnt) + { + free (epnt); + epnt = NULL; + } + + if (elf_sections) + { + free (elf_sections); + elf_sections = NULL; + } + } +} + +#ifdef SUPPORT_DISASSEMBLY +/* Needed by the i386 disassembler. For extra credit, someone could +fix this so that we insert symbolic addresses here, esp for GOT/PLT +symbols */ + +void +print_address (unsigned int addr, FILE * outfile) +{ + fprintf (outfile,"0x%8.8x", addr); +} + +/* Needed by the i386 disassembler. */ +void +db_task_printsym (unsigned int addr) +{ + print_address (addr, stderr); +} +#endif + +int +main (argc, argv) + int argc; + char ** argv; +{ + parse_args (argc, argv); + + expected_endian = 0x12345678; + + if (* ((char *) & expected_endian) == 0x12) + expected_endian = ELFDATA2MSB; + else + expected_endian = ELFDATA2LSB; + + if (optind < (argc - 1)) + show_name = 1; + + while (optind < argc) + process_file (argv [optind ++]); + + return 0; +} |