X-Git-Url: http://drtracing.org/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=d9686731fda9d630e793e2bb1a1e88db9e5fbe97;hb=156c2f8bf75a86dfa719220f9f259196d9d2491b;hp=ca6be94cacc6ee3451b9c8e47f0fca13fe56a631;hpb=04a866f231231ff6078c39381915f4fad37da20f;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index ca6be94cac..d9686731fd 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1,5 +1,5 @@ /* readelf.c -- display contents of an ELF format file - Copyright (C) 1998, 1999 Free Software Foundation, Inc. + Copyright (C) 1998, 99, 2000 Free Software Foundation, Inc. Originally developed by Eric Youngdale Modifications by Nick Clifton @@ -23,10 +23,19 @@ #include +#include #include #include #include +#if __GNUC__ >= 2 +/* Define BFD64 here, even if our default architecture is 32 bit ELF + as this will allow us to read in and parse 64bit and 32bit ELF files. + Only do this if we belive that the compiler can support a 64 bit + data type. For now we only rely on GCC being able to do this. */ +#define BFD64 +#endif + #include "bfd.h" #include "elf/common.h" @@ -59,23 +68,23 @@ #include "elf/fr30.h" #include "elf/mcore.h" #include "elf/i960.h" +#include "elf/pj.h" +#include "elf/avr.h" +#include "elf/ia64.h" +#include "elf/cris.h" +#include "elf/i860.h" #include "bucomm.h" #include "getopt.h" -#ifdef ANSI_PROTOTYPES -#include -#else -#include -#endif - char * program_name = "readelf"; unsigned int dynamic_addr; -unsigned int dynamic_size; +bfd_size_type dynamic_size; unsigned int rela_addr; unsigned int rela_size; char * dynamic_strings; char * string_table; +unsigned long num_dynamic_syms; Elf_Internal_Sym * dynamic_symbols; Elf_Internal_Syminfo * dynamic_syminfo; unsigned long dynamic_syminfo_offset; @@ -104,7 +113,9 @@ int do_debug_abbrevs; int do_debug_lines; int do_debug_pubnames; int do_debug_aranges; -int binary_class; +int do_arch; +int do_notes; +int is_32bit_elf; /* A dynamic array of flags indicating which sections require dumping. */ char * dump_sects = NULL; @@ -114,39 +125,68 @@ unsigned int num_dump_sects = 0; #define DISASS_DUMP (1 << 1) #define DEBUG_DUMP (1 << 2) +/* How to rpint a vma value. */ +typedef enum print_mode +{ + HEX, + DEC, + DEC_5, + UNSIGNED, + PREFIX_HEX, + FULL_HEX, + LONG_HEX +} +print_mode; + /* Forward declarations for dumb compilers. */ -static unsigned long (* byte_get) PARAMS ((unsigned char *, int)); -static const char * get_mips_dynamic_type PARAMS ((unsigned long type)); -static const char * get_dynamic_type PARAMS ((unsigned long type)); -static int dump_relocations PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Sym *, char *, int)); -static char * get_file_type PARAMS ((unsigned e_type)); -static char * get_machine_name PARAMS ((unsigned e_machine)); -static char * get_machine_data PARAMS ((unsigned e_data)); -static char * get_machine_flags PARAMS ((unsigned, unsigned e_machine)); -static const char * get_mips_segment_type PARAMS ((unsigned long type)); -static const char * get_segment_type PARAMS ((unsigned long p_type)); -static const char * get_mips_section_type_name PARAMS ((unsigned int sh_type)); -static const char * get_section_type_name PARAMS ((unsigned int sh_type)); -static char * get_symbol_binding PARAMS ((unsigned int binding)); -static char * get_symbol_type PARAMS ((unsigned int type)); +static void print_vma PARAMS ((bfd_vma, print_mode)); +static bfd_vma (* byte_get) PARAMS ((unsigned char *, int)); +static bfd_vma byte_get_little_endian PARAMS ((unsigned char *, int)); +static bfd_vma byte_get_big_endian PARAMS ((unsigned char *, int)); +static const char * get_mips_dynamic_type PARAMS ((unsigned long)); +static const char * get_sparc64_dynamic_type PARAMS ((unsigned long)); +static const char * get_parisc_dynamic_type PARAMS ((unsigned long)); +static const char * get_dynamic_type PARAMS ((unsigned long)); +static int dump_relocations PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Sym *, unsigned long, char *, int)); +static char * get_file_type PARAMS ((unsigned)); +static char * get_machine_name PARAMS ((unsigned)); +static void decode_ARM_machine_flags PARAMS ((unsigned, char [])); +static char * get_machine_flags PARAMS ((unsigned, unsigned)); +static const char * get_mips_segment_type PARAMS ((unsigned long)); +static const char * get_parisc_segment_type PARAMS ((unsigned long)); +static const char * get_segment_type PARAMS ((unsigned long)); +static const char * get_mips_section_type_name PARAMS ((unsigned int)); +static const char * get_parisc_section_type_name PARAMS ((unsigned int)); +static const char * get_section_type_name PARAMS ((unsigned int)); +static const char * get_symbol_binding PARAMS ((unsigned int)); +static const char * get_symbol_type PARAMS ((unsigned int)); +static const char * get_symbol_visibility PARAMS ((unsigned int)); +static const char * get_symbol_index_type PARAMS ((unsigned int)); +static const char * get_dynamic_flags PARAMS ((bfd_vma)); static void usage PARAMS ((void)); -static void parse_args PARAMS ((int argc, char ** argv)); +static void parse_args PARAMS ((int, char **)); static int process_file_header PARAMS ((void)); static int process_program_headers PARAMS ((FILE *)); static int process_section_headers PARAMS ((FILE *)); -static void dynamic_segment_mips_val PARAMS ((Elf_Internal_Dyn *entry)); +static void dynamic_segment_mips_val PARAMS ((Elf_Internal_Dyn *)); +static void dynamic_segment_parisc_val PARAMS ((Elf_Internal_Dyn *)); static int process_dynamic_segment PARAMS ((FILE *)); static int process_symbol_table PARAMS ((FILE *)); static int process_section_contents PARAMS ((FILE *)); -static void process_file PARAMS ((char * file_name)); +static void process_file PARAMS ((char *)); static int process_relocs PARAMS ((FILE *)); static int process_version_sections PARAMS ((FILE *)); -static char * get_ver_flags PARAMS ((unsigned int flags)); -static char * get_symbol_index_type PARAMS ((unsigned int type)); -static int get_section_headers PARAMS ((FILE * file)); -static int get_file_header PARAMS ((FILE * file)); -static Elf_Internal_Sym * get_elf_symbols PARAMS ((FILE * file, unsigned long offset, unsigned long number)); -static int * get_dynamic_data PARAMS ((FILE * file, unsigned int number)); +static char * get_ver_flags PARAMS ((unsigned int)); +static int get_32bit_section_headers PARAMS ((FILE *)); +static int get_64bit_section_headers PARAMS ((FILE *)); +static int get_32bit_program_headers PARAMS ((FILE *, Elf_Internal_Phdr *)); +static int get_64bit_program_headers PARAMS ((FILE *, Elf_Internal_Phdr *)); +static int get_file_header PARAMS ((FILE *)); +static Elf_Internal_Sym * get_32bit_elf_symbols PARAMS ((FILE *, unsigned long, unsigned long)); +static Elf_Internal_Sym * get_64bit_elf_symbols PARAMS ((FILE *, unsigned long, unsigned long)); +static int * get_dynamic_data PARAMS ((FILE *, unsigned int)); +static int get_32bit_dynamic_segment PARAMS ((FILE *)); +static int get_64bit_dynamic_segment PARAMS ((FILE *)); #ifdef SUPPORT_DISASSEMBLY static int disassemble_section PARAMS ((Elf32_Internal_Shdr *, FILE *)); #endif @@ -159,7 +199,7 @@ static int display_debug_abbrev PARAMS ((Elf32_Internal_Sh static int display_debug_aranges PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *)); static unsigned char * process_abbrev_section PARAMS ((unsigned char *, unsigned char *)); static unsigned long read_leb128 PARAMS ((unsigned char *, int *, int)); -static int process_extended_line_op PARAMS ((unsigned char *, int)); +static int process_extended_line_op PARAMS ((unsigned char *, int, int)); static void reset_state_machine PARAMS ((int)); static char * get_TAG_name PARAMS ((unsigned long)); static char * get_AT_name PARAMS ((unsigned long)); @@ -167,14 +207,19 @@ static char * get_FORM_name PARAMS ((unsigned long)); static void free_abbrevs PARAMS ((void)); static void add_abbrev PARAMS ((unsigned long, unsigned long, int)); static void add_abbrev_attr PARAMS ((unsigned long, unsigned long)); -static unsigned char * read_and_display_attr PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long)); +static unsigned char * read_and_display_attr PARAMS ((unsigned long, unsigned long, unsigned char *, unsigned long, unsigned long)); static unsigned char * display_block PARAMS ((unsigned char *, unsigned long)); -static void decode_location_expression PARAMS ((unsigned char *, unsigned int)); +static void decode_location_expression PARAMS ((unsigned char *, unsigned int, unsigned long)); static void request_dump PARAMS ((unsigned int, char)); static const char * get_elf_class PARAMS ((unsigned char)); static const char * get_data_encoding PARAMS ((unsigned char)); static const char * get_osabi_name PARAMS ((unsigned char)); static int guess_is_rela PARAMS ((unsigned long)); +static char * get_note_type PARAMS ((unsigned int)); +static int process_note PARAMS ((Elf32_Internal_Note *)); +static int process_corefile_note_segment PARAMS ((FILE *, bfd_vma, bfd_vma)); +static int process_corefile_note_segments PARAMS ((FILE *)); +static int process_corefile_contents PARAMS ((FILE *)); typedef int Elf32_Word; @@ -190,6 +235,20 @@ typedef int Elf32_Word; #define BYTE_GET(field) byte_get (field, sizeof (field)) +/* If we can support a 64 bit data type then BFD64 should be defined + and sizeof (bfd_vma) == 8. In this case when translating from an + external 8 byte field to an internal field, we can assume that the + internal field is also 8 bytes wide and so we can extact all the data. + If, however, BFD64 is not defined, then we must assume that the + internal data structure only has 4 byte wide fields that are the + equivalent of the 8 byte wide external counterparts, and so we must + truncate the data. */ +#ifdef BFD64 +#define BYTE_GET8(field) byte_get (field, -8) +#else +#define BYTE_GET8(field) byte_get (field, 8) +#endif + #define NUM_ELEM(array) (sizeof (array) / sizeof ((array)[0])) #define GET_DATA_ALLOC(offset, size, var, type, reason) \ @@ -228,6 +287,11 @@ typedef int Elf32_Word; return 0; \ } +#define GET_ELF_SYMBOLS(file, offset, size) \ + (is_32bit_elf ? get_32bit_elf_symbols (file, offset, size) \ + : get_64bit_elf_symbols (file, offset, size)) + + #ifdef ANSI_PROTOTYPES static void error (const char * message, ...) @@ -284,7 +348,7 @@ warn (va_alist) } #endif -static unsigned long int +static bfd_vma byte_get_little_endian (field, size) unsigned char * field; int size; @@ -298,19 +362,128 @@ byte_get_little_endian (field, size) return ((unsigned int) (field [0])) | (((unsigned int) (field [1])) << 8); + case 8: + /* We want to extract data from an 8 byte wide field and + place it into a 4 byte wide field. Since this is a little + endian source we can juts use the 4 byte extraction code. */ + /* Fall through. */ case 4: return ((unsigned long) (field [0])) | (((unsigned long) (field [1])) << 8) | (((unsigned long) (field [2])) << 16) | (((unsigned long) (field [3])) << 24); +#ifdef BFD64 + case -8: + /* This is a special case, generated by the BYTE_GET8 macro. + It means that we are loading an 8 byte value from a field + in an external structure into an 8 byte value in a field + in an internal strcuture. */ + return ((bfd_vma) (field [0])) + | (((bfd_vma) (field [1])) << 8) + | (((bfd_vma) (field [2])) << 16) + | (((bfd_vma) (field [3])) << 24) + | (((bfd_vma) (field [4])) << 32) + | (((bfd_vma) (field [5])) << 40) + | (((bfd_vma) (field [6])) << 48) + | (((bfd_vma) (field [7])) << 56); +#endif default: error (_("Unhandled data length: %d\n"), size); - abort(); + abort (); } } -static unsigned long int +/* Print a VMA value. */ +static void +print_vma (vma, mode) + bfd_vma vma; + print_mode mode; +{ +#ifdef BFD64 + if (is_32bit_elf) +#endif + { + switch (mode) + { + case FULL_HEX: printf ("0x"); /* drop through */ + case LONG_HEX: printf ("%8.8lx", (unsigned long) vma); break; + case PREFIX_HEX: printf ("0x"); /* drop through */ + case HEX: printf ("%lx", (unsigned long) vma); break; + case DEC: printf ("%ld", (unsigned long) vma); break; + case DEC_5: printf ("%5ld", (long) vma); break; + case UNSIGNED: printf ("%lu", (unsigned long) vma); break; + } + } +#ifdef BFD64 + else + { + switch (mode) + { + case FULL_HEX: + printf ("0x"); + /* drop through */ + + case LONG_HEX: + printf_vma (vma); + break; + + case PREFIX_HEX: + printf ("0x"); + /* drop through */ + + case HEX: +#if BFD_HOST_64BIT_LONG + printf ("%lx", vma); +#else + if (_bfd_int64_high (vma)) + printf ("%lx%lx", _bfd_int64_high (vma), _bfd_int64_low (vma)); + else + printf ("%lx", _bfd_int64_low (vma)); +#endif + break; + + case DEC: +#if BFD_HOST_64BIT_LONG + printf ("%ld", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%ld", _bfd_int64_low (vma)); + else + printf ("%ld", _bfd_int64_low (vma)); +#endif + break; + + case DEC_5: +#if BFD_HOST_64BIT_LONG + printf ("%5ld", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%ld", _bfd_int64_low (vma)); + else + printf ("%5ld", _bfd_int64_low (vma)); +#endif + break; + + case UNSIGNED: +#if BFD_HOST_64BIT_LONG + printf ("%lu", vma); +#else + if (_bfd_int64_high (vma)) + /* ugg */ + printf ("++%lu", _bfd_int64_low (vma)); + else + printf ("%lu", _bfd_int64_low (vma)); +#endif + break; + } + } +#endif +} + +static bfd_vma byte_get_big_endian (field, size) unsigned char * field; int size; @@ -329,9 +502,33 @@ byte_get_big_endian (field, size) | (((unsigned long) (field [1])) << 16) | (((unsigned long) (field [0])) << 24); + case 8: + /* Although we are extracing data from an 8 byte wide field, we + are returning only 4 bytes of data. */ + return ((unsigned long) (field [7])) + | (((unsigned long) (field [6])) << 8) + | (((unsigned long) (field [5])) << 16) + | (((unsigned long) (field [4])) << 24); + +#ifdef BFD64 + case -8: + /* This is a special case, generated by the BYTE_GET8 macro. + It means that we are loading an 8 byte value from a field + in an external structure into an 8 byte value in a field + in an internal strcuture. */ + return ((bfd_vma) (field [7])) + | (((bfd_vma) (field [6])) << 8) + | (((bfd_vma) (field [5])) << 16) + | (((bfd_vma) (field [4])) << 24) + | (((bfd_vma) (field [3])) << 32) + | (((bfd_vma) (field [2])) << 40) + | (((bfd_vma) (field [1])) << 48) + | (((bfd_vma) (field [0])) << 56); +#endif + default: error (_("Unhandled data length: %d\n"), size); - abort(); + abort (); } } @@ -353,9 +550,11 @@ guess_is_rela (e_machine) case EM_MIPS: case EM_MIPS_RS4_BE: return FALSE; - + /* Targets that use RELA relocations. */ case EM_68K: + case EM_SPARC32PLUS: + case EM_SPARCV9: case EM_SPARC: case EM_PPC: case EM_CYGNUS_V850: @@ -366,89 +565,174 @@ guess_is_rela (e_machine) case EM_SH: case EM_ALPHA: case EM_MCORE: + case EM_IA_64: + case EM_AVR: + case EM_CRIS: + case EM_860: return TRUE; - + + case EM_MMA: + case EM_PCP: + case EM_NCPU: + case EM_NDR1: + case EM_STARCORE: + case EM_ME16: + case EM_ST100: + case EM_TINYJ: + case EM_FX66: + case EM_ST9PLUS: + case EM_ST7: + case EM_68HC16: + case EM_68HC11: + case EM_68HC08: + case EM_68HC05: + case EM_SVX: + case EM_ST19: + case EM_VAX: default: warn (_("Don't know about relocations on this machine architecture\n")); return FALSE; } } -/* Display the contents of the relocation data - found at the specified offset. */ +/* Display the contents of the relocation data found at the specified offset. */ static int -dump_relocations (file, rel_offset, rel_size, symtab, strtabm, is_rela) - FILE * file; - unsigned long rel_offset; - unsigned long rel_size; - Elf_Internal_Sym * symtab; - char * strtab; - int is_rela; +dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) + FILE * file; + unsigned long rel_offset; + unsigned long rel_size; + Elf_Internal_Sym * symtab; + unsigned long nsyms; + char * strtab; + int is_rela; { unsigned int i; Elf_Internal_Rel * rels; Elf_Internal_Rela * relas; - + if (is_rela == UNKNOWN) is_rela = guess_is_rela (elf_header.e_machine); if (is_rela) { - Elf32_External_Rela * erelas; - - GET_DATA_ALLOC (rel_offset, rel_size, erelas, - Elf32_External_Rela *, "relocs"); - - rel_size = rel_size / sizeof (Elf32_External_Rela); - - relas = (Elf_Internal_Rela *) malloc (rel_size * - sizeof (Elf_Internal_Rela)); - - if (relas == NULL) + if (is_32bit_elf) { - error(_("out of memory parsing relocs")); - return 0; + Elf32_External_Rela * erelas; + + GET_DATA_ALLOC (rel_offset, rel_size, erelas, + Elf32_External_Rela *, "relocs"); + + rel_size = rel_size / sizeof (Elf32_External_Rela); + + relas = (Elf_Internal_Rela *) + malloc (rel_size * sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < rel_size; i++) + { + relas[i].r_offset = BYTE_GET (erelas[i].r_offset); + relas[i].r_info = BYTE_GET (erelas[i].r_info); + relas[i].r_addend = BYTE_GET (erelas[i].r_addend); + } + + free (erelas); + + rels = (Elf_Internal_Rel *) relas; } - - for (i = 0; i < rel_size; i++) + else { - relas[i].r_offset = BYTE_GET (erelas[i].r_offset); - relas[i].r_info = BYTE_GET (erelas[i].r_info); - relas[i].r_addend = BYTE_GET (erelas[i].r_addend); + Elf64_External_Rela * erelas; + + GET_DATA_ALLOC (rel_offset, rel_size, erelas, + Elf64_External_Rela *, "relocs"); + + rel_size = rel_size / sizeof (Elf64_External_Rela); + + relas = (Elf_Internal_Rela *) + malloc (rel_size * sizeof (Elf_Internal_Rela)); + + if (relas == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < rel_size; i++) + { + relas[i].r_offset = BYTE_GET8 (erelas[i].r_offset); + relas[i].r_info = BYTE_GET8 (erelas[i].r_info); + relas[i].r_addend = BYTE_GET8 (erelas[i].r_addend); + } + + free (erelas); + + rels = (Elf_Internal_Rel *) relas; } - - free (erelas); - - rels = (Elf_Internal_Rel *) relas; } else { - Elf32_External_Rel * erels; - unsigned long saved_rel_size = rel_size; - - GET_DATA_ALLOC (rel_offset, rel_size, erels, - Elf32_External_Rel *, "relocs"); - - rel_size = rel_size / sizeof (Elf32_External_Rel); - - rels = (Elf_Internal_Rel *) malloc (rel_size * - sizeof (Elf_Internal_Rel)); - if (rels == NULL) + if (is_32bit_elf) { - error(_("out of memory parsing relocs")); - return 0; + Elf32_External_Rel * erels; + + GET_DATA_ALLOC (rel_offset, rel_size, erels, + Elf32_External_Rel *, "relocs"); + + rel_size = rel_size / sizeof (Elf32_External_Rel); + + rels = (Elf_Internal_Rel *) + malloc (rel_size * sizeof (Elf_Internal_Rel)); + + if (rels == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < rel_size; i++) + { + rels[i].r_offset = BYTE_GET (erels[i].r_offset); + rels[i].r_info = BYTE_GET (erels[i].r_info); + } + + free (erels); + + relas = (Elf_Internal_Rela *) rels; } - - for (i = 0; i < rel_size; i++) + else { - rels[i].r_offset = BYTE_GET (erels[i].r_offset); - rels[i].r_info = BYTE_GET (erels[i].r_info); + Elf64_External_Rel * erels; + + GET_DATA_ALLOC (rel_offset, rel_size, erels, + Elf64_External_Rel *, "relocs"); + + rel_size = rel_size / sizeof (Elf64_External_Rel); + + rels = (Elf_Internal_Rel *) + malloc (rel_size * sizeof (Elf_Internal_Rel)); + + if (rels == NULL) + { + error(_("out of memory parsing relocs")); + return 0; + } + + for (i = 0; i < rel_size; i++) + { + rels[i].r_offset = BYTE_GET8 (erels[i].r_offset); + rels[i].r_info = BYTE_GET8 (erels[i].r_info); + } + + free (erels); + + relas = (Elf_Internal_Rela *) rels; } - - free (erels); - - relas = (Elf_Internal_Rela *) rels; } if (is_rela) @@ -460,10 +744,11 @@ dump_relocations (file, rel_offset, rel_size, symtab, strtabm, is_rela) for (i = 0; i < rel_size; i++) { - const char * rtype; - unsigned long offset; - unsigned long info; - int symtab_index; + const char * rtype; + bfd_vma offset; + bfd_vma info; + bfd_vma symtab_index; + bfd_vma type; if (is_rela) { @@ -476,7 +761,30 @@ dump_relocations (file, rel_offset, rel_size, symtab, strtabm, is_rela) info = rels [i].r_info; } + if (is_32bit_elf) + { + type = ELF32_R_TYPE (info); + symtab_index = ELF32_R_SYM (info); + } + else + { + if (elf_header.e_machine == EM_SPARCV9) + type = ELF64_R_TYPE_ID (info); + else + type = ELF64_R_TYPE (info); + /* The #ifdef BFD64 below is to prevent a compile time warning. + We know that if we do not have a 64 bit data type that we + will never execute this code anyway. */ +#ifdef BFD64 + symtab_index = ELF64_R_SYM (info); +#endif + } + +#ifdef _bfd_int64_low + printf (" %8.8lx %5.5lx ", _bfd_int64_low (offset), _bfd_int64_low (info)); +#else printf (" %8.8lx %5.5lx ", offset, info); +#endif switch (elf_header.e_machine) { @@ -485,112 +793,153 @@ dump_relocations (file, rel_offset, rel_size, symtab, strtabm, is_rela) break; case EM_CYGNUS_M32R: - rtype = elf_m32r_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_m32r_reloc_type (type); break; case EM_386: case EM_486: - rtype = elf_i386_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_i386_reloc_type (type); break; case EM_68K: - rtype = elf_m68k_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_m68k_reloc_type (type); break; case EM_960: - rtype = elf_i960_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_i960_reloc_type (type); + break; + + case EM_AVR: + rtype = elf_avr_reloc_type (type); break; + case EM_OLD_SPARCV9: + case EM_SPARC32PLUS: + case EM_SPARCV9: case EM_SPARC: - rtype = elf_sparc_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_sparc_reloc_type (type); break; case EM_CYGNUS_V850: - rtype = v850_reloc_type (ELF32_R_TYPE (info)); + rtype = v850_reloc_type (type); break; case EM_CYGNUS_D10V: - rtype = elf_d10v_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_d10v_reloc_type (type); break; case EM_CYGNUS_D30V: - rtype = elf_d30v_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_d30v_reloc_type (type); break; case EM_SH: - rtype = elf_sh_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_sh_reloc_type (type); break; case EM_CYGNUS_MN10300: - rtype = elf_mn10300_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_mn10300_reloc_type (type); break; case EM_CYGNUS_MN10200: - rtype = elf_mn10200_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_mn10200_reloc_type (type); break; case EM_CYGNUS_FR30: - rtype = elf_fr30_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_fr30_reloc_type (type); break; case EM_MCORE: - rtype = elf_mcore_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_mcore_reloc_type (type); break; case EM_PPC: - rtype = elf_ppc_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_ppc_reloc_type (type); break; case EM_MIPS: case EM_MIPS_RS4_BE: - rtype = elf_mips_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_mips_reloc_type (type); break; case EM_ALPHA: - rtype = elf_alpha_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_alpha_reloc_type (type); break; case EM_ARM: - rtype = elf_arm_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_arm_reloc_type (type); break; case EM_CYGNUS_ARC: - rtype = elf_arc_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_arc_reloc_type (type); break; case EM_PARISC: - rtype = elf32_hppa_reloc_type (ELF32_R_TYPE (info)); + rtype = elf_hppa_reloc_type (type); + break; + + case EM_PJ: + rtype = elf_pj_reloc_type (type); + break; + case EM_IA_64: + rtype = elf_ia64_reloc_type (type); + break; + + case EM_CRIS: + rtype = elf_cris_reloc_type (type); + break; + + case EM_860: + rtype = elf_i860_reloc_type (type); break; } if (rtype == NULL) - printf (_("unrecognised: %-7lx"), ELF32_R_TYPE (info)); +#ifdef _bfd_int64_low + printf (_("unrecognised: %-7lx"), _bfd_int64_low (type)); +#else + printf (_("unrecognised: %-7lx"), type); +#endif else printf ("%-21.21s", rtype); - symtab_index = ELF32_R_SYM (info); - - if (symtab_index && symtab != NULL) + if (symtab_index) { - Elf_Internal_Sym * psym; + if (symtab != NULL) + { + if (symtab_index >= nsyms) + printf (" bad symbol index: %08lx", (unsigned long) symtab_index); + else + { + Elf_Internal_Sym * psym; - psym = symtab + symtab_index; + psym = symtab + symtab_index; - printf (" %08lx ", (unsigned long) psym->st_value); + printf (" "); + print_vma (psym->st_value, LONG_HEX); + printf (" "); - if (psym->st_name == 0) - printf ("%-25.25s", - SECTION_NAME (section_headers + psym->st_shndx)); - else if (strtab == NULL) - printf (_(""), psym->st_name); - else - printf ("%-25.25s", strtab + psym->st_name); + if (psym->st_name == 0) + printf ("%-25.25s", + SECTION_NAME (section_headers + psym->st_shndx)); + else if (strtab == NULL) + printf (_(""), psym->st_name); + else + printf ("%-25.25s", strtab + psym->st_name); - if (is_rela) - printf (" + %lx", (unsigned long) relas [i].r_addend); + if (is_rela) + printf (" + %lx", (unsigned long) relas [i].r_addend); + } + } } else if (is_rela) - printf ("%34c%lx", ' ', (unsigned long) relas[i].r_addend); + { + printf ("%*c", is_32bit_elf ? 34 : 26, ' '); + print_vma (relas[i].r_addend, LONG_HEX); + } + + if (elf_header.e_machine == EM_SPARCV9 + && !strcmp (rtype, "R_SPARC_OLO10")) + printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info)); putchar ('\n'); } @@ -654,6 +1003,42 @@ get_mips_dynamic_type (type) } } +static const char * +get_sparc64_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_SPARC_REGISTER: return "SPARC_REGISTER"; + default: + return NULL; + } +} + +static const char * +get_parisc_dynamic_type (type) + unsigned long type; +{ + switch (type) + { + case DT_HP_LOAD_MAP: return "HP_LOAD_MAP"; + case DT_HP_DLD_FLAGS: return "HP_DLD_FLAGS"; + case DT_HP_DLD_HOOK: return "HP_DLD_HOOK"; + case DT_HP_UX10_INIT: return "HP_UX10_INIT"; + case DT_HP_UX10_INITSZ: return "HP_UX10_INITSZ"; + case DT_HP_PREINIT: return "HP_PREINIT"; + case DT_HP_PREINITSZ: return "HP_PREINITSZ"; + case DT_HP_NEEDED: return "HP_NEEDED"; + case DT_HP_TIME_STAMP: return "HP_TIME_STAMP"; + case DT_HP_CHECKSUM: return "HP_CHECKSUM"; + case DT_HP_GST_SIZE: return "HP_GST_SIZE"; + case DT_HP_GST_VERSION: return "HP_GST_VERSION"; + case DT_HP_GST_HASHVAL: return "HP_GST_HASHVAL"; + default: + return NULL; + } +} + static const char * get_dynamic_type (type) unsigned long type; @@ -691,20 +1076,31 @@ get_dynamic_type (type) case DT_FINI_ARRAY: return "FINI_ARRAY"; case DT_INIT_ARRAYSZ: return "INIT_ARRAYSZ"; case DT_FINI_ARRAYSZ: return "FINI_ARRAYSZ"; - + case DT_RUNPATH: return "RUNPATH"; + case DT_FLAGS: return "FLAGS"; + + case DT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case DT_PREINIT_ARRAYSZ: return "PREINIT_ARRAYSZ"; + + case DT_CHECKSUM: return "CHECKSUM"; case DT_PLTPADSZ: return "PLTPADSZ"; case DT_MOVEENT: return "MOVEENT"; case DT_MOVESZ: return "MOVESZ"; - case DT_FEATURE_1: return "FEATURE_1"; + case DT_FEATURE: return "FEATURE"; case DT_POSFLAG_1: return "POSFLAG_1"; case DT_SYMINSZ: return "SYMINSZ"; case DT_SYMINENT: return "SYMINENT"; /* aka VALRNGHI */ - + case DT_ADDRRNGLO: return "ADDRRNGLO"; + case DT_CONFIG: return "CONFIG"; + case DT_DEPAUDIT: return "DEPAUDIT"; + case DT_AUDIT: return "AUDIT"; + case DT_PLTPAD: return "PLTPAD"; + case DT_MOVETAB: return "MOVETAB"; case DT_SYMINFO: return "SYMINFO"; /* aka ADDRRNGHI */ - + case DT_VERSYM: return "VERSYM"; - + case DT_RELACOUNT: return "RELACOUNT"; case DT_RELCOUNT: return "RELCOUNT"; case DT_FLAGS_1: return "FLAGS_1"; @@ -712,22 +1108,25 @@ get_dynamic_type (type) case DT_VERDEFNUM: return "VERDEFNUM"; case DT_VERNEED: return "VERNEED"; case DT_VERNEEDNUM: return "VERNEEDNUM"; - - case DT_AUXILIARY: return "AUXILARY"; + + case DT_AUXILIARY: return "AUXILIARY"; case DT_USED: return "USED"; case DT_FILTER: return "FILTER"; - + default: if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) { const char * result; - + switch (elf_header.e_machine) { case EM_MIPS: case EM_MIPS_RS4_BE: result = get_mips_dynamic_type (type); break; + case EM_SPARCV9: + result = get_sparc64_dynamic_type (type); + break; default: result = NULL; break; @@ -739,10 +1138,27 @@ get_dynamic_type (type) sprintf (buff, _("Processor Specific: %lx"), type); } else if ((type >= DT_LOOS) && (type <= DT_HIOS)) - sprintf (buff, _("Operating System specific: %lx"), type); + { + const char * result; + + switch (elf_header.e_machine) + { + case EM_PARISC: + result = get_parisc_dynamic_type (type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, _("Operating System specific: %lx"), type); + } else sprintf (buff, _(": %lx"), type); - + return buff; } } @@ -776,7 +1192,7 @@ static char * get_machine_name (e_machine) unsigned e_machine; { - static char buff [32]; + static char buff [64]; /* XXX */ switch (e_machine) { @@ -788,8 +1204,8 @@ get_machine_name (e_machine) 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: return "MIPS R3000"; + case EM_S370: return "IBM System/370"; case EM_MIPS_RS4_BE: return "MIPS R4000 big-endian"; case EM_OLD_SPARCV9: return "Sparc v9 (old)"; case EM_PARISC: return "HPPA"; @@ -811,7 +1227,7 @@ get_machine_name (e_machine) case EM_H8_300H: return "Hitachi H8/300H"; case EM_H8S: return "Hitachi H8S"; case EM_H8_500: return "Hitachi H8/500"; - case EM_IA_64: return "Intel Merced"; + case EM_IA_64: return "Intel IA-64"; case EM_MIPS_X: return "Stanford MIPS-X"; case EM_COLDFIRE: return "Motorola Coldfire"; case EM_68HC12: return "Motorola M68HC12"; @@ -824,51 +1240,185 @@ get_machine_name (e_machine) case EM_CYGNUS_MN10300: return "mn10300"; case EM_CYGNUS_MN10200: return "mn10200"; case EM_CYGNUS_FR30: return "Fujitsu FR30"; - + case EM_PJ: return "picoJava"; + case EM_MMA: return "Fujitsu Multimedia Accelerator"; + case EM_PCP: return "Siemens PCP"; + case EM_NCPU: return "Sony nCPU embedded RISC processor"; + case EM_NDR1: return "Denso NDR1 microprocesspr"; + case EM_STARCORE: return "Motorola Star*Core processor"; + case EM_ME16: return "Toyota ME16 processor"; + case EM_ST100: return "STMicroelectronics ST100 processor"; + case EM_TINYJ: return "Advanced Logic Corp. TinyJ embedded processor"; + case EM_FX66: return "Siemens FX66 microcontroller"; + case EM_ST9PLUS: return "STMicroelectronics ST9+ 8/16 bit microcontroller"; + case EM_ST7: return "STMicroelectronics ST7 8-bit microcontroller"; + case EM_68HC16: return "Motorola MC68HC16 Microcontroller"; + case EM_68HC11: return "Motorola MC68HC11 Microcontroller"; + case EM_68HC08: return "Motorola MC68HC08 Microcontroller"; + case EM_68HC05: return "Motorola MC68HC05 Microcontroller"; + case EM_SVX: return "Silicon Graphics SVx"; + case EM_ST19: return "STMicroelectronics ST19 8-bit microcontroller"; + case EM_VAX: return "Digital VAX"; + case EM_AVR: return "Atmel AVR 8-bit microcontroller"; + case EM_CRIS: return "Axis Communications 32-bit embedded processor"; default: sprintf (buff, _(": %x"), e_machine); return buff; } } -static char * -get_machine_flags (e_flags, e_machine) +static void +decode_ARM_machine_flags (e_flags, buf) unsigned e_flags; - unsigned e_machine; + char buf[]; { - static char buf [1024]; - - buf[0] = '\0'; - if (e_flags) - { - switch (e_machine) - { - default: - break; - - case EM_68K: - if (e_flags & EF_CPU32) - strcat (buf, ", cpu32"); - break; - - case EM_PPC: - if (e_flags & EF_PPC_EMB) - strcat (buf, ", emb"); + unsigned eabi; + int unknown = 0; - if (e_flags & EF_PPC_RELOCATABLE) - strcat (buf, ", relocatable"); + eabi = EF_ARM_EABI_VERSION (e_flags); + e_flags &= ~ EF_ARM_EABIMASK; - if (e_flags & EF_PPC_RELOCATABLE_LIB) - strcat (buf, ", relocatable-lib"); - break; + /* Handle "generic" ARM flags. */ + if (e_flags & EF_ARM_RELEXEC) + { + strcat (buf, ", relocatable executable"); + e_flags &= ~ EF_ARM_RELEXEC; + } + + if (e_flags & EF_ARM_HASENTRY) + { + strcat (buf, ", has entry point"); + e_flags &= ~ EF_ARM_HASENTRY; + } + + /* Now handle EABI specific flags. */ + switch (eabi) + { + default: + strcat (buf, ", "); + if (e_flags) + unknown = 1; + break; - case EM_CYGNUS_V850: - switch (e_flags & EF_V850_ARCH) + case EF_ARM_EABI_VER1: + while (e_flags) + { + unsigned flag; + + /* Process flags one bit at a time. */ + flag = e_flags & - e_flags; + e_flags &= ~ flag; + + switch (flag) { - case E_V850E_ARCH: - strcat (buf, ", v850e"); + case EF_ARM_SYMSARESORTED: /* Conflicts with EF_INTERWORK. */ + strcat (buf, ", sorted symbol tables"); break; - case E_V850EA_ARCH: + + default: + unknown = 1; + break; + } + } + break; + + case EF_ARM_EABI_UNKNOWN: + while (e_flags) + { + unsigned flag; + + /* Process flags one bit at a time. */ + flag = e_flags & - e_flags; + e_flags &= ~ flag; + + switch (flag) + { + case EF_INTERWORK: + strcat (buf, ", interworking enabled"); + break; + + case EF_APCS_26: + strcat (buf, ", uses APCS/26"); + break; + + case EF_APCS_FLOAT: + strcat (buf, ", uses APCS/float"); + break; + + case EF_PIC: + strcat (buf, ", position independent"); + break; + + case EF_ALIGN8: + strcat (buf, ", 8 bit structure alignment"); + break; + + case EF_NEW_ABI: + strcat (buf, ", uses new ABI"); + break; + + case EF_OLD_ABI: + strcat (buf, ", uses old ABI"); + break; + + case EF_SOFT_FLOAT: + strcat (buf, ", software FP"); + break; + + default: + unknown = 1; + break; + } + } + } + + if (unknown) + strcat (buf,", "); +} + +static char * +get_machine_flags (e_flags, e_machine) + unsigned e_flags; + unsigned e_machine; +{ + static char buf [1024]; + + buf[0] = '\0'; + + if (e_flags) + { + switch (e_machine) + { + default: + break; + + case EM_ARM: + decode_ARM_machine_flags (e_flags, buf); + break; + + case EM_68K: + if (e_flags & EF_CPU32) + strcat (buf, ", cpu32"); + break; + + case EM_PPC: + if (e_flags & EF_PPC_EMB) + strcat (buf, ", emb"); + + if (e_flags & EF_PPC_RELOCATABLE) + strcat (buf, ", relocatable"); + + if (e_flags & EF_PPC_RELOCATABLE_LIB) + strcat (buf, ", relocatable-lib"); + break; + + case EM_CYGNUS_V850: + switch (e_flags & EF_V850_ARCH) + { + case E_V850E_ARCH: + strcat (buf, ", v850e"); + break; + case E_V850EA_ARCH: strcat (buf, ", v850ea"); break; case E_V850_ARCH: @@ -911,27 +1461,84 @@ get_machine_flags (e_flags, e_machine) if ((e_flags & EF_MIPS_ARCH) == E_MIPS_ARCH_4) strcat (buf, ", mips4"); + + switch ((e_flags & EF_MIPS_MACH)) + { + case E_MIPS_MACH_3900: strcat (buf, ", 3900"); break; + case E_MIPS_MACH_4010: strcat (buf, ", 4010"); break; + case E_MIPS_MACH_4100: strcat (buf, ", 4100"); break; + case E_MIPS_MACH_4650: strcat (buf, ", 4650"); break; + case E_MIPS_MACH_4111: strcat (buf, ", 4111"); break; + case E_MIPS_MACH_MIPS32: strcat (buf, ", mips32"); break; + } break; - } - } - return buf; -} + case EM_SPARCV9: + if (e_flags & EF_SPARC_32PLUS) + strcat (buf, ", v8+"); -static char * -get_machine_data (e_data) - unsigned e_data; -{ - static char buff [32]; + if (e_flags & EF_SPARC_SUN_US1) + strcat (buf, ", ultrasparcI"); - switch (e_data) - { - case ELFDATA2LSB: return _("ELFDATA2LSB (little endian)"); - case ELFDATA2MSB: return _("ELFDATA2MSB (big endian)"); - default: - sprintf (buff, _(": %x"), e_data); - return buff; + if (e_flags & EF_SPARC_SUN_US3) + strcat (buf, ", ultrasparcIII"); + + if (e_flags & EF_SPARC_HAL_R1) + strcat (buf, ", halr1"); + + if (e_flags & EF_SPARC_LEDATA) + strcat (buf, ", ledata"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_TSO) + strcat (buf, ", tso"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_PSO) + strcat (buf, ", pso"); + + if ((e_flags & EF_SPARCV9_MM) == EF_SPARCV9_RMO) + strcat (buf, ", rmo"); + break; + + case EM_PARISC: + switch (e_flags & EF_PARISC_ARCH) + { + case EFA_PARISC_1_0: + strcpy (buf, ", PA-RISC 1.0"); + break; + case EFA_PARISC_1_1: + strcpy (buf, ", PA-RISC 1.1"); + break; + case EFA_PARISC_2_0: + strcpy (buf, ", PA-RISC 2.0"); + break; + default: + break; + } + if (e_flags & EF_PARISC_TRAPNIL) + strcat (buf, ", trapnil"); + if (e_flags & EF_PARISC_EXT) + strcat (buf, ", ext"); + if (e_flags & EF_PARISC_LSB) + strcat (buf, ", lsb"); + if (e_flags & EF_PARISC_WIDE) + strcat (buf, ", wide"); + if (e_flags & EF_PARISC_NO_KABP) + strcat (buf, ", no kabp"); + if (e_flags & EF_PARISC_LAZYSWAP) + strcat (buf, ", lazyswap"); + break; + + case EM_PJ: + if ((e_flags & EF_PICOJAVA_NEWCALLS) == EF_PICOJAVA_NEWCALLS) + strcat (buf, ", new calling convention"); + + if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS) + strcat (buf, ", gnu calling convention"); + break; + } } + + return buf; } static const char * @@ -953,6 +1560,33 @@ get_mips_segment_type (type) return NULL; } +static const char * +get_parisc_segment_type (type) + unsigned long type; +{ + switch (type) + { + case PT_HP_TLS: return "HP_TLS"; + case PT_HP_CORE_NONE: return "HP_CORE_NONE"; + case PT_HP_CORE_VERSION: return "HP_CORE_VERSION"; + case PT_HP_CORE_KERNEL: return "HP_CORE_KERNEL"; + case PT_HP_CORE_COMM: return "HP_CORE_COMM"; + case PT_HP_CORE_PROC: return "HP_CORE_PROC"; + case PT_HP_CORE_LOADABLE: return "HP_CORE_LOADABLE"; + case PT_HP_CORE_STACK: return "HP_CORE_STACK"; + case PT_HP_CORE_SHM: return "HP_CORE_SHM"; + case PT_HP_CORE_MMF: return "HP_CORE_MMF"; + case PT_HP_PARALLEL: return "HP_PARALLEL"; + case PT_HP_FASTBIND: return "HP_FASTBIND"; + case PT_PARISC_ARCHEXT: return "PARISC_ARCHEXT"; + case PT_PARISC_UNWIND: return "PARISC_UNWIND"; + default: + break; + } + + return NULL; +} + static const char * get_segment_type (p_type) unsigned long p_type; @@ -973,25 +1607,45 @@ get_segment_type (p_type) if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) { const char * result; - + switch (elf_header.e_machine) { case EM_MIPS: case EM_MIPS_RS4_BE: result = get_mips_segment_type (p_type); break; + case EM_PARISC: + result = get_parisc_segment_type (p_type); + break; default: result = NULL; break; } - + if (result != NULL) return result; - + sprintf (buff, "LOPROC+%lx", p_type - PT_LOPROC); } else if ((p_type >= PT_LOOS) && (p_type <= PT_HIOS)) - sprintf (buff, "LOOS+%lx", p_type - PT_LOOS); + { + const char * result; + + switch (elf_header.e_machine) + { + case EM_PARISC: + result = get_parisc_segment_type (p_type); + break; + default: + result = NULL; + break; + } + + if (result != NULL) + return result; + + sprintf (buff, "LOOS+%lx", p_type - PT_LOOS); + } else sprintf (buff, _(": %lx"), p_type); @@ -1050,6 +1704,21 @@ get_mips_section_type_name (sh_type) return NULL; } +static const char * +get_parisc_section_type_name (sh_type) + unsigned int sh_type; +{ + switch (sh_type) + { + case SHT_PARISC_EXT: return "PARISC_EXT"; + case SHT_PARISC_UNWIND: return "PARISC_UNWIND"; + case SHT_PARISC_DOC: return "PARISC_DOC"; + default: + break; + } + return NULL; +} + static const char * get_section_type_name (sh_type) unsigned int sh_type; @@ -1070,6 +1739,9 @@ get_section_type_name (sh_type) case SHT_REL: return "REL"; case SHT_SHLIB: return "SHLIB"; case SHT_DYNSYM: return "DYNSYM"; + case SHT_INIT_ARRAY: return "INIT_ARRAY"; + case SHT_FINI_ARRAY: return "FINI_ARRAY"; + case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; case SHT_GNU_verdef: return "VERDEF"; case SHT_GNU_verneed: return "VERNEED"; case SHT_GNU_versym: return "VERSYM"; @@ -1089,6 +1761,9 @@ get_section_type_name (sh_type) case EM_MIPS_RS4_BE: result = get_mips_section_type_name (sh_type); break; + case EM_PARISC: + result = get_parisc_section_type_name (sh_type); + break; default: result = NULL; break; @@ -1105,7 +1780,7 @@ get_section_type_name (sh_type) sprintf (buff, "SHT_LOUSER+%x", sh_type - SHT_LOUSER); else sprintf (buff, _(": %x"), sh_type); - + return buff; } } @@ -1116,14 +1791,16 @@ struct option options [] = {"file-header", no_argument, 0, 'h'}, {"program-headers", no_argument, 0, 'l'}, {"headers", no_argument, 0, 'e'}, - {"histogram", no_argument, & do_histogram, 1}, + {"histogram", no_argument, 0, 'I'}, {"segments", no_argument, 0, 'l'}, {"sections", no_argument, 0, 'S'}, {"section-headers", no_argument, 0, 'S'}, {"symbols", no_argument, 0, 's'}, {"syms", no_argument, 0, 's'}, {"relocs", no_argument, 0, 'r'}, + {"notes", no_argument, 0, 'n'}, {"dynamic", no_argument, 0, 'd'}, + {"arch-specific", no_argument, 0, 'A'}, {"version-info", no_argument, 0, 'V'}, {"use-dynamic", no_argument, 0, 'D'}, {"hex-dump", required_argument, 0, 'x'}, @@ -1142,7 +1819,7 @@ usage () { fprintf (stdout, _("Usage: readelf {options} elf-file(s)\n")); fprintf (stdout, _(" Options are:\n")); - fprintf (stdout, _(" -a or --all Equivalent to: -h -l -S -s -r -d -V --histogram\n")); + fprintf (stdout, _(" -a or --all Equivalent to: -h -l -S -s -r -d -V -A -I\n")); fprintf (stdout, _(" -h or --file-header Display the ELF file header\n")); fprintf (stdout, _(" -l or --program-headers or --segments\n")); fprintf (stdout, _(" Display the program headers\n")); @@ -1150,9 +1827,11 @@ usage () fprintf (stdout, _(" Display the sections' header\n")); fprintf (stdout, _(" -e or --headers Equivalent to: -h -l -S\n")); fprintf (stdout, _(" -s or --syms or --symbols Display the symbol table\n")); + fprintf (stdout, _(" -n or --notes Display the core notes (if present)\n")); fprintf (stdout, _(" -r or --relocs Display the relocations (if present)\n")); fprintf (stdout, _(" -d or --dynamic Display the dynamic segment (if present)\n")); fprintf (stdout, _(" -V or --version-info Display the version sections (if present)\n")); + fprintf (stdout, _(" -A or --arch-specific Display architecture specific information (if any).\n")); fprintf (stdout, _(" -D or --use-dynamic Use the dynamic section info when displaying symbols\n")); fprintf (stdout, _(" -x or --hex-dump=\n")); fprintf (stdout, _(" Dump the contents of section \n")); @@ -1162,10 +1841,10 @@ usage () fprintf (stdout, _(" -i or --instruction-dump=\n")); fprintf (stdout, _(" Disassemble the contents of section \n")); #endif - fprintf (stdout, _(" --histogram Display histogram of bucket list lengths\n")); + fprintf (stdout, _(" -I or --histogram Display histogram of bucket list lengths\n")); fprintf (stdout, _(" -v or --version Display the version number of readelf\n")); fprintf (stdout, _(" -H or --help Display this information\n")); - fprintf (stdout, _("Report bugs to bug-gnu-utils@gnu.org\n")); + fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); exit (0); } @@ -1212,7 +1891,7 @@ parse_args (argc, argv) usage (); while ((c = getopt_long - (argc, argv, "ersahldSDw::x:i:vV", options, NULL)) != EOF) + (argc, argv, "ersahnldSDAIw::x:i:vV", options, NULL)) != EOF) { char * cp; int section; @@ -1235,12 +1914,17 @@ parse_args (argc, argv) do_segments ++; do_version ++; do_histogram ++; + do_arch ++; + do_notes ++; break; case 'e': do_header ++; do_sections ++; do_segments ++; break; + case 'A': + do_arch ++; + break; case 'D': do_using_dynamic ++; break; @@ -1262,6 +1946,12 @@ parse_args (argc, argv) case 'd': do_dynamic ++; break; + case 'I': + do_histogram ++; + break; + case 'n': + do_notes ++; + break; case 'x': do_dump ++; section = strtoul (optarg, & cp, 0); @@ -1340,7 +2030,7 @@ parse_args (argc, argv) if (!do_dynamic && !do_syms && !do_reloc && !do_sections && !do_segments && !do_header && !do_dump && !do_version - && !do_histogram && !do_debugging) + && !do_histogram && !do_debugging && !do_arch && !do_notes) usage (); else if (argc < 3) { @@ -1353,12 +2043,16 @@ static const char * get_elf_class (elf_class) unsigned char elf_class; { + static char buff [32]; + switch (elf_class) { case ELFCLASSNONE: return _("none"); case ELFCLASS32: return _("ELF32"); case ELFCLASS64: return _("ELF64"); - default: return _(""); + default: + sprintf (buff, _(""), elf_class); + return buff; } } @@ -1366,12 +2060,16 @@ static const char * get_data_encoding (encoding) unsigned char encoding; { + static char buff [32]; + switch (encoding) { case ELFDATANONE: return _("none"); case ELFDATA2LSB: return _("2's complement, little endian"); case ELFDATA2MSB: return _("2's complement, big endian"); - default: return _(""); + default: + sprintf (buff, _(""), encoding); + return buff; } } @@ -1379,12 +2077,27 @@ static const char * get_osabi_name (osabi) unsigned char osabi; { + static char buff [32]; + switch (osabi) { - case ELFOSABI_SYSV: return _("UNIX - System V"); + case ELFOSABI_NONE: return _("UNIX - System V"); case ELFOSABI_HPUX: return _("UNIX - HP-UX"); + case ELFOSABI_NETBSD: return _("UNIX - NetBSD"); + case ELFOSABI_LINUX: return _("UNIX - Linux"); + case ELFOSABI_HURD: return _("GNU/Hurd"); + case ELFOSABI_SOLARIS: return _("UNIX - Solaris"); + case ELFOSABI_MONTEREY: return _("UNIX - Monterey"); + case ELFOSABI_IRIX: return _("UNIX - IRIX"); + case ELFOSABI_FREEBSD: return _("UNIX - FreeBSD"); + case ELFOSABI_TRU64: return _("UNIX - TRU64"); + case ELFOSABI_MODESTO: return _("Novell - Modesto"); + case ELFOSABI_OPENBSD: return _("UNIX - OpenBSD"); case ELFOSABI_STANDALONE: return _("Standalone App"); - default: return _(""); + case ELFOSABI_ARM: return _("ARM"); + default: + sprintf (buff, _(""), osabi); + return buff; } } @@ -1417,8 +2130,11 @@ process_file_header () get_data_encoding (elf_header.e_ident [EI_DATA])); printf (_(" Version: %d %s\n"), elf_header.e_ident [EI_VERSION], - elf_header.e_ident [EI_VERSION] == EV_CURRENT ? "(current)" : - elf_header.e_ident [EI_VERSION] != EV_NONE ? "" : ""); + (elf_header.e_ident [EI_VERSION] == EV_CURRENT + ? "(current)" + : (elf_header.e_ident [EI_VERSION] != EV_NONE + ? "" + : ""))); printf (_(" OS/ABI: %s\n"), get_osabi_name (elf_header.e_ident [EI_OSABI])); printf (_(" ABI Version: %d\n"), @@ -1429,14 +2145,15 @@ process_file_header () get_machine_name (elf_header.e_machine)); printf (_(" Version: 0x%lx\n"), (unsigned long) elf_header.e_version); - printf (_(" Data: %s\n"), - get_machine_data (elf_header.e_ident [EI_DATA])); - printf (_(" Entry point address: 0x%lx\n"), - (unsigned long) elf_header.e_entry); - printf (_(" Start of program headers: %ld (bytes into file)\n"), - (long) elf_header.e_phoff); - printf (_(" Start of section headers: %ld (bytes into file)\n"), - (long) elf_header.e_shoff); + + printf (_(" Entry point address: ")); + print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); + printf (_("\n Start of program headers: ")); + print_vma ((bfd_vma) elf_header.e_phoff, DEC); + printf (_(" (bytes into file)\n Start of section headers: ")); + print_vma ((bfd_vma) elf_header.e_shoff, DEC); + printf (_(" (bytes into file)\n")); + printf (_(" Flags: 0x%lx%s\n"), (unsigned long) elf_header.e_flags, get_machine_flags (elf_header.e_flags, elf_header.e_machine)); @@ -1454,28 +2171,83 @@ process_file_header () (long) elf_header.e_shstrndx); } - /* Test class after dumping header so that at least the header can be - display on 64 bit binaries. */ - - binary_class = elf_header.e_ident [EI_CLASS]; - if (binary_class != ELFCLASS32) + return 1; +} + + +static int +get_32bit_program_headers (file, program_headers) + FILE * file; + Elf_Internal_Phdr * program_headers; +{ + Elf32_External_Phdr * phdrs; + Elf32_External_Phdr * external; + Elf32_Internal_Phdr * internal; + unsigned int i; + + GET_DATA_ALLOC (elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + phdrs, Elf32_External_Phdr *, "program headers"); + + for (i = 0, internal = program_headers, external = phdrs; + i < elf_header.e_phnum; + i ++, internal ++, external ++) { - error (_("Not a 32 bit ELF file\n")); - return 0; + internal->p_type = BYTE_GET (external->p_type); + internal->p_offset = BYTE_GET (external->p_offset); + internal->p_vaddr = BYTE_GET (external->p_vaddr); + internal->p_paddr = BYTE_GET (external->p_paddr); + internal->p_filesz = BYTE_GET (external->p_filesz); + internal->p_memsz = BYTE_GET (external->p_memsz); + internal->p_flags = BYTE_GET (external->p_flags); + internal->p_align = BYTE_GET (external->p_align); } + free (phdrs); + return 1; } +static int +get_64bit_program_headers (file, program_headers) + FILE * file; + Elf_Internal_Phdr * program_headers; +{ + Elf64_External_Phdr * phdrs; + Elf64_External_Phdr * external; + Elf64_Internal_Phdr * internal; + unsigned int i; + + GET_DATA_ALLOC (elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + phdrs, Elf64_External_Phdr *, "program headers"); + + for (i = 0, internal = program_headers, external = phdrs; + i < elf_header.e_phnum; + i ++, internal ++, external ++) + { + internal->p_type = BYTE_GET (external->p_type); + internal->p_flags = BYTE_GET (external->p_flags); + internal->p_offset = BYTE_GET8 (external->p_offset); + internal->p_vaddr = BYTE_GET8 (external->p_vaddr); + internal->p_paddr = BYTE_GET8 (external->p_paddr); + internal->p_filesz = BYTE_GET8 (external->p_filesz); + internal->p_memsz = BYTE_GET8 (external->p_memsz); + internal->p_align = BYTE_GET8 (external->p_align); + } + + free (phdrs); + + return 1; +} static int process_program_headers (file) FILE * file; { - Elf32_External_Phdr * phdrs; - Elf32_Internal_Phdr * program_headers; - Elf32_Internal_Phdr * segment; - unsigned int i; + Elf_Internal_Phdr * program_headers; + Elf_Internal_Phdr * segment; + unsigned int i; if (elf_header.e_phnum == 0) { @@ -1486,18 +2258,17 @@ process_program_headers (file) if (do_segments && !do_header) { - printf (_("\nElf file is %s\n"), get_file_type (elf_header.e_type)); - printf (_("Entry point 0x%lx\n"), (unsigned long) elf_header.e_entry); - printf (_("There are %d program headers, starting at offset %lx:\n"), - elf_header.e_phnum, (unsigned long) elf_header.e_phoff); + printf (_("\nElf file type is %s\n"), get_file_type (elf_header.e_type)); + printf (_("Entry point ")); + print_vma ((bfd_vma) elf_header.e_entry, PREFIX_HEX); + printf (_("\nThere are %d program headers, starting at offset "), + elf_header.e_phnum); + print_vma ((bfd_vma) elf_header.e_phoff, DEC); + printf ("\n"); } - GET_DATA_ALLOC (elf_header.e_phoff, - elf_header.e_phentsize * elf_header.e_phnum, - phdrs, Elf32_External_Phdr *, "program headers"); - - program_headers = (Elf32_Internal_Phdr *) malloc - (elf_header.e_phnum * sizeof (Elf32_Internal_Phdr)); + program_headers = (Elf_Internal_Phdr *) malloc + (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); if (program_headers == NULL) { @@ -1505,28 +2276,32 @@ process_program_headers (file) return 0; } - for (i = 0, segment = program_headers; - i < elf_header.e_phnum; - i ++, segment ++) + if (is_32bit_elf) + i = get_32bit_program_headers (file, program_headers); + else + i = get_64bit_program_headers (file, program_headers); + + if (i == 0) { - segment->p_type = BYTE_GET (phdrs[i].p_type); - segment->p_offset = BYTE_GET (phdrs[i].p_offset); - segment->p_vaddr = BYTE_GET (phdrs[i].p_vaddr); - segment->p_paddr = BYTE_GET (phdrs[i].p_paddr); - segment->p_filesz = BYTE_GET (phdrs[i].p_filesz); - segment->p_memsz = BYTE_GET (phdrs[i].p_memsz); - segment->p_flags = BYTE_GET (phdrs[i].p_flags); - segment->p_align = BYTE_GET (phdrs[i].p_align); + free (program_headers); + return 0; } - free (phdrs); - if (do_segments) { printf (_("\nProgram Header%s:\n"), elf_header.e_phnum > 1 ? "s" : ""); - printf - (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + + if (is_32bit_elf) + printf + (_(" Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align\n")); + else + { + printf + (_(" Type Offset VirtAddr PhysAddr\n")); + printf + (_(" FileSiz MemSiz Flags Align\n")); + } } loadaddr = -1; @@ -1539,17 +2314,38 @@ process_program_headers (file) { if (do_segments) { - printf (" %-11.11s ", get_segment_type (segment->p_type)); - printf ("0x%6.6lx ", (unsigned long) segment->p_offset); - printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr); - printf ("0x%8.8lx ", (unsigned long) segment->p_paddr); - printf ("0x%5.5lx ", (unsigned long) segment->p_filesz); - printf ("0x%5.5lx ", (unsigned long) segment->p_memsz); - printf ("%c%c%c ", - (segment->p_flags & PF_R ? 'R' : ' '), - (segment->p_flags & PF_W ? 'W' : ' '), - (segment->p_flags & PF_X ? 'E' : ' ')); - printf ("%#lx", (unsigned long) segment->p_align); + printf (" %-14.14s ", get_segment_type (segment->p_type)); + + if (is_32bit_elf) + { + printf ("0x%6.6lx ", (unsigned long) segment->p_offset); + printf ("0x%8.8lx ", (unsigned long) segment->p_vaddr); + printf ("0x%8.8lx ", (unsigned long) segment->p_paddr); + printf ("0x%5.5lx ", (unsigned long) segment->p_filesz); + printf ("0x%5.5lx ", (unsigned long) segment->p_memsz); + printf ("%c%c%c ", + (segment->p_flags & PF_R ? 'R' : ' '), + (segment->p_flags & PF_W ? 'W' : ' '), + (segment->p_flags & PF_X ? 'E' : ' ')); + printf ("%#lx", (unsigned long) segment->p_align); + } + else + { + print_vma (segment->p_offset, FULL_HEX); + putchar (' '); + print_vma (segment->p_vaddr, FULL_HEX); + putchar (' '); + print_vma (segment->p_paddr, FULL_HEX); + printf ("\n "); + print_vma (segment->p_filesz, FULL_HEX); + putchar (' '); + print_vma (segment->p_memsz, FULL_HEX); + printf (" %c%c%c ", + (segment->p_flags & PF_R ? 'R' : ' '), + (segment->p_flags & PF_W ? 'W' : ' '), + (segment->p_flags & PF_X ? 'E' : ' ')); + print_vma (segment->p_align, HEX); + } } switch (segment->p_type) @@ -1569,7 +2365,7 @@ process_program_headers (file) break; case PT_INTERP: - if (fseek (file, segment->p_offset, SEEK_SET)) + if (fseek (file, (long) segment->p_offset, SEEK_SET)) error (_("Unable to find program interpreter name\n")); else { @@ -1602,8 +2398,8 @@ process_program_headers (file) for (i = 0; i < elf_header.e_phnum; i++) { - int j; - Elf32_Internal_Shdr * section; + int j; + Elf_Internal_Shdr * section; segment = program_headers + i; section = section_headers; @@ -1619,7 +2415,7 @@ process_program_headers (file) ? (section->sh_addr >= segment->p_vaddr && section->sh_addr + section->sh_size <= segment->p_vaddr + segment->p_memsz) - : (section->sh_offset >= segment->p_offset + : ((bfd_vma) section->sh_offset >= segment->p_offset && (section->sh_offset + section->sh_size <= segment->p_offset + segment->p_filesz)))) printf ("%s ", SECTION_NAME (section)); @@ -1636,7 +2432,7 @@ process_program_headers (file) static int -get_section_headers (file) +get_32bit_section_headers (file) FILE * file; { Elf32_External_Shdr * shdrs; @@ -1647,8 +2443,8 @@ get_section_headers (file) elf_header.e_shentsize * elf_header.e_shnum, shdrs, Elf32_External_Shdr *, "section headers"); - section_headers = (Elf32_Internal_Shdr *) malloc - (elf_header.e_shnum * sizeof (Elf32_Internal_Shdr)); + section_headers = (Elf_Internal_Shdr *) malloc + (elf_header.e_shnum * sizeof (Elf_Internal_Shdr)); if (section_headers == NULL) { @@ -1677,8 +2473,50 @@ get_section_headers (file) return 1; } +static int +get_64bit_section_headers (file) + FILE * file; +{ + Elf64_External_Shdr * shdrs; + Elf64_Internal_Shdr * internal; + unsigned int i; + + GET_DATA_ALLOC (elf_header.e_shoff, + elf_header.e_shentsize * elf_header.e_shnum, + shdrs, Elf64_External_Shdr *, "section headers"); + + section_headers = (Elf_Internal_Shdr *) malloc + (elf_header.e_shnum * sizeof (Elf_Internal_Shdr)); + + if (section_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + for (i = 0, internal = section_headers; + i < elf_header.e_shnum; + i ++, internal ++) + { + internal->sh_name = BYTE_GET (shdrs[i].sh_name); + internal->sh_type = BYTE_GET (shdrs[i].sh_type); + internal->sh_flags = BYTE_GET8 (shdrs[i].sh_flags); + internal->sh_addr = BYTE_GET8 (shdrs[i].sh_addr); + internal->sh_size = BYTE_GET8 (shdrs[i].sh_size); + internal->sh_entsize = BYTE_GET8 (shdrs[i].sh_entsize); + internal->sh_link = BYTE_GET (shdrs[i].sh_link); + internal->sh_info = BYTE_GET (shdrs[i].sh_info); + internal->sh_offset = BYTE_GET (shdrs[i].sh_offset); + internal->sh_addralign = BYTE_GET (shdrs[i].sh_addralign); + } + + free (shdrs); + + return 1; +} + static Elf_Internal_Sym * -get_elf_symbols (file, offset, number) +get_32bit_elf_symbols (file, offset, number) FILE * file; unsigned long offset; unsigned long number; @@ -1718,12 +2556,99 @@ get_elf_symbols (file, offset, number) return isyms; } +static Elf_Internal_Sym * +get_64bit_elf_symbols (file, offset, number) + FILE * file; + unsigned long offset; + unsigned long number; +{ + Elf64_External_Sym * esyms; + Elf_Internal_Sym * isyms; + Elf_Internal_Sym * psym; + unsigned int j; + + GET_DATA_ALLOC (offset, number * sizeof (Elf64_External_Sym), + esyms, Elf64_External_Sym *, "symbols"); + + isyms = (Elf_Internal_Sym *) malloc (number * sizeof (Elf_Internal_Sym)); + + if (isyms == NULL) + { + error (_("Out of memory\n")); + free (esyms); + + return NULL; + } + + for (j = 0, psym = isyms; + j < number; + j ++, psym ++) + { + psym->st_name = BYTE_GET (esyms[j].st_name); + psym->st_info = BYTE_GET (esyms[j].st_info); + psym->st_other = BYTE_GET (esyms[j].st_other); + psym->st_shndx = BYTE_GET (esyms[j].st_shndx); + psym->st_value = BYTE_GET8 (esyms[j].st_value); + psym->st_size = BYTE_GET8 (esyms[j].st_size); + } + + free (esyms); + + return isyms; +} + +static const char * +get_elf_section_flags (sh_flags) + bfd_vma sh_flags; +{ + static char buff [32]; + + * buff = 0; + + while (sh_flags) + { + bfd_vma flag; + + flag = sh_flags & - sh_flags; + sh_flags &= ~ flag; + + switch (flag) + { + case SHF_WRITE: strcat (buff, "W"); break; + case SHF_ALLOC: strcat (buff, "A"); break; + case SHF_EXECINSTR: strcat (buff, "X"); break; + case SHF_MERGE: strcat (buff, "M"); break; + case SHF_STRINGS: strcat (buff, "S"); break; + case SHF_INFO_LINK: strcat (buff, "I"); break; + case SHF_LINK_ORDER: strcat (buff, "L"); break; + case SHF_OS_NONCONFORMING: strcat (buff, "O"); break; + + default: + if (flag & SHF_MASKOS) + { + strcat (buff, "o"); + sh_flags &= ~ SHF_MASKOS; + } + else if (flag & SHF_MASKPROC) + { + strcat (buff, "p"); + sh_flags &= ~ SHF_MASKPROC; + } + else + strcat (buff, "x"); + break; + } + } + + return buff; +} + static int process_section_headers (file) FILE * file; { - Elf32_Internal_Shdr * section; - int i; + Elf_Internal_Shdr * section; + int i; section_headers = NULL; @@ -1736,10 +2661,15 @@ process_section_headers (file) } if (do_sections && !do_header) - printf (_("There are %d section headers, starting at offset %lx:\n"), + printf (_("There are %d section headers, starting at offset 0x%lx:\n"), elf_header.e_shnum, (unsigned long) elf_header.e_shoff); - if (! get_section_headers (file)) + if (is_32bit_elf) + { + if (! get_32bit_section_headers (file)) + return 0; + } + else if (! get_64bit_section_headers (file)) return 0; /* Read in the string table, so that we have names to display. */ @@ -1760,6 +2690,7 @@ process_section_headers (file) dynamic_symbols = NULL; dynamic_strings = NULL; dynamic_syminfo = NULL; + for (i = 0, section = section_headers; i < elf_header.e_shnum; i ++, section ++) @@ -1774,9 +2705,9 @@ process_section_headers (file) continue; } - dynamic_symbols = get_elf_symbols - (file, section->sh_offset, - section->sh_size / section->sh_entsize); + num_dynamic_syms = section->sh_size / section->sh_entsize; + dynamic_symbols = + GET_ELF_SYMBOLS (file, section->sh_offset, num_dynamic_syms); } else if (section->sh_type == SHT_STRTAB && strcmp (name, ".dynstr") == 0) @@ -1811,8 +2742,15 @@ process_section_headers (file) return 1; printf (_("\nSection Header%s:\n"), elf_header.e_shnum > 1 ? "s" : ""); - printf - (_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n")); + + if (is_32bit_elf) + printf + (_(" [Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n")); + else + { + printf (_(" [Nr] Name Type Address Offset\n")); + printf (_(" Size EntSize Flags Link Info Align\n")); + } for (i = 0, section = section_headers; i < elf_header.e_shnum; @@ -1823,21 +2761,45 @@ process_section_headers (file) SECTION_NAME (section), get_section_type_name (section->sh_type)); - printf ( "%8.8lx %6.6lx %6.6lx %2.2lx", - (unsigned long) section->sh_addr, - (unsigned long) section->sh_offset, - (unsigned long) section->sh_size, - (unsigned long) section->sh_entsize); - - printf (" %c%c%c %2ld %3lx %ld\n", - (section->sh_flags & SHF_WRITE ? 'W' : ' '), - (section->sh_flags & SHF_ALLOC ? 'A' : ' '), - (section->sh_flags & SHF_EXECINSTR ? 'X' : ' '), - (unsigned long) section->sh_link, - (unsigned long) section->sh_info, - (unsigned long) section->sh_addralign); + if (is_32bit_elf) + { + print_vma (section->sh_addr, LONG_HEX); + + printf ( " %6.6lx %6.6lx %2.2lx", + (unsigned long) section->sh_offset, + (unsigned long) section->sh_size, + (unsigned long) section->sh_entsize); + + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf (" %2ld %3lx %ld\n", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } + else + { + putchar (' '); + print_vma (section->sh_addr, LONG_HEX); + printf (" %8.8lx", section->sh_offset); + printf ("\n "); + print_vma (section->sh_size, LONG_HEX); + printf (" "); + print_vma (section->sh_entsize, LONG_HEX); + + printf (" %3s ", get_elf_section_flags (section->sh_flags)); + + printf (" %2ld %3lx %ld\n", + (unsigned long) section->sh_link, + (unsigned long) section->sh_info, + (unsigned long) section->sh_addralign); + } } + printf (_("Key to Flags: W (write), A (alloc), X (execute), M (merge), S (strings)\n")); + printf (_(" I (info), L (link order), O (extra OS processing required)\n")); + printf (_(" o (os specific), p (processor specific) x (unknown)\n")); + return 1; } @@ -1855,7 +2817,7 @@ process_relocs (file) if (do_using_dynamic) { - int is_rela; + int is_rela = FALSE; rel_size = 0; rel_offset = 0; @@ -1876,7 +2838,19 @@ process_relocs (file) { rel_offset = dynamic_info[DT_JMPREL]; rel_size = dynamic_info[DT_PLTRELSZ]; - is_rela = UNKNOWN; + + switch (dynamic_info[DT_PLTREL]) + { + case DT_REL: + is_rela = FALSE; + break; + case DT_RELA: + is_rela = TRUE; + break; + default: + is_rela = UNKNOWN; + break; + } } if (rel_size) @@ -1886,7 +2860,7 @@ process_relocs (file) rel_offset, rel_size); dump_relocations (file, rel_offset - loadaddr, rel_size, - dynamic_symbols, dynamic_strings, is_rela); + dynamic_symbols, num_dynamic_syms, dynamic_strings, is_rela); } else printf (_("\nThere are no dynamic relocations in this file.\n")); @@ -1915,33 +2889,22 @@ process_relocs (file) Elf_Internal_Sym * symtab; char * strtab; int is_rela; - + unsigned long nsyms; + printf (_("\nRelocation section ")); if (string_table == NULL) - { - printf ("%d", section->sh_name); - is_rela = UNKNOWN; - } + printf ("%d", section->sh_name); else - { - printf ("'%s'", SECTION_NAME (section)); - - if (strncmp (".rela.", SECTION_NAME (section), 6) == 0) - is_rela = TRUE; - else if (strncmp (".rel.", SECTION_NAME (section), 5) == 0) - is_rela = FALSE; - else - is_rela = UNKNOWN; - } + printf ("'%s'", SECTION_NAME (section)); printf (_(" at offset 0x%lx contains %lu entries:\n"), rel_offset, (unsigned long) (rel_size / section->sh_entsize)); symsec = section_headers + section->sh_link; - symtab = get_elf_symbols (file, symsec->sh_offset, - symsec->sh_size / symsec->sh_entsize); + nsyms = symsec->sh_size / symsec->sh_entsize; + symtab = GET_ELF_SYMBOLS (file, symsec->sh_offset, nsyms); if (symtab == NULL) continue; @@ -1951,7 +2914,9 @@ process_relocs (file) GET_DATA_ALLOC (strsec->sh_offset, strsec->sh_size, strtab, char *, "string table"); - dump_relocations (file, rel_offset, rel_size, symtab, strtab, is_rela); + is_rela = section->sh_type == SHT_RELA; + + dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela); free (strtab); free (symtab); @@ -1998,7 +2963,7 @@ dynamic_segment_mips_val (entry) puts (""); } break; - + case DT_MIPS_IVERSION: if (dynamic_strings != NULL) printf ("Interface Version: %s\n", @@ -2006,16 +2971,21 @@ dynamic_segment_mips_val (entry) else printf ("%ld\n", (long) entry->d_un.d_ptr); break; - + case DT_MIPS_TIME_STAMP: { char timebuf[20]; + struct tm * tmp; + time_t time = entry->d_un.d_val; - strftime (timebuf, 20, "%Y-%m-%dT%H:%M:%S", gmtime (&time)); + tmp = gmtime (&time); + sprintf (timebuf, "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); printf ("Time Stamp: %s\n", timebuf); } break; - + case DT_MIPS_RLD_VERSION: case DT_MIPS_LOCAL_GOTNO: case DT_MIPS_CONFLICTNO: @@ -2031,37 +3001,126 @@ dynamic_segment_mips_val (entry) case DT_MIPS_COMPACT_SIZE: printf ("%ld\n", (long) entry->d_un.d_ptr); break; - + default: printf ("%#lx\n", (long) entry->d_un.d_ptr); } } -/* Parse the dynamic segment */ + +static void +dynamic_segment_parisc_val (entry) + Elf_Internal_Dyn * entry; +{ + switch (entry->d_tag) + { + case DT_HP_DLD_FLAGS: + { + static struct + { + long int bit; + const char * str; + } + flags[] = + { + { DT_HP_DEBUG_PRIVATE, "HP_DEBUG_PRIVATE" }, + { DT_HP_DEBUG_CALLBACK, "HP_DEBUG_CALLBACK" }, + { DT_HP_DEBUG_CALLBACK_BOR, "HP_DEBUG_CALLBACK_BOR" }, + { DT_HP_NO_ENVVAR, "HP_NO_ENVVAR" }, + { DT_HP_BIND_NOW, "HP_BIND_NOW" }, + { DT_HP_BIND_NONFATAL, "HP_BIND_NONFATAL" }, + { DT_HP_BIND_VERBOSE, "HP_BIND_VERBOSE" }, + { DT_HP_BIND_RESTRICTED, "HP_BIND_RESTRICTED" }, + { DT_HP_BIND_SYMBOLIC, "HP_BIND_SYMBOLIC" }, + { DT_HP_RPATH_FIRST, "HP_RPATH_FIRST" }, + { DT_HP_BIND_DEPTH_FIRST, "HP_BIND_DEPTH_FIRST" } + }; + int first = 1; + size_t cnt; + bfd_vma val = entry->d_un.d_val; + + for (cnt = 0; cnt < sizeof (flags) / sizeof (flags[0]); ++cnt) + if (val & flags[cnt].bit) + { + if (! first) + putchar (' '); + fputs (flags[cnt].str, stdout); + first = 0; + val ^= flags[cnt].bit; + } + + if (val != 0 || first) + { + if (! first) + putchar (' '); + print_vma (val, HEX); + } + } + break; + + default: + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + break; + } +} + static int -process_dynamic_segment (file) +get_32bit_dynamic_segment (file) FILE * file; { - Elf_Internal_Dyn * entry; - Elf32_External_Dyn * edyn; - unsigned int i; + Elf32_External_Dyn * edyn; + Elf_Internal_Dyn * entry; + bfd_size_type i; - if (dynamic_size == 0) + GET_DATA_ALLOC (dynamic_addr, dynamic_size, + edyn, Elf32_External_Dyn *, "dynamic segment"); + + /* SGI's ELF has more than one section in the DYNAMIC segment. Determine + how large this .dynamic is now. We can do this even before the byte + swapping since the DT_NULL tag is recognizable. */ + dynamic_size = 0; + while (*(Elf32_Word *) edyn [dynamic_size++].d_tag != DT_NULL) + ; + + dynamic_segment = (Elf_Internal_Dyn *) + malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); + + if (dynamic_segment == NULL) { - if (do_dynamic) - printf (_("\nThere is no dynamic segment in this file.\n")); + error (_("Out of memory\n")); + free (edyn); + return 0; + } - return 1; + for (i = 0, entry = dynamic_segment; + i < dynamic_size; + i ++, entry ++) + { + entry->d_tag = BYTE_GET (edyn [i].d_tag); + entry->d_un.d_val = BYTE_GET (edyn [i].d_un.d_val); } + free (edyn); + + return 1; +} + +static int +get_64bit_dynamic_segment (file) + FILE * file; +{ + Elf64_External_Dyn * edyn; + Elf_Internal_Dyn * entry; + bfd_size_type i; + GET_DATA_ALLOC (dynamic_addr, dynamic_size, - edyn, Elf32_External_Dyn *, "dynamic segment"); - + edyn, Elf64_External_Dyn *, "dynamic segment"); + /* SGI's ELF has more than one section in the DYNAMIC segment. Determine - how large .dynamic is now. We can do this even before the byte + how large this .dynamic is now. We can do this even before the byte swapping since the DT_NULL tag is recognizable. */ dynamic_size = 0; - while (*(Elf32_Word *) edyn[dynamic_size++].d_tag != DT_NULL) + while (*(bfd_vma *) edyn [dynamic_size ++].d_tag != DT_NULL) ; dynamic_segment = (Elf_Internal_Dyn *) @@ -2078,12 +3137,63 @@ process_dynamic_segment (file) i < dynamic_size; i ++, entry ++) { - entry->d_tag = BYTE_GET (edyn [i].d_tag); - entry->d_un.d_val = BYTE_GET (edyn [i].d_un.d_val); + entry->d_tag = BYTE_GET8 (edyn [i].d_tag); + entry->d_un.d_val = BYTE_GET8 (edyn [i].d_un.d_val); } free (edyn); + return 1; +} + +static const char * +get_dynamic_flags (flags) + bfd_vma flags; +{ + static char buff [64]; + while (flags) + { + bfd_vma flag; + + flag = flags & - flags; + flags &= ~ flag; + + switch (flag) + { + case DF_ORIGIN: strcat (buff, "ORIGIN "); break; + case DF_SYMBOLIC: strcat (buff, "SYMBOLIC "); break; + case DF_TEXTREL: strcat (buff, "TEXTREL "); break; + case DF_BIND_NOW: strcat (buff, "BIND_NOW "); break; + default: strcat (buff, "unknown "); break; + } + } + return buff; +} + +/* Parse and display the contents of the dynamic segment. */ +static int +process_dynamic_segment (file) + FILE * file; +{ + Elf_Internal_Dyn * entry; + bfd_size_type i; + + if (dynamic_size == 0) + { + if (do_dynamic) + printf (_("\nThere is no dynamic segment in this file.\n")); + + return 1; + } + + if (is_32bit_elf) + { + if (! get_32bit_dynamic_segment (file)) + return 0; + } + else if (! get_64bit_dynamic_segment (file)) + return 0; + /* Find the appropriate symbol table. */ if (dynamic_symbols == NULL) { @@ -2092,7 +3202,6 @@ process_dynamic_segment (file) ++i, ++ entry) { unsigned long offset; - long num_syms; if (entry->d_tag != DT_SYMTAB) continue; @@ -2103,21 +3212,23 @@ process_dynamic_segment (file) we default to reading in the entire file (!) and processing that. This is overkill, I know, but it should work. */ - offset = entry->d_un.d_val - loadaddr; if (fseek (file, 0, SEEK_END)) error (_("Unable to seek to end of file!")); - num_syms = (ftell (file) - offset) / sizeof (Elf32_External_Sym); + if (is_32bit_elf) + num_dynamic_syms = (ftell (file) - offset) / sizeof (Elf32_External_Sym); + else + num_dynamic_syms = (ftell (file) - offset) / sizeof (Elf64_External_Sym); - if (num_syms < 1) + if (num_dynamic_syms < 1) { error (_("Unable to determine the number of symbols to load\n")); continue; } - dynamic_symbols = get_elf_symbols (file, offset, num_syms); + dynamic_symbols = GET_ELF_SYMBOLS (file, offset, num_dynamic_syms); } } @@ -2183,8 +3294,8 @@ process_dynamic_segment (file) if (dynamic_syminfo_offset != 0 && syminsz != 0) { - Elf_External_Syminfo *extsyminfo; - Elf_Internal_Syminfo *syminfo; + Elf_External_Syminfo * extsyminfo; + Elf_Internal_Syminfo * syminfo; /* There is a syminfo section. Read the data. */ GET_DATA_ALLOC (dynamic_syminfo_offset, syminsz, extsyminfo, @@ -2210,8 +3321,8 @@ process_dynamic_segment (file) } if (do_dynamic && dynamic_addr) - printf (_("\nDynamic segment at offset 0x%x contains %d entries:\n"), - dynamic_addr, dynamic_size); + printf (_("\nDynamic segment at offset 0x%x contains %ld entries:\n"), + dynamic_addr, (long) dynamic_size); if (do_dynamic) printf (_(" Tag Type Name/Value\n")); @@ -2220,31 +3331,67 @@ process_dynamic_segment (file) i++, entry ++) { if (do_dynamic) - printf (_(" 0x%-8.8lx (%s)%*s"), - (unsigned long) entry->d_tag, - get_dynamic_type (entry->d_tag), - 27 - strlen (get_dynamic_type (entry->d_tag)), - " "); + { + const char * dtype; + + putchar (' '); + print_vma (entry->d_tag, FULL_HEX); + dtype = get_dynamic_type (entry->d_tag); + printf (" (%s)%*s", dtype, + ((is_32bit_elf ? 27 : 19) + - (int) strlen (dtype)), + " "); + } switch (entry->d_tag) { + case DT_FLAGS: + if (do_dynamic) + printf ("%s", get_dynamic_flags (entry->d_un.d_val)); + break; + case DT_AUXILIARY: case DT_FILTER: + case DT_CONFIG: + case DT_DEPAUDIT: + case DT_AUDIT: if (do_dynamic) { - if (entry->d_tag == DT_AUXILIARY) - printf (_("Auxiliary library")); - else - printf (_("Filter library")); + switch (entry->d_tag) + { + case DT_AUXILIARY: + printf (_("Auxiliary library")); + break; + + case DT_FILTER: + printf (_("Filter library")); + break; + + case DT_CONFIG: + printf (_("Configuration file")); + break; + + case DT_DEPAUDIT: + printf (_("Dependency audit library")); + break; + + case DT_AUDIT: + printf (_("Audit library")); + break; + } if (dynamic_strings) printf (": [%s]\n", dynamic_strings + entry->d_un.d_val); else - printf (": %#lx\n", (long) entry->d_un.d_val); + { + printf (": "); + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } } break; - case DT_FEATURE_1: + case DT_FEATURE: if (do_dynamic) { printf (_("Flags:")); @@ -2258,6 +3405,11 @@ process_dynamic_segment (file) printf (" PARINIT"); val ^= DTF_1_PARINIT; } + if (val & DTF_1_CONFEXP) + { + printf (" CONFEXP"); + val ^= DTF_1_CONFEXP; + } if (val != 0) printf (" %lx", val); puts (""); @@ -2355,6 +3507,21 @@ process_dynamic_segment (file) printf (" INTERPOSE"); val ^= DF_1_INTERPOSE; } + if (val & DF_1_NODEFLIB) + { + printf (" NODEFLIB"); + val ^= DF_1_NODEFLIB; + } + if (val & DF_1_NODUMP) + { + printf (" NODUMP"); + val ^= DF_1_NODUMP; + } + if (val & DF_1_CONLFAT) + { + printf (" CONLFAT"); + val ^= DF_1_CONLFAT; + } if (val != 0) printf (" %lx", val); puts (""); @@ -2383,6 +3550,7 @@ process_dynamic_segment (file) case DT_DEBUG : case DT_TEXTREL : case DT_JMPREL : + case DT_RUNPATH : dynamic_info[entry->d_tag] = entry->d_un.d_val; if (do_dynamic) @@ -2401,26 +3569,31 @@ process_dynamic_segment (file) case DT_NEEDED: printf (_("Shared library: [%s]"), name); - if (strcmp (name, program_interpreter)) - printf ("\n"); - else - printf (_(" program interpreter\n")); + if (strcmp (name, program_interpreter) == 0) + printf (_(" program interpreter")); break; case DT_SONAME: - printf (_("Library soname: [%s]\n"), name); + printf (_("Library soname: [%s]"), name); break; case DT_RPATH: - printf (_("Library rpath: [%s]\n"), name); + printf (_("Library rpath: [%s]"), name); + break; + + case DT_RUNPATH: + printf (_("Library runpath: [%s]"), name); break; default: - printf ("%#lx\n", (long) entry->d_un.d_val); + print_vma (entry->d_un.d_val, PREFIX_HEX); + break; } } else - printf ("%#lx\n", (long) entry->d_un.d_val); + print_vma (entry->d_un.d_val, PREFIX_HEX); + + putchar ('\n'); } break; @@ -2437,7 +3610,10 @@ process_dynamic_segment (file) case DT_INIT_ARRAYSZ: case DT_FINI_ARRAYSZ: if (do_dynamic) - printf ("%lu (bytes)\n", (unsigned long) entry->d_un.d_val); + { + print_vma (entry->d_un.d_val, UNSIGNED); + printf (" (bytes)\n"); + } break; case DT_VERDEFNUM: @@ -2445,7 +3621,10 @@ process_dynamic_segment (file) case DT_RELACOUNT: case DT_RELCOUNT: if (do_dynamic) - printf ("%lu\n", (unsigned long) entry->d_un.d_val); + { + print_vma (entry->d_un.d_val, UNSIGNED); + putchar ('\n'); + } break; case DT_SYMINSZ: @@ -2468,15 +3647,16 @@ process_dynamic_segment (file) break; } } - - printf ("%#lx\n", (long) entry->d_un.d_val); + + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); } break; case DT_BIND_NOW: /* The value of this entry is ignored. */ break; - + default: if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) version_info [DT_VERSIONTAGIDX (entry->d_tag)] = @@ -2490,8 +3670,12 @@ process_dynamic_segment (file) case EM_MIPS_RS4_BE: dynamic_segment_mips_val (entry); break; + case EM_PARISC: + dynamic_segment_parisc_val (entry); + break; default: - printf ("%#lx\n", (long) entry->d_un.d_ptr); + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); } } break; @@ -2578,7 +3762,7 @@ process_version_sections (file) Elf_Internal_Verdaux aux; int j; int isum; - + vstart = ((char *) edefs) + idx; edef = (Elf_External_Verdef *) vstart; @@ -2635,7 +3819,7 @@ process_version_sections (file) free (edefs); } break; - + case SHT_GNU_verneed: { Elf_External_Verneed * eneed; @@ -2715,7 +3899,7 @@ process_version_sections (file) idx += ent.vn_next; } - + free (eneed); } break; @@ -2736,9 +3920,8 @@ process_version_sections (file) found = 1; - symbols = get_elf_symbols - (file, link_section->sh_offset, - link_section->sh_size / link_section->sh_entsize); + symbols = GET_ELF_SYMBOLS (file, link_section->sh_offset, + link_section->sh_size / link_section->sh_entsize); string_sec = section_headers + link_section->sh_link; @@ -2770,6 +3953,7 @@ process_version_sections (file) for (cnt = 0; cnt < total; cnt += 4) { int j, nn; + char * name; printf (" %03x:", cnt); @@ -2803,8 +3987,8 @@ process_version_sections (file) { Elf_External_Verneed evn; Elf_External_Vernaux evna; - Elf_Internal_Vernaux ivna; - unsigned long vna_off; + Elf_Internal_Vernaux ivna; + unsigned long vna_off; GET_DATA (offset, evn, "version need"); @@ -2830,10 +4014,10 @@ process_version_sections (file) { ivna.vna_name = BYTE_GET (evna.vna_name); + name = strtab + ivna.vna_name; nn += printf ("(%s%-*s", - strtab + ivna.vna_name, - 12 - strlen (strtab - + ivna.vna_name), + name, + 12 - (int) strlen (name), ")"); break; } @@ -2876,12 +4060,11 @@ process_version_sections (file) ivda.vda_name = BYTE_GET (evda.vda_name); + name = strtab + ivda.vda_name; nn += printf ("(%s%-*s", - strtab + ivda.vda_name, - 12 - - strlen (strtab - + ivda.vda_name), + name, + 12 - (int) strlen (name), ")"); } } @@ -2903,10 +4086,10 @@ process_version_sections (file) do { - Elf_Internal_Vernaux ivna; + Elf_Internal_Vernaux ivna; Elf_External_Verneed evn; Elf_External_Vernaux evna; - unsigned long a_off; + unsigned long a_off; GET_DATA (offset, evn, "version need"); @@ -2932,10 +4115,10 @@ process_version_sections (file) { ivna.vna_name = BYTE_GET (evna.vna_name); + name = strtab + ivna.vna_name; nn += printf ("(%s%-*s", - strtab + ivna.vna_name, - 12 - strlen (strtab - + ivna.vna_name), + name, + 12 - (int) strlen (name), ")"); break; } @@ -2977,10 +4160,10 @@ process_version_sections (file) ivda.vda_name = BYTE_GET (evda.vda_name); + name = strtab + ivda.vda_name; nn += printf ("(%s%-*s", - strtab + ivda.vda_name, - 12 - strlen (strtab - + ivda.vda_name), + name, + 12 - (int) strlen (name), ")"); } } @@ -2997,7 +4180,7 @@ process_version_sections (file) free (symbols); } break; - + default: break; } @@ -3009,7 +4192,7 @@ process_version_sections (file) return 1; } -static char * +static const char * get_symbol_binding (binding) unsigned int binding; { @@ -3017,9 +4200,9 @@ get_symbol_binding (binding) switch (binding) { - case STB_LOCAL: return _("LOCAL"); - case STB_GLOBAL: return _("GLOBAL"); - case STB_WEAK: return _("WEAK"); + case STB_LOCAL: return "LOCAL"; + case STB_GLOBAL: return "GLOBAL"; + case STB_WEAK: return "WEAK"; default: if (binding >= STB_LOPROC && binding <= STB_HIPROC) sprintf (buff, _(": %d"), binding); @@ -3031,7 +4214,7 @@ get_symbol_binding (binding) } } -static char * +static const char * get_symbol_type (type) unsigned int type; { @@ -3039,23 +4222,59 @@ get_symbol_type (type) switch (type) { - case STT_NOTYPE: return _("NOTYPE"); - case STT_OBJECT: return _("OBJECT"); - case STT_FUNC: return _("FUNC"); - case STT_SECTION: return _("SECTION"); - case STT_FILE: return _("FILE"); + case STT_NOTYPE: return "NOTYPE"; + case STT_OBJECT: return "OBJECT"; + case STT_FUNC: return "FUNC"; + case STT_SECTION: return "SECTION"; + case STT_FILE: return "FILE"; + case STT_COMMON: return "COMMON"; default: if (type >= STT_LOPROC && type <= STT_HIPROC) - sprintf (buff, _(": %d"), type); + { + if (elf_header.e_machine == EM_ARM && type == STT_ARM_TFUNC) + return "THUMB_FUNC"; + + if (elf_header.e_machine == EM_SPARCV9 && type == STT_REGISTER) + return "REGISTER"; + + if (elf_header.e_machine == EM_PARISC && type == STT_PARISC_MILLI) + return "PARISC_MILLI"; + + sprintf (buff, _(": %d"), type); + } else if (type >= STT_LOOS && type <= STT_HIOS) - sprintf (buff, _(": %d"), type); + { + if (elf_header.e_machine == EM_PARISC) + { + if (type == STT_HP_OPAQUE) + return "HP_OPAQUE"; + if (type == STT_HP_STUB) + return "HP_STUB"; + } + + sprintf (buff, _(": %d"), type); + } else sprintf (buff, _(": %d"), type); return buff; } } -static char * +static const char * +get_symbol_visibility (visibility) + unsigned int visibility; +{ + switch (visibility) + { + case STV_DEFAULT: return "DEFAULT"; + case STV_INTERNAL: return "INTERNAL"; + case STV_HIDDEN: return "HIDDEN"; + case STV_PROTECTED: return "PROTECTED"; + default: abort (); + } +} + +static const char * get_symbol_index_type (type) unsigned int type; { @@ -3081,16 +4300,15 @@ get_symbol_index_type (type) } } - static int * get_dynamic_data (file, number) FILE * file; unsigned int number; { - char * e_data; + unsigned char * e_data; int * i_data; - e_data = (char *) malloc (number * 4); + e_data = (unsigned char *) malloc (number * 4); if (e_data == NULL) { @@ -3127,10 +4345,10 @@ process_symbol_table (file) FILE * file; { Elf32_Internal_Shdr * section; - char nb [4]; - char nc [4]; - int nbuckets; - int nchains; + unsigned char nb [4]; + unsigned char nc [4]; + int nbuckets = 0; + int nchains = 0; int * buckets = NULL; int * chains = NULL; @@ -3175,29 +4393,31 @@ process_symbol_table (file) int si; printf (_("\nSymbol table for image:\n")); - printf (_(" Num Buc: Value Size Type Bind Ot Ndx Name\n")); + if (is_32bit_elf) + printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); + else + printf (_(" Num Buc: Value Size Type Bind Vis Ndx Name\n")); for (hn = 0; hn < nbuckets; hn++) { if (! buckets [hn]) continue; - for (si = buckets [hn]; si; si = chains [si]) + for (si = buckets [hn]; si < nchains && si > 0; si = chains [si]) { Elf_Internal_Sym * psym; psym = dynamic_symbols + si; - printf (" %3d %3d: %8lx %5ld %6s %6s %2d ", - si, hn, - (unsigned long) psym->st_value, - (unsigned long) psym->st_size, - get_symbol_type (ELF_ST_TYPE (psym->st_info)), - get_symbol_binding (ELF_ST_BIND (psym->st_info)), - psym->st_other); - - printf ("%3.3s", get_symbol_index_type (psym->st_shndx)); - + printf (" %3d %3d: ", si, hn); + print_vma (psym->st_value, LONG_HEX); + putchar (' ' ); + print_vma (psym->st_size, DEC_5); + + printf (" %6s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); + printf (" %6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); + printf (" %3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); + printf (" %3.3s", get_symbol_index_type (psym->st_shndx)); printf (" %s\n", dynamic_strings + psym->st_name); } } @@ -3223,10 +4443,12 @@ process_symbol_table (file) printf (_("\nSymbol table '%s' contains %lu entries:\n"), SECTION_NAME (section), (unsigned long) (section->sh_size / section->sh_entsize)); - fputs (_(" Num: Value Size Type Bind Ot Ndx Name\n"), - stdout); + if (is_32bit_elf) + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); + else + printf (_(" Num: Value Size Type Bind Vis Ndx Name\n")); - symtab = get_elf_symbols (file, section->sh_offset, + symtab = GET_ELF_SYMBOLS (file, section->sh_offset, section->sh_size / section->sh_entsize); if (symtab == NULL) continue; @@ -3247,16 +4469,14 @@ process_symbol_table (file) si < section->sh_size / section->sh_entsize; si ++, psym ++) { - printf (" %3d: %8lx %5ld %-7s %-6s %2d ", - si, - (unsigned long) psym->st_value, - (unsigned long) psym->st_size, - get_symbol_type (ELF_ST_TYPE (psym->st_info)), - get_symbol_binding (ELF_ST_BIND (psym->st_info)), - psym->st_other); - - printf ("%4s", get_symbol_index_type (psym->st_shndx)); - + printf ("%6d: ", si); + print_vma (psym->st_value, LONG_HEX); + putchar (' '); + print_vma (psym->st_size, DEC_5); + printf (" %-7s", get_symbol_type (ELF_ST_TYPE (psym->st_info))); + printf (" %-6s", get_symbol_binding (ELF_ST_BIND (psym->st_info))); + printf (" %-3s", get_symbol_visibility (ELF_ST_VISIBILITY (psym->st_other))); + printf (" %4s", get_symbol_index_type (psym->st_shndx)); printf (" %s", strtab + psym->st_name); if (section->sh_type == SHT_DYNSYM && @@ -3294,15 +4514,15 @@ process_symbol_table (file) offset = version_info [DT_VERSIONTAGIDX (DT_VERNEED)] - loadaddr; - GET_DATA (offset, evn, "version need"); - - ivn.vn_aux = BYTE_GET (evn.vn_aux); - ivn.vn_next = BYTE_GET (evn.vn_next); - do { unsigned long vna_off; + GET_DATA (offset, evn, "version need"); + + ivn.vn_aux = BYTE_GET (evn.vn_aux); + ivn.vn_next = BYTE_GET (evn.vn_next); + vna_off = offset + ivn.vn_aux; do @@ -3421,11 +4641,11 @@ process_symbol_table (file) if (! buckets [hn]) continue; - for (si = buckets[hn]; si; si = chains[si]) + for (si = buckets[hn]; si > 0 && si < nchains; si = chains[si]) { - ++nsyms; + ++ nsyms; if (maxlength < ++lengths[hn]) - ++maxlength; + ++ maxlength; } } @@ -3439,14 +4659,17 @@ process_symbol_table (file) for (hn = 0; hn < nbuckets; ++hn) ++ counts [lengths [hn]]; - printf (" 0 %-10d (%5.1f%%)\n", - counts[0], (counts[0] * 100.0) / nbuckets); - for (si = 1; si <= maxlength; ++si) + if (nbuckets > 0) { - nzero_counts += counts[si] * si; - printf ("%7d %-10d (%5.1f%%) %5.1f%%\n", - si, counts[si], (counts[si] * 100.0) / nbuckets, - (nzero_counts * 100.0) / nsyms); + printf (" 0 %-10d (%5.1f%%)\n", + counts[0], (counts[0] * 100.0) / nbuckets); + for (si = 1; si <= maxlength; ++si) + { + nzero_counts += counts[si] * si; + printf ("%7d %-10d (%5.1f%%) %5.1f%%\n", + si, counts[si], (counts[si] * 100.0) / nbuckets, + (nzero_counts * 100.0) / nsyms); + } } free (counts); @@ -3464,9 +4687,9 @@ process_symbol_table (file) static int process_syminfo (file) - FILE * file; + FILE * file ATTRIBUTE_UNUSED; { - int i; + unsigned int i; if (dynamic_syminfo == NULL || !do_dynamic) @@ -3543,8 +4766,8 @@ dump_section (section, file) Elf32_Internal_Shdr * section; FILE * file; { - int bytes; - int addr; + bfd_size_type bytes; + bfd_vma addr; unsigned char * data; unsigned char * start; @@ -3574,10 +4797,11 @@ dump_section (section, file) lbytes = (bytes > 16 ? 16 : bytes); - printf (" 0x%8.8x ", addr); + printf (" 0x%8.8lx ", (unsigned long) addr); switch (elf_header.e_ident [EI_DATA]) { + default: case ELFDATA2LSB: for (j = 15; j >= 0; j --) { @@ -3692,16 +4916,17 @@ reset_state_machine (is_stmt) /* Handled an extend line op. Returns true if this is the end of sequence. */ static int -process_extended_line_op (data, is_stmt) +process_extended_line_op (data, is_stmt, pointer_size) unsigned char * data; int is_stmt; + int pointer_size; { unsigned char op_code; int bytes_read; unsigned int len; unsigned char * name; unsigned long adr; - + len = read_leb128 (data, & bytes_read, 0); data += bytes_read; @@ -3715,7 +4940,7 @@ process_extended_line_op (data, is_stmt) op_code = * data ++; printf (_(" Extended opcode %d: "), op_code); - + switch (op_code) { case DW_LNE_end_sequence: @@ -3724,8 +4949,7 @@ process_extended_line_op (data, is_stmt) break; case DW_LNE_set_address: - /* XXX - assumption here that address size is 4! */ - adr = byte_get (data, 4); + adr = byte_get (data, pointer_size); printf (_("set Address to 0x%lx\n"), adr); state_machine_regs.address = adr; break; @@ -3733,10 +4957,10 @@ process_extended_line_op (data, is_stmt) case DW_LNE_define_file: printf (_(" define new File Table entry\n")); printf (_(" Entry\tDir\tTime\tSize\tName\n")); - + printf (_(" %d\t"), ++ state_machine_regs.last_file_entry); name = data; - data += strlen (data) + 1; + data += strlen ((char *) data) + 1; printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); data += bytes_read; printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); @@ -3753,12 +4977,16 @@ process_extended_line_op (data, is_stmt) return len; } +/* Size of pointers in the .debug_line section. This information is not + really present in that section. It's obtained before dumping the debug + sections by doing some pre-scan of the .debug_info section. */ +static int debug_line_pointer_size = 4; static int display_debug_lines (section, start, file) Elf32_Internal_Shdr * section; unsigned char * start; - FILE * file; + FILE * file ATTRIBUTE_UNUSED; { DWARF2_External_LineInfo * external; DWARF2_Internal_LineInfo info; @@ -3783,7 +5011,7 @@ display_debug_lines (section, start, file) (_("The line info appears to be corrupt - the section is too small\n")); return 0; } - + /* Check its version number. */ info.li_version = BYTE_GET (external->li_version); if (info.li_version != 2) @@ -3791,18 +5019,18 @@ display_debug_lines (section, start, file) warn (_("Only DWARF version 2 line info is currently supported.\n")); return 0; } - + info.li_prologue_length = BYTE_GET (external->li_prologue_length); info.li_min_insn_length = BYTE_GET (external->li_min_insn_length); info.li_default_is_stmt = BYTE_GET (external->li_default_is_stmt); info.li_line_base = BYTE_GET (external->li_line_base); info.li_line_range = BYTE_GET (external->li_line_range); info.li_opcode_base = BYTE_GET (external->li_opcode_base); - + /* Sign extend the line base field. */ info.li_line_base <<= 24; info.li_line_base >>= 24; - + printf (_(" Length: %ld\n"), info.li_length); printf (_(" DWARF Version: %d\n"), info.li_version); printf (_(" Prolgue Length: %d\n"), info.li_prologue_length); @@ -3815,35 +5043,35 @@ display_debug_lines (section, start, file) end_of_sequence = data + info.li_length + sizeof (info.li_length); reset_state_machine (info.li_default_is_stmt); - + /* Display the contents of the Opcodes table. */ standard_opcodes = data + sizeof (* external); - + printf (_("\n Opcodes:\n")); - + for (i = 1; i < info.li_opcode_base; i++) - printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i]); - + printf (_(" Opcode %d has %d args\n"), i, standard_opcodes[i - 1]); + /* Display the contents of the Directory table. */ data = standard_opcodes + info.li_opcode_base - 1; - + if (* data == 0) printf (_("\n The Directory Table is empty.\n")); else { printf (_("\n The Directory Table:\n")); - + while (* data != 0) { printf (_(" %s\n"), data); - - data += strlen (data) + 1; + + data += strlen ((char *) data) + 1; } } - + /* Skip the NUL at the end of the table. */ data ++; - + /* Display the contents of the File Name table. */ if (* data == 0) printf (_("\n The File Name Table is empty.\n")); @@ -3851,17 +5079,17 @@ display_debug_lines (section, start, file) { printf (_("\n The File Name Table:\n")); printf (_(" Entry\tDir\tTime\tSize\tName\n")); - + while (* data != 0) { - char * name; + unsigned char * name; int bytes_read; - + printf (_(" %d\t"), ++ state_machine_regs.last_file_entry); name = data; - - data += strlen (data) + 1; - + + data += strlen ((char *) data) + 1; + printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); data += bytes_read; printf (_("%lu\t"), read_leb128 (data, & bytes_read, 0)); @@ -3871,32 +5099,33 @@ display_debug_lines (section, start, file) printf (_("%s\n"), name); } } - + /* Skip the NUL at the end of the table. */ data ++; - + /* Now display the statements. */ printf (_("\n Line Number Statements:\n")); - - + + while (data < end_of_sequence) { unsigned char op_code; int adv; int bytes_read; - + op_code = * data ++; - + switch (op_code) { case DW_LNS_extended_op: - data += process_extended_line_op (data, info.li_default_is_stmt); + data += process_extended_line_op (data, info.li_default_is_stmt, + debug_line_pointer_size); break; - + case DW_LNS_copy: printf (_(" Copy\n")); break; - + case DW_LNS_advance_pc: adv = info.li_min_insn_length * read_leb128 (data, & bytes_read, 0); data += bytes_read; @@ -3904,7 +5133,7 @@ display_debug_lines (section, start, file) printf (_(" Advance PC by %d to %lx\n"), adv, state_machine_regs.address); break; - + case DW_LNS_advance_line: adv = read_leb128 (data, & bytes_read, 1); data += bytes_read; @@ -3912,7 +5141,7 @@ display_debug_lines (section, start, file) printf (_(" Advance Line by %d to %d\n"), adv, state_machine_regs.line); break; - + case DW_LNS_set_file: adv = read_leb128 (data, & bytes_read, 0); data += bytes_read; @@ -3920,33 +5149,34 @@ display_debug_lines (section, start, file) adv); state_machine_regs.file = adv; break; - + case DW_LNS_set_column: adv = read_leb128 (data, & bytes_read, 0); data += bytes_read; printf (_(" Set column to %d\n"), adv); state_machine_regs.column = adv; break; - + case DW_LNS_negate_stmt: adv = state_machine_regs.is_stmt; adv = ! adv; printf (_(" Set is_stmt to %d\n"), adv); state_machine_regs.is_stmt = adv; break; - + case DW_LNS_set_basic_block: printf (_(" Set basic block\n")); state_machine_regs.basic_block = 1; break; - + case DW_LNS_const_add_pc: - adv = (255 - info.li_opcode_base) / info.li_line_range; + adv = (((255 - info.li_opcode_base) / info.li_line_range) + * info.li_min_insn_length); state_machine_regs.address += adv; printf (_(" Advance PC by constant %d to 0x%lx\n"), adv, state_machine_regs.address); break; - + case DW_LNS_fixed_advance_pc: adv = byte_get (data, 2); data += 2; @@ -3954,14 +5184,14 @@ display_debug_lines (section, start, file) printf (_(" Advance PC by fixed size amount %d to 0x%lx\n"), adv, state_machine_regs.address); break; - + default: op_code -= info.li_opcode_base; adv = (op_code / info.li_line_range) * info.li_min_insn_length; state_machine_regs.address += adv; printf (_(" Special opcode %d: advance Address by %d to 0x%lx"), op_code, adv, state_machine_regs.address); - adv += (op_code % info.li_line_range) + info.li_line_base; + adv = (op_code % info.li_line_range) + info.li_line_base; state_machine_regs.line += adv; printf (_(" and Line by %d to %d\n"), adv, state_machine_regs.line); @@ -3970,7 +5200,7 @@ display_debug_lines (section, start, file) } printf ("\n"); } - + return 1; } @@ -3978,7 +5208,7 @@ static int display_debug_pubnames (section, start, file) Elf32_Internal_Shdr * section; unsigned char * start; - FILE * file; + FILE * file ATTRIBUTE_UNUSED; { DWARF2_External_PubNames * external; DWARF2_Internal_PubNames pubnames; @@ -4005,7 +5235,14 @@ display_debug_pubnames (section, start, file) if (pubnames.pn_version != 2) { - warn (_("Only DWARF 2 pubnames are currently supported")); + static int warned = 0; + + if (! warned) + { + warn (_("Only DWARF 2 pubnames are currently supported\n")); + warned = 1; + } + continue; } @@ -4028,7 +5265,7 @@ display_debug_pubnames (section, start, file) { data += 4; printf (" %ld\t\t%s\n", offset, data); - data += strlen (data) + 1; + data += strlen ((char *) data) + 1; } } while (offset != 0); @@ -4366,8 +5603,11 @@ process_abbrev_section (start, end) entry = read_leb128 (start, & bytes_read, 0); start += bytes_read; + /* A single zero is supposed to end the section according + to the standard. If there's more, then signal that to + the caller. */ if (entry == 0) - return start; + return start == end ? NULL : start; tag = read_leb128 (start, & bytes_read, 0); start += bytes_read; @@ -4400,7 +5640,7 @@ static int display_debug_abbrev (section, start, file) Elf32_Internal_Shdr * section; unsigned char * start; - FILE * file; + FILE * file ATTRIBUTE_UNUSED; { abbrev_entry * entry; unsigned char * end = start + section->sh_size; @@ -4445,212 +5685,343 @@ display_block (data, length) { printf (_(" %lu byte block: "), length); - while (length --) - printf ("%lx ", byte_get (data ++, 1)); + while (length --) + printf ("%lx ", (unsigned long) byte_get (data ++, 1)); + + return data; +} + +static void +decode_location_expression (data, pointer_size, length) + unsigned char * data; + unsigned int pointer_size; + unsigned long length; +{ + unsigned op; + int bytes_read; + unsigned long uvalue; + unsigned char *end = data + length; + + while (data < end) + { + op = * data ++; + + switch (op) + { + case DW_OP_addr: + printf ("DW_OP_addr: %lx", + (unsigned long) byte_get (data, pointer_size)); + data += pointer_size; + break; + case DW_OP_deref: + printf ("DW_OP_deref"); + break; + case DW_OP_const1u: + printf ("DW_OP_const1u: %lu", (unsigned long) byte_get (data++, 1)); + break; + case DW_OP_const1s: + printf ("DW_OP_const1s: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_const2u: + printf ("DW_OP_const2u: %lu", (unsigned long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_const2s: + printf ("DW_OP_const2s: %ld", (long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_const4u: + printf ("DW_OP_const4u: %lu", (unsigned long) byte_get (data, 4)); + data += 4; + break; + case DW_OP_const4s: + printf ("DW_OP_const4s: %ld", (long) byte_get (data, 4)); + data += 4; + break; + case DW_OP_const8u: + printf ("DW_OP_const8u: %lu %lu", (unsigned long) byte_get (data, 4), + (unsigned long) byte_get (data + 4, 4)); + data += 8; + break; + case DW_OP_const8s: + printf ("DW_OP_const8s: %ld %ld", (long) byte_get (data, 4), + (long) byte_get (data + 4, 4)); + data += 8; + break; + case DW_OP_constu: + printf ("DW_OP_constu: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_consts: + printf ("DW_OP_consts: %ld", read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_dup: + printf ("DW_OP_dup"); + break; + case DW_OP_drop: + printf ("DW_OP_drop"); + break; + case DW_OP_over: + printf ("DW_OP_over"); + break; + case DW_OP_pick: + printf ("DW_OP_pick: %ld", (unsigned long) byte_get (data++, 1)); + break; + case DW_OP_swap: + printf ("DW_OP_swap"); + break; + case DW_OP_rot: + printf ("DW_OP_rot"); + break; + case DW_OP_xderef: + printf ("DW_OP_xderef"); + break; + case DW_OP_abs: + printf ("DW_OP_abs"); + break; + case DW_OP_and: + printf ("DW_OP_and"); + break; + case DW_OP_div: + printf ("DW_OP_div"); + break; + case DW_OP_minus: + printf ("DW_OP_minus"); + break; + case DW_OP_mod: + printf ("DW_OP_mod"); + break; + case DW_OP_mul: + printf ("DW_OP_mul"); + break; + case DW_OP_neg: + printf ("DW_OP_neg"); + break; + case DW_OP_not: + printf ("DW_OP_not"); + break; + case DW_OP_or: + printf ("DW_OP_or"); + break; + case DW_OP_plus: + printf ("DW_OP_plus"); + break; + case DW_OP_plus_uconst: + printf ("DW_OP_plus_uconst: %lu", + read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_shl: + printf ("DW_OP_shl"); + break; + case DW_OP_shr: + printf ("DW_OP_shr"); + break; + case DW_OP_shra: + printf ("DW_OP_shra"); + break; + case DW_OP_xor: + printf ("DW_OP_xor"); + break; + case DW_OP_bra: + printf ("DW_OP_bra: %ld", (long) byte_get (data, 2)); + data += 2; + break; + case DW_OP_eq: + printf ("DW_OP_eq"); + break; + case DW_OP_ge: + printf ("DW_OP_ge"); + break; + case DW_OP_gt: + printf ("DW_OP_gt"); + break; + case DW_OP_le: + printf ("DW_OP_le"); + break; + case DW_OP_lt: + printf ("DW_OP_lt"); + break; + case DW_OP_ne: + printf ("DW_OP_ne"); + break; + case DW_OP_skip: + printf ("DW_OP_skip: %ld", (long) byte_get (data, 2)); + data += 2; + break; + + case DW_OP_lit0: + case DW_OP_lit1: + case DW_OP_lit2: + case DW_OP_lit3: + case DW_OP_lit4: + case DW_OP_lit5: + case DW_OP_lit6: + case DW_OP_lit7: + case DW_OP_lit8: + case DW_OP_lit9: + case DW_OP_lit10: + case DW_OP_lit11: + case DW_OP_lit12: + case DW_OP_lit13: + case DW_OP_lit14: + case DW_OP_lit15: + case DW_OP_lit16: + case DW_OP_lit17: + case DW_OP_lit18: + case DW_OP_lit19: + case DW_OP_lit20: + case DW_OP_lit21: + case DW_OP_lit22: + case DW_OP_lit23: + case DW_OP_lit24: + case DW_OP_lit25: + case DW_OP_lit26: + case DW_OP_lit27: + case DW_OP_lit28: + case DW_OP_lit29: + case DW_OP_lit30: + case DW_OP_lit31: + printf ("DW_OP_lit%d", op - DW_OP_lit0); + break; - return data; -} + case DW_OP_reg0: + case DW_OP_reg1: + case DW_OP_reg2: + case DW_OP_reg3: + case DW_OP_reg4: + case DW_OP_reg5: + case DW_OP_reg6: + case DW_OP_reg7: + case DW_OP_reg8: + case DW_OP_reg9: + case DW_OP_reg10: + case DW_OP_reg11: + case DW_OP_reg12: + case DW_OP_reg13: + case DW_OP_reg14: + case DW_OP_reg15: + case DW_OP_reg16: + case DW_OP_reg17: + case DW_OP_reg18: + case DW_OP_reg19: + case DW_OP_reg20: + case DW_OP_reg21: + case DW_OP_reg22: + case DW_OP_reg23: + case DW_OP_reg24: + case DW_OP_reg25: + case DW_OP_reg26: + case DW_OP_reg27: + case DW_OP_reg28: + case DW_OP_reg29: + case DW_OP_reg30: + case DW_OP_reg31: + printf ("DW_OP_reg%d", op - DW_OP_reg0); + break; -static void -decode_location_expression (data, pointer_size) - unsigned char * data; - unsigned int pointer_size; -{ - unsigned char op; - int bytes_read; + case DW_OP_breg0: + case DW_OP_breg1: + case DW_OP_breg2: + case DW_OP_breg3: + case DW_OP_breg4: + case DW_OP_breg5: + case DW_OP_breg6: + case DW_OP_breg7: + case DW_OP_breg8: + case DW_OP_breg9: + case DW_OP_breg10: + case DW_OP_breg11: + case DW_OP_breg12: + case DW_OP_breg13: + case DW_OP_breg14: + case DW_OP_breg15: + case DW_OP_breg16: + case DW_OP_breg17: + case DW_OP_breg18: + case DW_OP_breg19: + case DW_OP_breg20: + case DW_OP_breg21: + case DW_OP_breg22: + case DW_OP_breg23: + case DW_OP_breg24: + case DW_OP_breg25: + case DW_OP_breg26: + case DW_OP_breg27: + case DW_OP_breg28: + case DW_OP_breg29: + case DW_OP_breg30: + case DW_OP_breg31: + printf ("DW_OP_breg%d: %ld", op - DW_OP_breg0, + read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; - op = * data ++; - - switch (op) - { - case DW_OP_addr: printf ("DW_OP_addr: %lx", byte_get (data, pointer_size)); break; - case DW_OP_deref: printf ("DW_OP_deref"); break; - case DW_OP_const1u: printf ("DW_OP_const1u: %lu", byte_get (data, 1)); break; - case DW_OP_const1s: printf ("DW_OP_const1s: %ld", (long) byte_get (data, 1)); break; - case DW_OP_const2u: printf ("DW_OP_const2u: %lu", byte_get (data, 2)); break; - case DW_OP_const2s: printf ("DW_OP_const2s: %ld", (long) byte_get (data, 2)); break; - case DW_OP_const4u: printf ("DW_OP_const4u: %lu", byte_get (data, 4)); break; - case DW_OP_const4s: printf ("DW_OP_const4s: %ld", (long) byte_get (data, 4)); break; - case DW_OP_const8u: printf ("DW_OP_const8u: %lu %lu", byte_get (data, 4), byte_get (data + 4, 4)); break; - case DW_OP_const8s: printf ("DW_OP_const8s: %ld %ld", byte_get (data, 4), byte_get (data + 4, 4)); break; - case DW_OP_constu: printf ("DW_OP_constu: %lu", read_leb128 (data, NULL, 0)); break; - case DW_OP_consts: printf ("DW_OP_consts: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_dup: printf ("DW_OP_dup"); break; - case DW_OP_drop: printf ("DW_OP_drop"); break; - case DW_OP_over: printf ("DW_OP_over"); break; - case DW_OP_pick: printf ("DW_OP_pick: %ld", byte_get (data, 1)); break; - case DW_OP_swap: printf ("DW_OP_swap"); break; - case DW_OP_rot: printf ("DW_OP_rot"); break; - case DW_OP_xderef: printf ("DW_OP_xderef"); break; - case DW_OP_abs: printf ("DW_OP_abs"); break; - case DW_OP_and: printf ("DW_OP_and"); break; - case DW_OP_div: printf ("DW_OP_div"); break; - case DW_OP_minus: printf ("DW_OP_minus"); break; - case DW_OP_mod: printf ("DW_OP_mod"); break; - case DW_OP_mul: printf ("DW_OP_mul"); break; - case DW_OP_neg: printf ("DW_OP_neg"); break; - case DW_OP_not: printf ("DW_OP_not"); break; - case DW_OP_or: printf ("DW_OP_or"); break; - case DW_OP_plus: printf ("DW_OP_plus"); break; - case DW_OP_plus_uconst: printf ("DW_OP_plus_uconst: %lu", read_leb128 (data, NULL, 0)); break; - case DW_OP_shl: printf ("DW_OP_shl"); break; - case DW_OP_shr: printf ("DW_OP_shr"); break; - case DW_OP_shra: printf ("DW_OP_shra"); break; - case DW_OP_xor: printf ("DW_OP_xor"); break; - case DW_OP_bra: printf ("DW_OP_bra: %ld", byte_get (data, 2)); break; - case DW_OP_eq: printf ("DW_OP_eq"); break; - case DW_OP_ge: printf ("DW_OP_ge"); break; - case DW_OP_gt: printf ("DW_OP_gt"); break; - case DW_OP_le: printf ("DW_OP_le"); break; - case DW_OP_lt: printf ("DW_OP_lt"); break; - case DW_OP_ne: printf ("DW_OP_ne"); break; - case DW_OP_skip: printf ("DW_OP_skip: %ld", byte_get (data, 2)); break; - case DW_OP_lit0: printf ("DW_OP_lit0"); break; - case DW_OP_lit1: printf ("DW_OP_lit1"); break; - case DW_OP_lit2: printf ("DW_OP_lit2"); break; - case DW_OP_lit3: printf ("DW_OP_lit3"); break; - case DW_OP_lit4: printf ("DW_OP_lit4"); break; - case DW_OP_lit5: printf ("DW_OP_lit5"); break; - case DW_OP_lit6: printf ("DW_OP_lit6"); break; - case DW_OP_lit7: printf ("DW_OP_lit7"); break; - case DW_OP_lit8: printf ("DW_OP_lit8"); break; - case DW_OP_lit9: printf ("DW_OP_lit9"); break; - case DW_OP_lit10: printf ("DW_OP_lit10"); break; - case DW_OP_lit11: printf ("DW_OP_lit11"); break; - case DW_OP_lit12: printf ("DW_OP_lit12"); break; - case DW_OP_lit13: printf ("DW_OP_lit13"); break; - case DW_OP_lit14: printf ("DW_OP_lit14"); break; - case DW_OP_lit15: printf ("DW_OP_lit15"); break; - case DW_OP_lit16: printf ("DW_OP_lit16"); break; - case DW_OP_lit17: printf ("DW_OP_lit17"); break; - case DW_OP_lit18: printf ("DW_OP_lit18"); break; - case DW_OP_lit19: printf ("DW_OP_lit19"); break; - case DW_OP_lit20: printf ("DW_OP_lit20"); break; - case DW_OP_lit21: printf ("DW_OP_lit21"); break; - case DW_OP_lit22: printf ("DW_OP_lit22"); break; - case DW_OP_lit23: printf ("DW_OP_lit23"); break; - case DW_OP_lit24: printf ("DW_OP_lit24"); break; - case DW_OP_lit25: printf ("DW_OP_lit25"); break; - case DW_OP_lit26: printf ("DW_OP_lit26"); break; - case DW_OP_lit27: printf ("DW_OP_lit27"); break; - case DW_OP_lit28: printf ("DW_OP_lit28"); break; - case DW_OP_lit29: printf ("DW_OP_lit29"); break; - case DW_OP_lit30: printf ("DW_OP_lit30"); break; - case DW_OP_lit31: printf ("DW_OP_lit31"); break; - case DW_OP_reg0: printf ("DW_OP_reg0"); break; - case DW_OP_reg1: printf ("DW_OP_reg1"); break; - case DW_OP_reg2: printf ("DW_OP_reg2"); break; - case DW_OP_reg3: printf ("DW_OP_reg3"); break; - case DW_OP_reg4: printf ("DW_OP_reg4"); break; - case DW_OP_reg5: printf ("DW_OP_reg5"); break; - case DW_OP_reg6: printf ("DW_OP_reg6"); break; - case DW_OP_reg7: printf ("DW_OP_reg7"); break; - case DW_OP_reg8: printf ("DW_OP_reg8"); break; - case DW_OP_reg9: printf ("DW_OP_reg9"); break; - case DW_OP_reg10: printf ("DW_OP_reg10"); break; - case DW_OP_reg11: printf ("DW_OP_reg11"); break; - case DW_OP_reg12: printf ("DW_OP_reg12"); break; - case DW_OP_reg13: printf ("DW_OP_reg13"); break; - case DW_OP_reg14: printf ("DW_OP_reg14"); break; - case DW_OP_reg15: printf ("DW_OP_reg15"); break; - case DW_OP_reg16: printf ("DW_OP_reg16"); break; - case DW_OP_reg17: printf ("DW_OP_reg17"); break; - case DW_OP_reg18: printf ("DW_OP_reg18"); break; - case DW_OP_reg19: printf ("DW_OP_reg19"); break; - case DW_OP_reg20: printf ("DW_OP_reg20"); break; - case DW_OP_reg21: printf ("DW_OP_reg21"); break; - case DW_OP_reg22: printf ("DW_OP_reg22"); break; - case DW_OP_reg23: printf ("DW_OP_reg23"); break; - case DW_OP_reg24: printf ("DW_OP_reg24"); break; - case DW_OP_reg25: printf ("DW_OP_reg25"); break; - case DW_OP_reg26: printf ("DW_OP_reg26"); break; - case DW_OP_reg27: printf ("DW_OP_reg27"); break; - case DW_OP_reg28: printf ("DW_OP_reg28"); break; - case DW_OP_reg29: printf ("DW_OP_reg29"); break; - case DW_OP_reg30: printf ("DW_OP_reg30"); break; - case DW_OP_reg31: printf ("DW_OP_reg31"); break; - case DW_OP_breg0: printf ("DW_OP_breg0: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg1: printf ("DW_OP_breg1: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg2: printf ("DW_OP_breg2: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg3: printf ("DW_OP_breg3: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg4: printf ("DW_OP_breg4: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg5: printf ("DW_OP_breg5: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg6: printf ("DW_OP_breg6: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg7: printf ("DW_OP_breg7: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg8: printf ("DW_OP_breg8: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg9: printf ("DW_OP_breg9: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg10: printf ("DW_OP_breg10: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg11: printf ("DW_OP_breg11: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg12: printf ("DW_OP_breg12: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg13: printf ("DW_OP_breg13: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg14: printf ("DW_OP_breg14: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg15: printf ("DW_OP_breg15: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg16: printf ("DW_OP_breg16: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg17: printf ("DW_OP_breg17: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg18: printf ("DW_OP_breg18: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg19: printf ("DW_OP_breg19: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg20: printf ("DW_OP_breg20: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg21: printf ("DW_OP_breg21: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg22: printf ("DW_OP_breg22: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg23: printf ("DW_OP_breg23: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg24: printf ("DW_OP_breg24: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg25: printf ("DW_OP_breg25: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg26: printf ("DW_OP_breg26: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg27: printf ("DW_OP_breg27: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg28: printf ("DW_OP_breg28: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg29: printf ("DW_OP_breg29: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg30: printf ("DW_OP_breg30: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_breg31: printf ("DW_OP_breg31: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_regx: printf ("DW_OP_regx: %lu", read_leb128 (data, NULL, 0)); break; - case DW_OP_fbreg: printf ("DW_OP_fbreg: %ld", read_leb128 (data, NULL, 1)); break; - case DW_OP_bregx: printf ("DW_OP_bregx: %lu %ld", read_leb128 (data, & bytes_read, 0), read_leb128 (data + bytes_read, NULL, 1)); break; - case DW_OP_piece: printf ("DW_OP_piece: %lu", read_leb128 (data, NULL, 0)); break; - case DW_OP_deref_size: printf ("DW_OP_deref_size: %ld", byte_get (data, 1)); break; - case DW_OP_xderef_size: printf ("DW_OP_xderef_size: %ld", byte_get (data, 1)); break; - case DW_OP_nop: printf ("DW_OP_nop"); break; + case DW_OP_regx: + printf ("DW_OP_regx: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_fbreg: + printf ("DW_OP_fbreg: %ld", read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_bregx: + uvalue = read_leb128 (data, &bytes_read, 0); + data += bytes_read; + printf ("DW_OP_bregx: %lu %ld", uvalue, + read_leb128 (data, &bytes_read, 1)); + data += bytes_read; + break; + case DW_OP_piece: + printf ("DW_OP_piece: %lu", read_leb128 (data, &bytes_read, 0)); + data += bytes_read; + break; + case DW_OP_deref_size: + printf ("DW_OP_deref_size: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_xderef_size: + printf ("DW_OP_xderef_size: %ld", (long) byte_get (data++, 1)); + break; + case DW_OP_nop: + printf ("DW_OP_nop"); + break; - default: - if (op >= DW_OP_lo_user - && op <= DW_OP_hi_user) - printf (_("(User defined location op)")); - else - printf (_("(Unknown location op)")); - break; + default: + if (op >= DW_OP_lo_user + && op <= DW_OP_hi_user) + printf (_("(User defined location op)")); + else + printf (_("(Unknown location op)")); + /* No way to tell where the next op is, so just bail. */ + return; + } } } static unsigned char * -read_and_display_attr (attribute, form, data, pointer_size) +read_and_display_attr (attribute, form, data, cu_offset, pointer_size) unsigned long attribute; unsigned long form; unsigned char * data; + unsigned long cu_offset; unsigned long pointer_size; { - unsigned long uvalue; - unsigned char * block_start; + unsigned long uvalue = 0; + unsigned char * block_start = NULL; int bytes_read; - int is_ref = 0; printf (" %-18s:", get_AT_name (attribute)); switch (form) { - case DW_FORM_ref_addr: - case DW_FORM_ref1: - case DW_FORM_ref2: - case DW_FORM_ref4: - case DW_FORM_ref8: - case DW_FORM_ref_udata: - is_ref = 1; - } - - switch (form) - { + default: + break; + case DW_FORM_ref_addr: case DW_FORM_addr: uvalue = byte_get (data, pointer_size); - printf (is_ref ? " <%x>" : " %#x", uvalue); data += pointer_size; break; @@ -4658,75 +6029,92 @@ read_and_display_attr (attribute, form, data, pointer_size) case DW_FORM_flag: case DW_FORM_data1: uvalue = byte_get (data ++, 1); - printf (is_ref ? " <%x>" : " %d", uvalue); break; case DW_FORM_ref2: case DW_FORM_data2: uvalue = byte_get (data, 2); data += 2; - printf (is_ref ? " <%x>" : " %d", uvalue); break; case DW_FORM_ref4: case DW_FORM_data4: uvalue = byte_get (data, 4); data += 4; - printf (is_ref ? " <%x>" : " %d", uvalue); - break; - - case DW_FORM_ref8: - case DW_FORM_data8: - uvalue = byte_get (data, 4); - printf (" %lx", uvalue); - printf (" %lx", byte_get (data + 4, 4)); - data += 8; - break; - - case DW_FORM_string: - printf (" %s", data); - data += strlen (data) + 1; break; case DW_FORM_sdata: uvalue = read_leb128 (data, & bytes_read, 1); data += bytes_read; - printf (" %ld", (long) uvalue); break; case DW_FORM_ref_udata: case DW_FORM_udata: uvalue = read_leb128 (data, & bytes_read, 0); data += bytes_read; - printf (is_ref ? " <%lx>" : " %ld", uvalue); + break; + } + + switch (form) + { + case DW_FORM_ref_addr: + printf (" <#%lx>", uvalue); + break; + + case DW_FORM_ref1: + case DW_FORM_ref2: + case DW_FORM_ref4: + case DW_FORM_ref_udata: + printf (" <%lx>", uvalue + cu_offset); + break; + + case DW_FORM_addr: + printf (" %#lx", uvalue); + + case DW_FORM_flag: + case DW_FORM_data1: + case DW_FORM_data2: + case DW_FORM_data4: + case DW_FORM_sdata: + case DW_FORM_udata: + printf (" %ld", uvalue); + break; + + case DW_FORM_ref8: + case DW_FORM_data8: + uvalue = byte_get (data, 4); + printf (" %lx", uvalue); + printf (" %lx", (unsigned long) byte_get (data + 4, 4)); + data += 8; + break; + + case DW_FORM_string: + printf (" %s", data); + data += strlen ((char *) data) + 1; break; case DW_FORM_block: uvalue = read_leb128 (data, & bytes_read, 0); block_start = data + bytes_read; data = display_block (block_start, uvalue); - uvalue = * block_start; break; case DW_FORM_block1: uvalue = byte_get (data, 1); block_start = data + 1; data = display_block (block_start, uvalue); - uvalue = * block_start; break; case DW_FORM_block2: uvalue = byte_get (data, 2); block_start = data + 2; data = display_block (block_start, uvalue); - uvalue = * block_start; break; case DW_FORM_block4: uvalue = byte_get (data, 4); block_start = data + 4; data = display_block (block_start, uvalue); - uvalue = * block_start; break; case DW_FORM_strp: @@ -4756,11 +6144,6 @@ read_and_display_attr (attribute, form, data, pointer_size) } break; - case DW_AT_frame_base: - if (uvalue >= DW_OP_reg0 && uvalue <= DW_OP_reg31) - printf ("(reg %ld)", uvalue - DW_OP_reg0); - break; - case DW_AT_language: switch (uvalue) { @@ -4857,12 +6240,16 @@ read_and_display_attr (attribute, form, data, pointer_size) } break; + case DW_AT_frame_base: case DW_AT_location: case DW_AT_data_member_location: case DW_AT_vtable_elem_location: - printf ("("); - decode_location_expression (block_start, pointer_size); - printf (")"); + if (block_start) + { + printf ("("); + decode_location_expression (block_start, pointer_size, uvalue); + printf (")"); + } break; default: @@ -4891,6 +6278,7 @@ display_debug_info (section, start, file) unsigned char * tags; int i; int level; + unsigned long cu_offset; external = (DWARF2_External_CompUnit *) start; @@ -4900,6 +6288,7 @@ display_debug_info (section, start, file) compunit.cu_pointer_size = BYTE_GET (external->cu_pointer_size); tags = start + sizeof (* external); + cu_offset = start - section_begin; start += compunit.cu_length + sizeof (external->cu_length); if (compunit.cu_version != 2) @@ -4949,7 +6338,7 @@ display_debug_info (section, start, file) while (tags < start) { int bytes_read; - int abbrev_number; + unsigned long abbrev_number; abbrev_entry * entry; abbrev_attr * attr; @@ -4972,12 +6361,12 @@ display_debug_info (section, start, file) if (entry == NULL) { - warn (_("Unable to locate entry %d in the abbreviation table\n"), + warn (_("Unable to locate entry %lu in the abbreviation table\n"), abbrev_number); return 0; } - printf (_(" <%d><%x>: Abbrev Number: %d (%s)\n"), + printf (_(" <%d><%x>: Abbrev Number: %lu (%s)\n"), level, tags - section_begin - bytes_read, abbrev_number, get_TAG_name (entry->tag)); @@ -4985,7 +6374,7 @@ display_debug_info (section, start, file) for (attr = entry->first_attr; attr; attr = attr->next) tags = read_and_display_attr (attr->attribute, attr->form, - tags, + tags, cu_offset, compunit.cu_pointer_size); if (entry->children) @@ -5002,7 +6391,7 @@ static int display_debug_aranges (section, start, file) Elf32_Internal_Shdr * section; unsigned char * start; - FILE * file; + FILE * file ATTRIBUTE_UNUSED; { unsigned char * end = start + section->sh_size; @@ -5015,6 +6404,7 @@ display_debug_aranges (section, start, file) unsigned char * ranges; unsigned long length; unsigned long address; + int excess; external = (DWARF2_External_ARange *) start; @@ -5024,6 +6414,12 @@ display_debug_aranges (section, start, file) arange.ar_pointer_size = BYTE_GET (external->ar_pointer_size); arange.ar_segment_size = BYTE_GET (external->ar_segment_size); + if (arange.ar_version != 2) + { + warn (_("Only DWARF 2 aranges are currently supported.\n")); + break; + } + printf (_(" Length: %ld\n"), arange.ar_length); printf (_(" Version: %d\n"), arange.ar_version); printf (_(" Offset into .debug_info: %lx\n"), arange.ar_info_offset); @@ -5034,19 +6430,25 @@ display_debug_aranges (section, start, file) ranges = start + sizeof (* external); + /* Must pad to an alignment boundary that is twice the pointer size. */ + excess = sizeof (*external) % (2 * arange.ar_pointer_size); + if (excess) + ranges += (2 * arange.ar_pointer_size) - excess; + for (;;) { address = byte_get (ranges, arange.ar_pointer_size); - if (address == 0) - break; - ranges += arange.ar_pointer_size; length = byte_get (ranges, arange.ar_pointer_size); ranges += arange.ar_pointer_size; + /* A pair of zeros marks the end of the list. */ + if (address == 0 && length == 0) + break; + printf (" %8.8lx %lu\n", address, length); } @@ -5062,8 +6464,8 @@ display_debug_aranges (section, start, file) static int display_debug_not_supported (section, start, file) Elf32_Internal_Shdr * section; - unsigned char * start; - FILE * file; + unsigned char * start ATTRIBUTE_UNUSED; + FILE * file ATTRIBUTE_UNUSED; { printf (_("Displaying the debug contents of section %s is not yet supported.\n"), SECTION_NAME (section)); @@ -5071,27 +6473,47 @@ display_debug_not_supported (section, start, file) return 1; } +/* Pre-scan the .debug_info section to record the size of address. + When dumping the .debug_line, we use that size information, assuming + that all compilation units have the same address size. */ +static int +prescan_debug_info (section, start, file) + Elf32_Internal_Shdr * section ATTRIBUTE_UNUSED; + unsigned char * start; + FILE * file ATTRIBUTE_UNUSED; +{ + DWARF2_External_CompUnit * external; + + external = (DWARF2_External_CompUnit *) start; + + debug_line_pointer_size = BYTE_GET (external->cu_pointer_size); + return 0; +} + /* A structure containing the name of a debug section and a pointer - to a function that can decode it. */ + to a function that can decode it. The third field is a prescan + function to be run over the section before displaying any of the + sections. */ struct { char * name; - int (* display) PARAMS((Elf32_Internal_Shdr *, unsigned char *, FILE *)); + int (* display) PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *)); + int (* prescan) PARAMS ((Elf32_Internal_Shdr *, unsigned char *, FILE *)); } debug_displays[] = { - { ".debug_info", display_debug_info }, - { ".debug_abbrev", display_debug_abbrev }, - { ".debug_line", display_debug_lines }, - { ".debug_aranges", display_debug_aranges }, - { ".debug_pubnames", display_debug_pubnames }, - { ".debug_macinfo", display_debug_not_supported }, - { ".debug_frame", display_debug_not_supported }, - { ".debug_str", display_debug_not_supported }, - { ".debug_static_func", display_debug_not_supported }, - { ".debug_static_vars", display_debug_not_supported }, - { ".debug_types", display_debug_not_supported }, - { ".debug_weaknames", display_debug_not_supported } + { ".debug_info", display_debug_info, prescan_debug_info }, + { ".debug_abbrev", display_debug_abbrev, NULL }, + { ".debug_line", display_debug_lines, NULL }, + { ".debug_aranges", display_debug_aranges, NULL }, + { ".debug_pubnames", display_debug_pubnames, NULL }, + { ".debug_macinfo", display_debug_not_supported, NULL }, + { ".debug_frame", display_debug_not_supported, NULL }, + { ".debug_str", display_debug_not_supported, NULL }, + { ".debug_static_func", display_debug_not_supported, NULL }, + { ".debug_static_vars", display_debug_not_supported, NULL }, + { ".debug_types", display_debug_not_supported, NULL }, + { ".debug_weaknames", display_debug_not_supported, NULL } }; static int @@ -5139,15 +6561,48 @@ static int process_section_contents (file) FILE * file; { - Elf32_Internal_Shdr * section; - unsigned int i; + Elf32_Internal_Shdr * section; + unsigned int i; if (! do_dump) return 1; + /* Pre-scan the debug sections to find some debug information not + present in some of them. For the .debug_line, we must find out the + size of address (specified in .debug_info and .debug_aranges). */ + for (i = 0, section = section_headers; + i < elf_header.e_shnum && i < num_dump_sects; + i ++, section ++) + { + char * name = SECTION_NAME (section); + int j; + + if (section->sh_size == 0) + continue; + + /* See if there is some pre-scan operation for this section. */ + for (j = NUM_ELEM (debug_displays); j--;) + if (strcmp (debug_displays[j].name, name) == 0) + { + if (debug_displays[j].prescan != NULL) + { + bfd_size_type length; + unsigned char * start; + + length = section->sh_size; + GET_DATA_ALLOC (section->sh_offset, length, start, unsigned char *, + "debug section data"); + + debug_displays[j].prescan (section, start, file); + free (start); + } + + break; + } + } + for (i = 0, section = section_headers; - i < elf_header.e_shnum - && i < num_dump_sects; + i < elf_header.e_shnum && i < num_dump_sects; i ++, section ++) { #ifdef SUPPORT_DISASSEMBLY @@ -5191,9 +6646,9 @@ process_mips_fpe_exception (mask) static int process_mips_specific (file) - FILE *file; + FILE * file; { - Elf_Internal_Dyn *entry; + Elf_Internal_Dyn * entry; size_t liblist_offset = 0; size_t liblistno = 0; size_t conflictsno = 0; @@ -5229,13 +6684,14 @@ process_mips_specific (file) if (liblist_offset != 0 && liblistno != 0 && do_dynamic) { - Elf32_External_Lib *elib; + Elf32_External_Lib * elib; size_t cnt; GET_DATA_ALLOC (liblist_offset, liblistno * sizeof (Elf32_External_Lib), elib, Elf32_External_Lib *, "liblist"); - printf ("\nSection '.liblist' contains %d entries:\n", liblistno); + printf ("\nSection '.liblist' contains %lu entries:\n", + (unsigned long) liblistno); fputs (" Library Time Stamp Checksum Version Flags\n", stdout); @@ -5244,6 +6700,7 @@ process_mips_specific (file) Elf32_Lib liblist; time_t time; char timebuf[20]; + struct tm * tmp; liblist.l_name = BYTE_GET (elib[cnt].l_name); time = BYTE_GET (elib[cnt].l_time_stamp); @@ -5251,9 +6708,12 @@ process_mips_specific (file) liblist.l_version = BYTE_GET (elib[cnt].l_version); liblist.l_flags = BYTE_GET (elib[cnt].l_flags); - strftime (timebuf, 20, "%Y-%m-%dT%H:%M:%S", gmtime (&time)); + tmp = gmtime (&time); + sprintf (timebuf, "%04u-%02u-%02uT%02u:%02u:%02u", + tmp->tm_year + 1900, tmp->tm_mon + 1, tmp->tm_mday, + tmp->tm_hour, tmp->tm_min, tmp->tm_sec); - printf ("%3d: %-20s %s %#10lx %-7ld", cnt, + printf ("%3lu: %-20s %s %#10lx %-7ld", (unsigned long) cnt, dynamic_strings + liblist.l_name, timebuf, liblist.l_checksum, liblist.l_version); @@ -5263,19 +6723,20 @@ process_mips_specific (file) { static const struct { - const char *name; + const char * name; int bit; - } l_flags_vals[] = - { - { " EXACT_MATCH", LL_EXACT_MATCH }, - { " IGNORE_INT_VER", LL_IGNORE_INT_VER }, - { " REQUIRE_MINOR", LL_REQUIRE_MINOR }, - { " EXPORTS", LL_EXPORTS }, - { " DELAY_LOAD", LL_DELAY_LOAD }, - { " DELTA", LL_DELTA } - }; + } + l_flags_vals[] = + { + { " EXACT_MATCH", LL_EXACT_MATCH }, + { " IGNORE_INT_VER", LL_IGNORE_INT_VER }, + { " REQUIRE_MINOR", LL_REQUIRE_MINOR }, + { " EXPORTS", LL_EXPORTS }, + { " DELAY_LOAD", LL_DELAY_LOAD }, + { " DELTA", LL_DELTA } + }; int flags = liblist.l_flags; - int fcnt; + size_t fcnt; for (fcnt = 0; fcnt < sizeof (l_flags_vals) / sizeof (l_flags_vals[0]); @@ -5297,16 +6758,16 @@ process_mips_specific (file) if (options_offset != 0) { - Elf_External_Options *eopt; - Elf_Internal_Shdr *sect = section_headers; - Elf_Internal_Options *iopt; - Elf_Internal_Options *option; + Elf_External_Options * eopt; + Elf_Internal_Shdr * sect = section_headers; + Elf_Internal_Options * iopt; + Elf_Internal_Options * option; size_t offset; int cnt; /* Find the section header so that we get the size. */ while (sect->sh_type != SHT_MIPS_OPTIONS) - ++sect; + ++ sect; GET_DATA_ALLOC (options_offset, sect->sh_size, eopt, Elf_External_Options *, "options"); @@ -5321,9 +6782,10 @@ process_mips_specific (file) offset = cnt = 0; option = iopt; + while (offset < sect->sh_size) { - Elf_External_Options *eoption; + Elf_External_Options * eoption; eoption = (Elf_External_Options *) ((char *) eopt + offset); @@ -5333,6 +6795,7 @@ process_mips_specific (file) option->info = BYTE_GET (eoption->info); offset += option->size; + ++option; ++cnt; } @@ -5341,6 +6804,7 @@ process_mips_specific (file) string_table + sect->sh_name, cnt); option = iopt; + while (cnt-- > 0) { size_t len; @@ -5377,16 +6841,16 @@ process_mips_specific (file) else { /* 64 bit form. */ - Elf64_External_RegInfo *ereg; + Elf64_External_RegInfo * ereg; Elf64_Internal_RegInfo reginfo; ereg = (Elf64_External_RegInfo *) (option + 1); - reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); + reginfo.ri_gprmask = BYTE_GET (ereg->ri_gprmask); reginfo.ri_cprmask[0] = BYTE_GET (ereg->ri_cprmask[0]); reginfo.ri_cprmask[1] = BYTE_GET (ereg->ri_cprmask[1]); reginfo.ri_cprmask[2] = BYTE_GET (ereg->ri_cprmask[2]); reginfo.ri_cprmask[3] = BYTE_GET (ereg->ri_cprmask[3]); - reginfo.ri_gp_value = BYTE_GET (ereg->ri_gp_value); + reginfo.ri_gp_value = BYTE_GET8 (ereg->ri_gp_value); printf ("GPR %08lx GP 0x", reginfo.ri_gprmask); @@ -5491,9 +6955,9 @@ process_mips_specific (file) if (conflicts_offset != 0 && conflictsno != 0) { - Elf32_External_Conflict *econf32; - Elf64_External_Conflict *econf64; - Elf32_Conflict *iconf; + Elf32_External_Conflict * econf32; + Elf64_External_Conflict * econf64; + Elf32_Conflict * iconf; size_t cnt; if (dynamic_symbols == NULL) @@ -5509,7 +6973,7 @@ process_mips_specific (file) return 0; } - if (binary_class == ELFCLASS32) + if (is_32bit_elf) { GET_DATA_ALLOC (conflicts_offset, conflictsno * sizeof (*econf32), econf32, Elf32_External_Conflict *, "conflict"); @@ -5531,24 +6995,204 @@ process_mips_specific (file) for (cnt = 0; cnt < conflictsno; ++cnt) { - Elf_Internal_Sym *psym = &dynamic_symbols[iconf[cnt]]; + Elf_Internal_Sym * psym = &dynamic_symbols[iconf[cnt]]; - printf ("%5u: %8lu %#10lx %s\n", - cnt, iconf[cnt], (unsigned long) psym->st_value, - dynamic_strings + psym->st_name); + printf ("%5lu: %8lu ", (unsigned long) cnt, iconf[cnt]); + print_vma (psym->st_value, FULL_HEX); + printf (" %s\n", dynamic_strings + psym->st_name); } - free (iconf); } return 1; } +static char * +get_note_type (e_type) + unsigned e_type; +{ + static char buff[64]; + + switch (e_type) + { + case NT_PRSTATUS: return _("NT_PRSTATUS (prstatus structure)"); + case NT_FPREGSET: return _("NT_FPREGSET (floating point registers)"); + case NT_PRPSINFO: return _("NT_PRPSINFO (prpsinfo structure)"); + case NT_TASKSTRUCT: return _("NT_TASKSTRUCT (task structure)"); + case NT_PRXFPREG: return _("NT_PRXFPREG (user_xfpregs structure)"); + case NT_PSTATUS: return _("NT_PSTATUS (pstatus structure)"); + case NT_FPREGS: return _("NT_FPREGS (floating point registers)"); + case NT_PSINFO: return _("NT_PSINFO (psinfo structure)"); + case NT_LWPSTATUS: return _("NT_LWPSTATUS (lwpstatus_t structure)"); + case NT_LWPSINFO: return _("NT_LWPSINFO (lwpsinfo_t structure)"); + case NT_WIN32PSTATUS: return _("NT_WIN32PSTATUS (win32_pstatus strcuture)"); + default: + sprintf (buff, _("Unknown note type: (0x%08x)"), e_type); + return buff; + } +} + +/* Note that by the ELF standard, the name field is already null byte + terminated, and namesz includes the terminating null byte. + I.E. the value of namesz for the name "FSF" is 4. + + If the value of namesz is zero, there is no name present. */ +static int +process_note (pnote) + Elf32_Internal_Note * pnote; +{ + printf (" %s\t\t0x%08lx\t%s\n", + pnote->namesz ? pnote->namedata : "(NONE)", + pnote->descsz, get_note_type (pnote->type)); + return 1; +} + + +static int +process_corefile_note_segment (file, offset, length) + FILE * file; + bfd_vma offset; + bfd_vma length; +{ + Elf_External_Note * pnotes; + Elf_External_Note * external; + int res = 1; + + if (length <= 0) + return 0; + + GET_DATA_ALLOC (offset, length, pnotes, Elf_External_Note *, "notes"); + + external = pnotes; + + printf (_("\nNotes at offset 0x%08lx with length 0x%08lx:\n"), + (unsigned long) offset, (unsigned long) length); + printf (_(" Owner\t\tData size\tDescription\n")); + + while (external < (Elf_External_Note *)((char *) pnotes + length)) + { + Elf32_Internal_Note inote; + char * temp = NULL; + + inote.type = BYTE_GET (external->type); + inote.namesz = BYTE_GET (external->namesz); + inote.namedata = external->name; + inote.descsz = BYTE_GET (external->descsz); + inote.descdata = inote.namedata + align_power (inote.namesz, 2); + inote.descpos = offset + (inote.descdata - (char *) pnotes); + + external = (Elf_External_Note *)(inote.descdata + align_power (inote.descsz, 2)); + + /* Verify that name is null terminated. It appears that at least + one version of Linux (RedHat 6.0) generates corefiles that don't + comply with the ELF spec by failing to include the null byte in + namesz. */ + if (inote.namedata[inote.namesz] != '\0') + { + temp = malloc (inote.namesz + 1); + + if (temp == NULL) + { + error (_("Out of memory\n")); + res = 0; + break; + } + + strncpy (temp, inote.namedata, inote.namesz); + temp[inote.namesz] = 0; + + /* warn (_("'%s' NOTE name not properly null terminated\n"), temp); */ + inote.namedata = temp; + } + + res &= process_note (& inote); + + if (temp != NULL) + { + free (temp); + temp = NULL; + } + } + + free (pnotes); + + return res; +} + +static int +process_corefile_note_segments (file) + FILE * file; +{ + Elf_Internal_Phdr * program_headers; + Elf_Internal_Phdr * segment; + unsigned int i; + int res = 1; + + program_headers = (Elf_Internal_Phdr *) malloc + (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + + if (program_headers == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + if (is_32bit_elf) + i = get_32bit_program_headers (file, program_headers); + else + i = get_64bit_program_headers (file, program_headers); + + if (i == 0) + { + free (program_headers); + return 0; + } + + for (i = 0, segment = program_headers; + i < elf_header.e_phnum; + i ++, segment ++) + { + if (segment->p_type == PT_NOTE) + res &= process_corefile_note_segment (file, + (bfd_vma) segment->p_offset, + (bfd_vma) segment->p_filesz); + } + + free (program_headers); + + return res; +} + +static int +process_corefile_contents (file) + FILE * file; +{ + /* If we have not been asked to display the notes then do nothing. */ + if (! do_notes) + return 1; + + /* If file is not a core file then exit. */ + if (elf_header.e_type != ET_CORE) + return 1; + + /* No program headers means no NOTE segment. */ + if (elf_header.e_phnum == 0) + { + printf (_("No note segments present in the core file.\n")); + return 1; + } + + return process_corefile_note_segments (file); +} + static int process_arch_specific (file) - FILE *file; + FILE * file; { + if (! do_arch) + return 1; + switch (elf_header.e_machine) { case EM_MIPS: @@ -5565,31 +7209,76 @@ static int get_file_header (file) FILE * file; { - Elf32_External_Ehdr ehdr; - - if (fread (& ehdr, sizeof (ehdr), 1, file) != 1) + /* Read in the identity array. */ + if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1) return 0; - memcpy (elf_header.e_ident, ehdr.e_ident, EI_NIDENT); + /* Determine how to read the rest of the header. */ + switch (elf_header.e_ident [EI_DATA]) + { + default: /* fall through */ + case ELFDATANONE: /* fall through */ + case ELFDATA2LSB: byte_get = byte_get_little_endian; break; + case ELFDATA2MSB: byte_get = byte_get_big_endian; break; + } + + /* For now we only support 32 bit and 64 bit ELF files. */ + is_32bit_elf = (elf_header.e_ident [EI_CLASS] != ELFCLASS64); + + /* Read in the rest of the header. */ + if (is_32bit_elf) + { + Elf32_External_Ehdr ehdr32; + + if (fread (ehdr32.e_type, sizeof (ehdr32) - EI_NIDENT, 1, file) != 1) + return 0; - if (elf_header.e_ident [EI_DATA] == ELFDATA2LSB) - byte_get = byte_get_little_endian; + elf_header.e_type = BYTE_GET (ehdr32.e_type); + elf_header.e_machine = BYTE_GET (ehdr32.e_machine); + elf_header.e_version = BYTE_GET (ehdr32.e_version); + elf_header.e_entry = BYTE_GET (ehdr32.e_entry); + elf_header.e_phoff = BYTE_GET (ehdr32.e_phoff); + elf_header.e_shoff = BYTE_GET (ehdr32.e_shoff); + elf_header.e_flags = BYTE_GET (ehdr32.e_flags); + elf_header.e_ehsize = BYTE_GET (ehdr32.e_ehsize); + elf_header.e_phentsize = BYTE_GET (ehdr32.e_phentsize); + elf_header.e_phnum = BYTE_GET (ehdr32.e_phnum); + elf_header.e_shentsize = BYTE_GET (ehdr32.e_shentsize); + elf_header.e_shnum = BYTE_GET (ehdr32.e_shnum); + elf_header.e_shstrndx = BYTE_GET (ehdr32.e_shstrndx); + } else - byte_get = byte_get_big_endian; - - elf_header.e_entry = BYTE_GET (ehdr.e_entry); - elf_header.e_phoff = BYTE_GET (ehdr.e_phoff); - elf_header.e_shoff = BYTE_GET (ehdr.e_shoff); - elf_header.e_version = BYTE_GET (ehdr.e_version); - elf_header.e_flags = BYTE_GET (ehdr.e_flags); - elf_header.e_type = BYTE_GET (ehdr.e_type); - elf_header.e_machine = BYTE_GET (ehdr.e_machine); - elf_header.e_ehsize = BYTE_GET (ehdr.e_ehsize); - elf_header.e_phentsize = BYTE_GET (ehdr.e_phentsize); - elf_header.e_phnum = BYTE_GET (ehdr.e_phnum); - elf_header.e_shentsize = BYTE_GET (ehdr.e_shentsize); - elf_header.e_shnum = BYTE_GET (ehdr.e_shnum); - elf_header.e_shstrndx = BYTE_GET (ehdr.e_shstrndx); + { + Elf64_External_Ehdr ehdr64; + + /* If we have been compiled with sizeof (bfd_vma) == 4, then + we will not be able to cope with the 64bit data found in + 64 ELF files. Detect this now and abort before we start + overwritting things. */ + if (sizeof (bfd_vma) < 8) + { + error (_("This instance of readelf has been built without support for a\n")); + error (_("64 bit data type and so it cannot read 64 bit ELF files.\n")); + return 0; + } + + if (fread (ehdr64.e_type, sizeof (ehdr64) - EI_NIDENT, 1, file) != 1) + return 0; + + elf_header.e_type = BYTE_GET (ehdr64.e_type); + elf_header.e_machine = BYTE_GET (ehdr64.e_machine); + elf_header.e_version = BYTE_GET (ehdr64.e_version); + elf_header.e_entry = BYTE_GET8 (ehdr64.e_entry); + elf_header.e_phoff = BYTE_GET8 (ehdr64.e_phoff); + elf_header.e_shoff = BYTE_GET8 (ehdr64.e_shoff); + elf_header.e_flags = BYTE_GET (ehdr64.e_flags); + elf_header.e_ehsize = BYTE_GET (ehdr64.e_ehsize); + elf_header.e_phentsize = BYTE_GET (ehdr64.e_phentsize); + elf_header.e_phnum = BYTE_GET (ehdr64.e_phnum); + elf_header.e_shentsize = BYTE_GET (ehdr64.e_shentsize); + elf_header.e_shnum = BYTE_GET (ehdr64.e_shnum); + elf_header.e_shstrndx = BYTE_GET (ehdr64.e_shstrndx); + } return 1; } @@ -5655,6 +7344,8 @@ process_file (file_name) process_section_contents (file); + process_corefile_contents (file); + process_arch_specific (file); fclose (file); @@ -5681,6 +7372,7 @@ process_file (file_name) { free (dynamic_symbols); dynamic_symbols = NULL; + num_dynamic_syms = 0; } if (dynamic_syminfo) @@ -5692,8 +7384,8 @@ process_file (file_name) #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 */ + fix this so that we insert symbolic addresses here, esp for GOT/PLT + symbols */ void print_address (unsigned int addr, FILE * outfile)