X-Git-Url: https://git.libre-soc.org/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=3561eff0a6eb915372dc99bd3777c4cd51a57b5d;hb=8c9a987975e3bda9ed098c87ece7a2140bf9fffa;hp=461d63f701ac812bfe270ee05d85b833c0224103;hpb=84ad6ede873e50111c8e64728ae858d079339002;p=binutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 461d63f701a..3561eff0a6e 100644 --- a/binutils/readelf.c +++ b/binutils/readelf.c @@ -1,5 +1,5 @@ /* readelf.c -- display contents of an ELF format file - Copyright 1998, 1999, 2000, 2001, 2002 Free Software Foundation, Inc. + Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc. Originally developed by Eric Youngdale Modifications by Nick Clifton @@ -21,7 +21,25 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ +/* The difference between readelf and objdump: + Both programs are capabale of displaying the contents of ELF format files, + so why does the binutils project have two file dumpers ? + + The reason is that objdump sees an ELF file through a BFD filter of the + world; if BFD has a bug where, say, it disagrees about a machine constant + in e_flags, then the odds are good that it will remain internally + consistent. The linker sees it the BFD way, objdump sees it the BFD way, + GAS sees it the BFD way. There was need for a tool to go find out what + the file actually says. + + This is why the readelf program does not link against the BFD library - it + exists as an independent program to help verify the correct working of BFD. + + There is also the case that readelf can provide more information about an + ELF file than is provided by objdump. In particular it can display DWARF + debugging information which (at the moment) objdump cannot. */ + #include #include #include @@ -75,9 +93,11 @@ #include "elf/mmix.h" #include "elf/mn10200.h" #include "elf/mn10300.h" +#include "elf/msp430.h" #include "elf/or32.h" #include "elf/pj.h" #include "elf/ppc.h" +#include "elf/ppc64.h" #include "elf/s390.h" #include "elf/sh.h" #include "elf/sparc.h" @@ -85,11 +105,18 @@ #include "elf/vax.h" #include "elf/x86-64.h" #include "elf/xstormy16.h" +#include "elf/iq2000.h" +#include "elf/xtensa.h" + +#include "aout/ar.h" #include "bucomm.h" #include "getopt.h" +#include "libiberty.h" char *program_name = "readelf"; +long archive_file_offset; +unsigned long archive_file_size; unsigned long dynamic_addr; bfd_size_type dynamic_size; char *dynamic_strings; @@ -101,11 +128,11 @@ Elf_Internal_Syminfo *dynamic_syminfo; unsigned long dynamic_syminfo_offset; unsigned int dynamic_syminfo_nent; char program_interpreter[64]; -long dynamic_info[DT_JMPREL + 1]; -long version_info[16]; -long loadaddr = 0; +bfd_vma dynamic_info[DT_JMPREL + 1]; +bfd_vma version_info[16]; Elf_Internal_Ehdr elf_header; Elf_Internal_Shdr *section_headers; +Elf_Internal_Phdr *program_headers; Elf_Internal_Dyn *dynamic_segment; Elf_Internal_Shdr *symtab_shndx_hdr; int show_name; @@ -157,224 +184,8 @@ typedef enum print_mode } print_mode; -/* Forward declarations for dumb compilers. */ -static void print_vma - PARAMS ((bfd_vma, print_mode)); -static void print_symbol - PARAMS ((int, const char *)); -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_ppc64_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 slurp_rela_relocs - PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rela **, - unsigned long *)); -static int slurp_rel_relocs - PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rela **, - 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_ia64_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_ia64_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, char **)); -static int process_file_header - PARAMS ((void)); -static int process_program_headers - PARAMS ((FILE *)); -static int process_section_headers - PARAMS ((FILE *)); -static int process_unwind - PARAMS ((FILE *)); -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_syminfo - PARAMS ((FILE *)); -static int process_section_contents - PARAMS ((FILE *)); -static void process_mips_fpe_exception - PARAMS ((int)); -static int process_mips_specific - PARAMS ((FILE *)); -static int 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)); -static int get_32bit_section_headers - PARAMS ((FILE *, unsigned int)); -static int get_64bit_section_headers - PARAMS ((FILE *, unsigned int)); -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 *, Elf_Internal_Shdr *)); -static Elf_Internal_Sym *get_64bit_elf_symbols - PARAMS ((FILE *, Elf_Internal_Shdr *)); -static const char *get_elf_section_flags - PARAMS ((bfd_vma)); -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 ((Elf_Internal_Shdr *, FILE *)); -#endif -static int dump_section - PARAMS ((Elf_Internal_Shdr *, FILE *)); -static int display_debug_section - PARAMS ((Elf_Internal_Shdr *, FILE *)); -static int display_debug_info - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_not_supported - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int prescan_debug_info - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_lines - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_pubnames - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_abbrev - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_aranges - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_frames - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_macinfo - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_str - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static int display_debug_loc - PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); -static unsigned char *process_abbrev_section - PARAMS ((unsigned char *, unsigned char *)); -static void load_debug_str - PARAMS ((FILE *)); -static void free_debug_str - PARAMS ((void)); -static const char *fetch_indirect_string - PARAMS ((unsigned long)); -static void load_debug_loc - PARAMS ((FILE *)); -static void free_debug_loc - PARAMS ((void)); -static unsigned long read_leb128 - PARAMS ((unsigned char *, int *, 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)); -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, - unsigned long)); -static unsigned char *read_and_display_attr_value - 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, unsigned long)); -static void request_dump - PARAMS ((unsigned int, int)); -static const char *get_elf_class - PARAMS ((unsigned int)); -static const char *get_data_encoding - PARAMS ((unsigned int)); -static const char *get_osabi_name - PARAMS ((unsigned int)); -static int guess_is_rela - PARAMS ((unsigned long)); -static const char *get_note_type - PARAMS ((unsigned int)); -static const char *get_netbsd_elfcore_note_type - PARAMS ((unsigned int)); -static int process_note - PARAMS ((Elf_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 *)); -static int process_arch_specific - PARAMS ((FILE *)); -static int process_gnu_liblist - PARAMS ((FILE *)); +static bfd_vma (*byte_get) (unsigned char *, int); +static void (*byte_put) (unsigned char *, bfd_vma, int); typedef int Elf32_Word; @@ -400,7 +211,7 @@ typedef int Elf32_Word; #define SECTION_HEADER(I) (section_headers + SECTION_HEADER_INDEX (I)) -#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ +#define DT_VERSIONTAGIDX(tag) (DT_VERNEEDNUM - (tag)) /* Reverse order! */ #define BYTE_GET(field) byte_get (field, sizeof (field)) @@ -426,56 +237,50 @@ typedef int Elf32_Word; static void -error VPARAMS ((const char *message, ...)) +error (const char *message, ...) { - VA_OPEN (args, message); - VA_FIXEDARG (args, const char *, message); + va_list args; + va_start (args, message); fprintf (stderr, _("%s: Error: "), program_name); vfprintf (stderr, message, args); - VA_CLOSE (args); + va_end (args); } static void -warn VPARAMS ((const char *message, ...)) +warn (const char *message, ...) { - VA_OPEN (args, message); - VA_FIXEDARG (args, const char *, message); + va_list args; + va_start (args, message); fprintf (stderr, _("%s: Warning: "), program_name); vfprintf (stderr, message, args); - VA_CLOSE (args); + va_end (args); } -static PTR get_data PARAMS ((PTR, FILE *, long, size_t, const char *)); - -static PTR -get_data (var, file, offset, size, reason) - PTR var; - FILE *file; - long offset; - size_t size; - const char *reason; +static void * +get_data (void *var, FILE *file, long offset, size_t size, const char *reason) { - PTR mvar; + void *mvar; if (size == 0) return NULL; - if (fseek (file, offset, SEEK_SET)) + if (fseek (file, archive_file_offset + offset, SEEK_SET)) { - error (_("Unable to seek to %x for %s\n"), offset, reason); + error (_("Unable to seek to 0x%x for %s\n"), + archive_file_offset + offset, reason); return NULL; } mvar = var; if (mvar == NULL) { - mvar = (PTR) malloc (size); + mvar = malloc (size); if (mvar == NULL) { - error (_("Out of memory allocating %d bytes for %s\n"), + error (_("Out of memory allocating 0x%x bytes for %s\n"), size, reason); return NULL; } @@ -483,7 +288,7 @@ get_data (var, file, offset, size, reason) if (fread (mvar, size, 1, file) != 1) { - error (_("Unable to read in %d bytes of %s\n"), size, reason); + error (_("Unable to read in 0x%x bytes of %s\n"), size, reason); if (mvar != var) free (mvar); return NULL; @@ -493,9 +298,7 @@ get_data (var, file, offset, size, reason) } static bfd_vma -byte_get_little_endian (field, size) - unsigned char *field; - int size; +byte_get_little_endian (unsigned char *field, int size) { switch (size) { @@ -525,7 +328,7 @@ byte_get_little_endian (field, size) /* 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. */ + in an internal structure. */ return ((bfd_vma) (field[0])) | (((bfd_vma) (field[1])) << 8) | (((bfd_vma) (field[2])) << 16) @@ -541,11 +344,58 @@ byte_get_little_endian (field, size) } } +static bfd_vma +byte_get_signed (unsigned char *field, int size) +{ + bfd_vma x = byte_get (field, size); + + switch (size) + { + case 1: + return (x ^ 0x80) - 0x80; + case 2: + return (x ^ 0x8000) - 0x8000; + case 4: + return (x ^ 0x80000000) - 0x80000000; + case 8: + case -8: + return x; + default: + abort (); + } +} + +static void +byte_put_little_endian (unsigned char *field, bfd_vma value, int size) +{ + switch (size) + { + case 8: + field[7] = (((value >> 24) >> 24) >> 8) & 0xff; + field[6] = ((value >> 24) >> 24) & 0xff; + field[5] = ((value >> 24) >> 16) & 0xff; + field[4] = ((value >> 24) >> 8) & 0xff; + /* Fall through. */ + case 4: + field[3] = (value >> 24) & 0xff; + field[2] = (value >> 16) & 0xff; + /* Fall through. */ + case 2: + field[1] = (value >> 8) & 0xff; + /* Fall through. */ + case 1: + field[0] = value & 0xff; + break; + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + /* Print a VMA value. */ static void -print_vma (vma, mode) - bfd_vma vma; - print_mode mode; +print_vma (bfd_vma vma, print_mode mode) { #ifdef BFD64 if (is_32bit_elf) @@ -553,13 +403,34 @@ print_vma (vma, mode) { 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; + case FULL_HEX: + printf ("0x"); + /* Drop through. */ + case LONG_HEX: + printf ("%8.8lx", (unsigned long) vma); + break; + + case DEC_5: + if (vma <= 99999) + { + printf ("%5ld", (long) vma); + break; + } + /* Drop through. */ + case PREFIX_HEX: + printf ("0x"); + /* Drop through. */ + case HEX: + printf ("%lx", (unsigned long) vma); + break; + + case DEC: + printf ("%ld", (unsigned long) vma); + break; + + case UNSIGNED: + printf ("%lu", (unsigned long) vma); + break; } } #ifdef BFD64 @@ -569,7 +440,7 @@ print_vma (vma, mode) { case FULL_HEX: printf ("0x"); - /* drop through */ + /* Drop through. */ case LONG_HEX: printf_vma (vma); @@ -577,7 +448,7 @@ print_vma (vma, mode) case PREFIX_HEX: printf ("0x"); - /* drop through */ + /* Drop through. */ case HEX: #if BFD_HOST_64BIT_LONG @@ -604,13 +475,18 @@ print_vma (vma, mode) case DEC_5: #if BFD_HOST_64BIT_LONG - printf ("%5ld", vma); + if (vma <= 99999) + printf ("%5ld", vma); + else + printf ("%#lx", vma); #else if (_bfd_int64_high (vma)) /* ugg */ printf ("++%ld", _bfd_int64_low (vma)); - else + else if (vma <= 99999) printf ("%5ld", _bfd_int64_low (vma)); + else + printf ("%#lx", _bfd_int64_low (vma)); #endif break; @@ -637,9 +513,7 @@ print_vma (vma, mode) truncating or padding as necessary. */ static void -print_symbol (width, symbol) - int width; - const char *symbol; +print_symbol (int width, const char *symbol) { if (do_wide) printf ("%s", symbol); @@ -650,9 +524,7 @@ print_symbol (width, symbol) } static bfd_vma -byte_get_big_endian (field, size) - unsigned char *field; - int size; +byte_get_big_endian (unsigned char *field, int size) { switch (size) { @@ -682,7 +554,7 @@ byte_get_big_endian (field, size) /* 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. */ + in an internal structure. */ return ((bfd_vma) (field[7])) | (((bfd_vma) (field[6])) << 8) | (((bfd_vma) (field[5])) << 16) @@ -699,11 +571,42 @@ byte_get_big_endian (field, size) } } +static void +byte_put_big_endian (unsigned char *field, bfd_vma value, int size) +{ + switch (size) + { + case 8: + field[7] = value & 0xff; + field[6] = (value >> 8) & 0xff; + field[5] = (value >> 16) & 0xff; + field[4] = (value >> 24) & 0xff; + value >>= 16; + value >>= 16; + /* Fall through. */ + case 4: + field[3] = value & 0xff; + field[2] = (value >> 8) & 0xff; + value >>= 16; + /* Fall through. */ + case 2: + field[1] = value & 0xff; + value >>= 8; + /* Fall through. */ + case 1: + field[0] = value & 0xff; + break; + + default: + error (_("Unhandled data length: %d\n"), size); + abort (); + } +} + /* Guess the relocation size commonly used by the specific machines. */ static int -guess_is_rela (e_machine) - unsigned long e_machine; +guess_is_rela (unsigned long e_machine) { switch (e_machine) { @@ -715,7 +618,6 @@ guess_is_rela (e_machine) case EM_DLX: case EM_OPENRISC: case EM_OR32: - case EM_M32R: case EM_CYGNUS_M32R: case EM_D10V: case EM_CYGNUS_D10V: @@ -756,10 +658,16 @@ guess_is_rela (e_machine) case EM_S390: case EM_S390_OLD: case EM_MMIX: + case EM_MSP430: + case EM_MSP430_OLD: case EM_XSTORMY16: case EM_VAX: case EM_IP2K: case EM_IP2K_OLD: + case EM_IQ2000: + case EM_XTENSA: + case EM_XTENSA_OLD: + case EM_M32R: return TRUE; case EM_MMA: @@ -786,12 +694,11 @@ guess_is_rela (e_machine) } static int -slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp) - FILE *file; - unsigned long rel_offset; - unsigned long rel_size; - Elf_Internal_Rela **relasp; - unsigned long *nrelasp; +slurp_rela_relocs (FILE *file, + unsigned long rel_offset, + unsigned long rel_size, + Elf_Internal_Rela **relasp, + unsigned long *nrelasp) { Elf_Internal_Rela *relas; unsigned long nrelas; @@ -801,15 +708,13 @@ slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp) { Elf32_External_Rela *erelas; - erelas = (Elf32_External_Rela *) get_data (NULL, file, rel_offset, - rel_size, _("relocs")); + erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs")); if (!erelas) return 0; nrelas = rel_size / sizeof (Elf32_External_Rela); - relas = (Elf_Internal_Rela *) - malloc (nrelas * sizeof (Elf_Internal_Rela)); + relas = malloc (nrelas * sizeof (Elf_Internal_Rela)); if (relas == NULL) { @@ -830,15 +735,13 @@ slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp) { Elf64_External_Rela *erelas; - erelas = (Elf64_External_Rela *) get_data (NULL, file, rel_offset, - rel_size, _("relocs")); + erelas = get_data (NULL, file, rel_offset, rel_size, _("relocs")); if (!erelas) return 0; nrelas = rel_size / sizeof (Elf64_External_Rela); - relas = (Elf_Internal_Rela *) - malloc (nrelas * sizeof (Elf_Internal_Rela)); + relas = malloc (nrelas * sizeof (Elf_Internal_Rela)); if (relas == NULL) { @@ -861,12 +764,11 @@ slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp) } static int -slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp) - FILE *file; - unsigned long rel_offset; - unsigned long rel_size; - Elf_Internal_Rela **relsp; - unsigned long *nrelsp; +slurp_rel_relocs (FILE *file, + unsigned long rel_offset, + unsigned long rel_size, + Elf_Internal_Rela **relsp, + unsigned long *nrelsp) { Elf_Internal_Rela *rels; unsigned long nrels; @@ -876,14 +778,13 @@ slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp) { Elf32_External_Rel *erels; - erels = (Elf32_External_Rel *) get_data (NULL, file, rel_offset, - rel_size, _("relocs")); + erels = get_data (NULL, file, rel_offset, rel_size, _("relocs")); if (!erels) return 0; nrels = rel_size / sizeof (Elf32_External_Rel); - rels = (Elf_Internal_Rela *) malloc (nrels * sizeof (Elf_Internal_Rela)); + rels = malloc (nrels * sizeof (Elf_Internal_Rela)); if (rels == NULL) { @@ -904,14 +805,13 @@ slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp) { Elf64_External_Rel *erels; - erels = (Elf64_External_Rel *) get_data (NULL, file, rel_offset, - rel_size, _("relocs")); + erels = get_data (NULL, file, rel_offset, rel_size, _("relocs")); if (!erels) return 0; nrels = rel_size / sizeof (Elf64_External_Rel); - rels = (Elf_Internal_Rela *) malloc (nrels * sizeof (Elf_Internal_Rela)); + rels = malloc (nrels * sizeof (Elf_Internal_Rela)); if (rels == NULL) { @@ -933,16 +833,17 @@ slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp) return 1; } -/* 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, 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; +dump_relocations (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_Rela *rels; @@ -984,14 +885,14 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) if (is_rela) { if (do_wide) - printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n")); + printf (_(" Offset Info Type Symbol's Value Symbol's Name + Addend\n")); else printf (_(" Offset Info Type Sym. Value Sym. Name + Addend\n")); } else { if (do_wide) - printf (_(" Offset Info Type Symbol's Value Symbol's Name\n")); + printf (_(" Offset Info Type Symbol's Value Symbol's Name\n")); else printf (_(" Offset Info Type Sym. Value Sym. Name\n")); } @@ -1006,8 +907,8 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) bfd_vma info; bfd_vma symtab_index; bfd_vma type; - bfd_vma type2 = (bfd_vma) NULL; - bfd_vma type3 = (bfd_vma) NULL; + bfd_vma type2 = 0; + bfd_vma type3 = 0; offset = rels[i].r_offset; info = rels[i].r_info; @@ -1019,8 +920,22 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) } else { + /* 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 if (elf_header.e_machine == EM_MIPS) { + /* In little-endian objects, r_info isn't really a 64-bit + little-endian value: it has a 32-bit little-endian + symbol index followed by four individual byte fields. + Reorder INFO accordingly. */ + if (elf_header.e_ident[EI_DATA] != ELFDATA2MSB) + info = (((info & 0xffffffff) << 32) + | ((info >> 56) & 0xff) + | ((info >> 40) & 0xff00) + | ((info >> 24) & 0xff0000) + | ((info >> 8) & 0xff000000)); type = ELF64_MIPS_R_TYPE (info); type2 = ELF64_MIPS_R_TYPE2 (info); type3 = ELF64_MIPS_R_TYPE3 (info); @@ -1029,10 +944,7 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) 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 } @@ -1154,11 +1066,19 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) rtype = elf_mmix_reloc_type (type); break; + case EM_MSP430: + case EM_MSP430_OLD: + rtype = elf_msp430_reloc_type (type); + break; + case EM_PPC: - case EM_PPC64: rtype = elf_ppc_reloc_type (type); break; + case EM_PPC64: + rtype = elf_ppc64_reloc_type (type); + break; + case EM_MIPS: case EM_MIPS_RS3_LE: rtype = elf_mips_reloc_type (type); @@ -1237,6 +1157,15 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) case EM_IP2K_OLD: rtype = elf_ip2k_reloc_type (type); break; + + case EM_IQ2000: + rtype = elf_iq2000_reloc_type (type); + break; + + case EM_XTENSA_OLD: + case EM_XTENSA: + rtype = elf_xtensa_reloc_type (type); + break; } if (rtype == NULL) @@ -1246,7 +1175,7 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) printf (_("unrecognized: %-7lx"), type); #endif else - printf (do_wide ? "%-21.21s" : "%-17.17s", rtype); + printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); if (symtab_index) { @@ -1283,6 +1212,10 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) sec_name = "ABS"; else if (psym->st_shndx == SHN_COMMON) sec_name = "COMMON"; + else if (elf_header.e_machine == EM_IA_64 + && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX + && psym->st_shndx == SHN_IA_64_ANSI_COMMON) + sec_name = "ANSI_COM"; else { sprintf (name_buf, "
", @@ -1347,8 +1280,7 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) } static const char * -get_mips_dynamic_type (type) - unsigned long type; +get_mips_dynamic_type (unsigned long type) { switch (type) { @@ -1401,8 +1333,7 @@ get_mips_dynamic_type (type) } static const char * -get_sparc64_dynamic_type (type) - unsigned long type; +get_sparc64_dynamic_type (unsigned long type) { switch (type) { @@ -1413,8 +1344,7 @@ get_sparc64_dynamic_type (type) } static const char * -get_ppc64_dynamic_type (type) - unsigned long type; +get_ppc64_dynamic_type (unsigned long type) { switch (type) { @@ -1427,8 +1357,7 @@ get_ppc64_dynamic_type (type) } static const char * -get_parisc_dynamic_type (type) - unsigned long type; +get_parisc_dynamic_type (unsigned long type) { switch (type) { @@ -1451,8 +1380,18 @@ get_parisc_dynamic_type (type) } static const char * -get_dynamic_type (type) - unsigned long type; +get_ia64_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_IA_64_PLT_RESERVE: return "IA_64_PLT_RESERVE"; + default: + return NULL; + } +} + +static const char * +get_dynamic_type (unsigned long type) { static char buff[32]; @@ -1547,6 +1486,9 @@ get_dynamic_type (type) case EM_PPC64: result = get_ppc64_dynamic_type (type); break; + case EM_IA_64: + result = get_ia64_dynamic_type (type); + break; default: result = NULL; break; @@ -1584,8 +1526,7 @@ get_dynamic_type (type) } static char * -get_file_type (e_type) - unsigned e_type; +get_file_type (unsigned e_type) { static char buff[32]; @@ -1609,8 +1550,7 @@ get_file_type (e_type) } static char * -get_machine_name (e_machine) - unsigned e_machine; +get_machine_name (unsigned e_machine) { static char buff[64]; /* XXX */ @@ -1640,14 +1580,14 @@ get_machine_name (e_machine) case EM_MCORE: return "MCORE"; case EM_ARM: return "ARM"; case EM_OLD_ALPHA: return "Digital Alpha (old)"; - case EM_SH: return "Hitachi SH"; + case EM_SH: return "Renesas / SuperH SH"; case EM_SPARCV9: return "Sparc v9"; case EM_TRICORE: return "Siemens Tricore"; case EM_ARC: return "ARC"; - case EM_H8_300: return "Hitachi H8/300"; - case EM_H8_300H: return "Hitachi H8/300H"; - case EM_H8S: return "Hitachi H8S"; - case EM_H8_500: return "Hitachi H8/500"; + case EM_H8_300: return "Renesas H8/300"; + case EM_H8_300H: return "Renesas H8/300H"; + case EM_H8S: return "Renesas H8S"; + case EM_H8_500: return "Renesas H8/500"; case EM_IA_64: return "Intel IA-64"; case EM_MIPS_X: return "Stanford MIPS-X"; case EM_COLDFIRE: return "Motorola Coldfire"; @@ -1658,7 +1598,7 @@ get_machine_name (e_machine) case EM_CYGNUS_D30V: case EM_D30V: return "d30v"; case EM_CYGNUS_M32R: - case EM_M32R: return "Mitsubishi M32r"; + case EM_M32R: return "Renesas M32R (formerly Mitsubishi M32r)"; case EM_CYGNUS_V850: case EM_V850: return "NEC v850"; case EM_CYGNUS_MN10300: @@ -1696,7 +1636,7 @@ get_machine_name (e_machine) case EM_ZSP: return "LSI Logic's 16-bit DSP processor"; case EM_MMIX: return "Donald Knuth's educational 64-bit processor"; case EM_HUANY: return "Harvard Universitys's machine-independent object format"; - case EM_PRISM: return "SiTera Prism"; + case EM_PRISM: return "Vitesse Prism"; case EM_X86_64: return "Advanced Micro Devices X86-64"; case EM_S390_OLD: case EM_S390: return "IBM S/390"; @@ -1706,6 +1646,9 @@ get_machine_name (e_machine) case EM_DLX: return "OpenDLX"; case EM_IP2K_OLD: case EM_IP2K: return "Ubicom IP2xxx 8-bit microcontrollers"; + case EM_IQ2000: return "Vitesse IQ2000"; + case EM_XTENSA_OLD: + case EM_XTENSA: return "Tensilica Xtensa Processor"; default: sprintf (buff, _(": %x"), e_machine); return buff; @@ -1713,9 +1656,7 @@ get_machine_name (e_machine) } static void -decode_ARM_machine_flags (e_flags, buf) - unsigned e_flags; - char buf[]; +decode_ARM_machine_flags (unsigned e_flags, char buf[]) { unsigned eabi; int unknown = 0; @@ -1843,6 +1784,10 @@ decode_ARM_machine_flags (e_flags, buf) strcat (buf, ", software FP"); break; + case EF_ARM_MAVERICK_FLOAT: + strcat (buf, ", Maverick FP"); + break; + default: unknown = 1; break; @@ -1855,9 +1800,7 @@ decode_ARM_machine_flags (e_flags, buf) } static char * -get_machine_flags (e_flags, e_machine) - unsigned e_flags; - unsigned e_machine; +get_machine_flags (unsigned e_flags, unsigned e_machine) { static char buf[1024]; @@ -1896,6 +1839,9 @@ get_machine_flags (e_flags, e_machine) case EM_CYGNUS_V850: switch (e_flags & EF_V850_ARCH) { + case E_V850E1_ARCH: + strcat (buf, ", v850e1"); + break; case E_V850E_ARCH: strcat (buf, ", v850e"); break; @@ -1986,7 +1932,9 @@ get_machine_flags (e_flags, e_machine) case E_MIPS_ARCH_4: strcat (buf, ", mips4"); break; case E_MIPS_ARCH_5: strcat (buf, ", mips5"); break; case E_MIPS_ARCH_32: strcat (buf, ", mips32"); break; + case E_MIPS_ARCH_32R2: strcat (buf, ", mips32r2"); break; case E_MIPS_ARCH_64: strcat (buf, ", mips64"); break; + case E_MIPS_ARCH_64R2: strcat (buf, ", mips64r2"); break; default: strcat (buf, ", unknown ISA"); break; } @@ -2086,8 +2034,37 @@ get_machine_flags (e_flags, e_machine) } static const char * -get_mips_segment_type (type) - unsigned long type; +get_osabi_name (unsigned int osabi) +{ + static char buff[32]; + + switch (osabi) + { + 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_AIX: return "UNIX - AIX"; + 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_OPENVMS: return "VMS - OpenVMS"; + case ELFOSABI_NSK: return "HP - Non-Stop Kernel"; + case ELFOSABI_AROS: return "Amiga Research OS"; + case ELFOSABI_STANDALONE: return _("Standalone App"); + case ELFOSABI_ARM: return "ARM"; + default: + sprintf (buff, _(""), osabi); + return buff; + } +} + +static const char * +get_mips_segment_type (unsigned long type) { switch (type) { @@ -2105,8 +2082,7 @@ get_mips_segment_type (type) } static const char * -get_parisc_segment_type (type) - unsigned long type; +get_parisc_segment_type (unsigned long type) { switch (type) { @@ -2132,8 +2108,7 @@ get_parisc_segment_type (type) } static const char * -get_ia64_segment_type (type) - unsigned long type; +get_ia64_segment_type (unsigned long type) { switch (type) { @@ -2151,8 +2126,7 @@ get_ia64_segment_type (type) } static const char * -get_segment_type (p_type) - unsigned long p_type; +get_segment_type (unsigned long p_type) { static char buff[32]; @@ -2169,6 +2143,7 @@ get_segment_type (p_type) case PT_GNU_EH_FRAME: return "GNU_EH_FRAME"; + case PT_GNU_STACK: return "STACK"; default: if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC)) @@ -2227,8 +2202,7 @@ get_segment_type (p_type) } static const char * -get_mips_section_type_name (sh_type) - unsigned int sh_type; +get_mips_section_type_name (unsigned int sh_type) { switch (sh_type) { @@ -2278,8 +2252,7 @@ get_mips_section_type_name (sh_type) } static const char * -get_parisc_section_type_name (sh_type) - unsigned int sh_type; +get_parisc_section_type_name (unsigned int sh_type) { switch (sh_type) { @@ -2293,13 +2266,17 @@ get_parisc_section_type_name (sh_type) } static const char * -get_ia64_section_type_name (sh_type) - unsigned int sh_type; +get_ia64_section_type_name (unsigned int sh_type) { + /* If the top 8 bits are 0x78 the next 8 are the os/abi ID. */ + if ((sh_type & 0xFF000000) == SHT_IA_64_LOPSREG) + return get_osabi_name ((sh_type & 0x00FF0000) >> 16); + switch (sh_type) { - case SHT_IA_64_EXT: return "IA_64_EXT"; - case SHT_IA_64_UNWIND: return "IA_64_UNWIND"; + case SHT_IA_64_EXT: return "IA_64_EXT"; + case SHT_IA_64_UNWIND: return "IA_64_UNWIND"; + case SHT_IA_64_PRIORITY_INIT: return "IA_64_PRIORITY_INIT"; default: break; } @@ -2307,8 +2284,7 @@ get_ia64_section_type_name (sh_type) } static const char * -get_section_type_name (sh_type) - unsigned int sh_type; +get_section_type_name (unsigned int sh_type) { static char buff[32]; @@ -2412,7 +2388,7 @@ struct option options[] = }; static void -usage () +usage (void) { fprintf (stdout, _("Usage: readelf elf-file(s)\n")); fprintf (stdout, _(" Display information about the contents of ELF format files\n")); @@ -2453,15 +2429,13 @@ usage () } static void -request_dump (section, type) - unsigned int section; - int type; +request_dump (unsigned int section, int type) { if (section >= num_dump_sects) { char *new_dump_sects; - new_dump_sects = (char *) calloc (section + 1, 1); + new_dump_sects = calloc (section + 1, 1); if (new_dump_sects == NULL) error (_("Out of memory allocating dump request table.")); @@ -2484,9 +2458,7 @@ request_dump (section, type) } static void -parse_args (argc, argv) - int argc; - char **argv; +parse_args (int argc, char **argv) { int c; @@ -2494,7 +2466,7 @@ parse_args (argc, argv) usage (); while ((c = getopt_long - (argc, argv, "ersuahnldSDAIw::x:i:vVW", options, NULL)) != EOF) + (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF) { char *cp; int section; @@ -2757,8 +2729,7 @@ parse_args (argc, argv) } static const char * -get_elf_class (elf_class) - unsigned int elf_class; +get_elf_class (unsigned int elf_class) { static char buff[32]; @@ -2774,8 +2745,7 @@ get_elf_class (elf_class) } static const char * -get_data_encoding (encoding) - unsigned int encoding; +get_data_encoding (unsigned int encoding) { static char buff[32]; @@ -2790,37 +2760,10 @@ get_data_encoding (encoding) } } -static const char * -get_osabi_name (osabi) - unsigned int osabi; -{ - static char buff[32]; - - switch (osabi) - { - 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_AIX: return "UNIX - AIX"; - 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"); - case ELFOSABI_ARM: return "ARM"; - default: - sprintf (buff, _(""), osabi); - return buff; - } -} - /* Decode the data held in 'elf_header'. */ + static int -process_file_header () +process_file_header (void) { if ( elf_header.e_ident[EI_MAG0] != ELFMAG0 || elf_header.e_ident[EI_MAG1] != ELFMAG1 @@ -2909,19 +2852,16 @@ process_file_header () static int -get_32bit_program_headers (file, program_headers) - FILE *file; - Elf_Internal_Phdr *program_headers; +get_32bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers) { Elf32_External_Phdr *phdrs; Elf32_External_Phdr *external; Elf_Internal_Phdr *internal; unsigned int i; - phdrs = ((Elf32_External_Phdr *) - get_data (NULL, file, elf_header.e_phoff, - elf_header.e_phentsize * elf_header.e_phnum, - _("program headers"))); + phdrs = get_data (NULL, file, elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + _("program headers")); if (!phdrs) return 0; @@ -2945,19 +2885,16 @@ get_32bit_program_headers (file, program_headers) } static int -get_64bit_program_headers (file, program_headers) - FILE *file; - Elf_Internal_Phdr *program_headers; +get_64bit_program_headers (FILE *file, Elf_Internal_Phdr *program_headers) { Elf64_External_Phdr *phdrs; Elf64_External_Phdr *external; Elf_Internal_Phdr *internal; unsigned int i; - phdrs = ((Elf64_External_Phdr *) - get_data (NULL, file, elf_header.e_phoff, - elf_header.e_phentsize * elf_header.e_phnum, - _("program headers"))); + phdrs = get_data (NULL, file, elf_header.e_phoff, + elf_header.e_phentsize * elf_header.e_phnum, + _("program headers")); if (!phdrs) return 0; @@ -2980,13 +2917,42 @@ get_64bit_program_headers (file, program_headers) return 1; } +/* Returns 1 if the program headers were read into `program_headers'. */ + +static int +get_program_headers (FILE *file) +{ + Elf_Internal_Phdr *phdrs; + + /* Check cache of prior read. */ + if (program_headers != NULL) + return 1; + + phdrs = malloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); + + if (phdrs == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + if (is_32bit_elf + ? get_32bit_program_headers (file, phdrs) + : get_64bit_program_headers (file, phdrs)) + { + program_headers = phdrs; + return 1; + } + + free (phdrs); + return 0; +} + /* Returns 1 if the program headers were loaded. */ static int -process_program_headers (file) - FILE *file; +process_program_headers (FILE *file) { - Elf_Internal_Phdr *program_headers; Elf_Internal_Phdr *segment; unsigned int i; @@ -3008,25 +2974,8 @@ process_program_headers (file) printf ("\n"); } - 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); + if (! get_program_headers (file)) return 0; - } if (do_segments) { @@ -3050,7 +2999,6 @@ process_program_headers (file) } } - loadaddr = -1; dynamic_addr = 0; dynamic_size = 0; @@ -3138,18 +3086,6 @@ process_program_headers (file) switch (segment->p_type) { - case PT_LOAD: - if (loadaddr == -1) - { - unsigned long align_mask = -segment->p_align; - - if (align_mask == 0) - --align_mask; - loadaddr = ((segment->p_vaddr & align_mask) - - (segment->p_offset & align_mask)); - } - break; - case PT_DYNAMIC: if (dynamic_addr) error (_("more than one dynamic segment\n")); @@ -3159,7 +3095,8 @@ process_program_headers (file) break; case PT_INTERP: - if (fseek (file, (long) segment->p_offset, SEEK_SET)) + if (fseek (file, archive_file_offset + (long) segment->p_offset, + SEEK_SET)) error (_("Unable to find program interpreter name\n")); else { @@ -3177,12 +3114,6 @@ process_program_headers (file) putc ('\n', stdout); } - if (loadaddr == -1) - { - /* Very strange. */ - loadaddr = 0; - } - if (do_segments && section_headers != NULL) { printf (_("\n Section to Segment mapping:\n")); @@ -3219,30 +3150,54 @@ process_program_headers (file) } } - free (program_headers); - return 1; } +/* Find the file offset corresponding to VMA by using the program headers. */ + +static long +offset_from_vma (FILE *file, bfd_vma vma, bfd_size_type size) +{ + Elf_Internal_Phdr *seg; + + if (! get_program_headers (file)) + { + warn (_("Cannot interpret virtual addresses without program headers.\n")); + return (long) vma; + } + + for (seg = program_headers; + seg < program_headers + elf_header.e_phnum; + ++seg) + { + if (seg->p_type != PT_LOAD) + continue; + + if (vma >= (seg->p_vaddr & -seg->p_align) + && vma + size <= seg->p_vaddr + seg->p_filesz) + return vma - seg->p_vaddr + seg->p_offset; + } + + warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"), + (long) vma); + return (long) vma; +} + + static int -get_32bit_section_headers (file, num) - FILE *file; - unsigned int num; +get_32bit_section_headers (FILE *file, unsigned int num) { Elf32_External_Shdr *shdrs; Elf_Internal_Shdr *internal; unsigned int i; - shdrs = ((Elf32_External_Shdr *) - get_data (NULL, file, elf_header.e_shoff, - elf_header.e_shentsize * num, - _("section headers"))); + shdrs = get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize * num, _("section headers")); if (!shdrs) return 0; - section_headers = ((Elf_Internal_Shdr *) - malloc (num * sizeof (Elf_Internal_Shdr))); + section_headers = malloc (num * sizeof (Elf_Internal_Shdr)); if (section_headers == NULL) { @@ -3272,23 +3227,18 @@ get_32bit_section_headers (file, num) } static int -get_64bit_section_headers (file, num) - FILE *file; - unsigned int num; +get_64bit_section_headers (FILE *file, unsigned int num) { Elf64_External_Shdr *shdrs; Elf_Internal_Shdr *internal; unsigned int i; - shdrs = ((Elf64_External_Shdr *) - get_data (NULL, file, elf_header.e_shoff, - elf_header.e_shentsize * num, - _("section headers"))); + shdrs = get_data (NULL, file, elf_header.e_shoff, + elf_header.e_shentsize * num, _("section headers")); if (!shdrs) return 0; - section_headers = ((Elf_Internal_Shdr *) - malloc (num * sizeof (Elf_Internal_Shdr))); + section_headers = malloc (num * sizeof (Elf_Internal_Shdr)); if (section_headers == NULL) { @@ -3318,9 +3268,7 @@ get_64bit_section_headers (file, num) } static Elf_Internal_Sym * -get_32bit_elf_symbols (file, section) - FILE *file; - Elf_Internal_Shdr *section; +get_32bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section) { unsigned long number; Elf32_External_Sym *esyms; @@ -3329,9 +3277,8 @@ get_32bit_elf_symbols (file, section) Elf_Internal_Sym *psym; unsigned int j; - esyms = ((Elf32_External_Sym *) - get_data (NULL, file, section->sh_offset, - section->sh_size, _("symbols"))); + esyms = get_data (NULL, file, section->sh_offset, section->sh_size, + _("symbols")); if (!esyms) return NULL; @@ -3340,9 +3287,8 @@ get_32bit_elf_symbols (file, section) && (symtab_shndx_hdr->sh_link == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) { - shndx = ((Elf_External_Sym_Shndx *) - get_data (NULL, file, symtab_shndx_hdr->sh_offset, - symtab_shndx_hdr->sh_size, _("symtab shndx"))); + shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, + symtab_shndx_hdr->sh_size, _("symtab shndx")); if (!shndx) { free (esyms); @@ -3351,7 +3297,7 @@ get_32bit_elf_symbols (file, section) } number = section->sh_size / section->sh_entsize; - isyms = (Elf_Internal_Sym *) malloc (number * sizeof (Elf_Internal_Sym)); + isyms = malloc (number * sizeof (Elf_Internal_Sym)); if (isyms == NULL) { @@ -3385,9 +3331,7 @@ get_32bit_elf_symbols (file, section) } static Elf_Internal_Sym * -get_64bit_elf_symbols (file, section) - FILE *file; - Elf_Internal_Shdr *section; +get_64bit_elf_symbols (FILE *file, Elf_Internal_Shdr *section) { unsigned long number; Elf64_External_Sym *esyms; @@ -3396,9 +3340,8 @@ get_64bit_elf_symbols (file, section) Elf_Internal_Sym *psym; unsigned int j; - esyms = ((Elf64_External_Sym *) - get_data (NULL, file, section->sh_offset, - section->sh_size, _("symbols"))); + esyms = get_data (NULL, file, section->sh_offset, section->sh_size, + _("symbols")); if (!esyms) return NULL; @@ -3407,9 +3350,8 @@ get_64bit_elf_symbols (file, section) && (symtab_shndx_hdr->sh_link == (unsigned long) SECTION_HEADER_NUM (section - section_headers))) { - shndx = ((Elf_External_Sym_Shndx *) - get_data (NULL, file, symtab_shndx_hdr->sh_offset, - symtab_shndx_hdr->sh_size, _("symtab shndx"))); + shndx = get_data (NULL, file, symtab_shndx_hdr->sh_offset, + symtab_shndx_hdr->sh_size, _("symtab shndx")); if (!shndx) { free (esyms); @@ -3418,7 +3360,7 @@ get_64bit_elf_symbols (file, section) } number = section->sh_size / section->sh_entsize; - isyms = (Elf_Internal_Sym *) malloc (number * sizeof (Elf_Internal_Sym)); + isyms = malloc (number * sizeof (Elf_Internal_Sym)); if (isyms == NULL) { @@ -3452,8 +3394,7 @@ get_64bit_elf_symbols (file, section) } static const char * -get_elf_section_flags (sh_flags) - bfd_vma sh_flags; +get_elf_section_flags (bfd_vma sh_flags) { static char buff[32]; @@ -3500,8 +3441,7 @@ get_elf_section_flags (sh_flags) } static int -process_section_headers (file) - FILE *file; +process_section_headers (FILE *file) { Elf_Internal_Shdr *section; unsigned int i; @@ -3533,8 +3473,11 @@ process_section_headers (file) if (section->sh_size != 0) { - string_table = (char *) get_data (NULL, file, section->sh_offset, - section->sh_size, _("string table")); + string_table = get_data (NULL, file, section->sh_offset, + section->sh_size, _("string table")); + + if (string_table == NULL) + return 0; string_table_length = section->sh_size; } @@ -3572,9 +3515,8 @@ process_section_headers (file) continue; } - dynamic_strings = (char *) get_data (NULL, file, section->sh_offset, - section->sh_size, - _("dynamic strings")); + dynamic_strings = get_data (NULL, file, section->sh_offset, + section->sh_size, _("dynamic strings")); } else if (section->sh_type == SHT_SYMTAB_SHNDX) { @@ -3734,10 +3676,22 @@ process_section_headers (file) return 1; } +struct +{ + const char *name; + int reloc; + int size; + int rela; +} dynamic_relocations [] = +{ + { "REL", DT_REL, DT_RELSZ, FALSE }, + { "RELA", DT_RELA, DT_RELASZ, TRUE }, + { "PLT", DT_JMPREL, DT_PLTRELSZ, UNKNOWN } +}; + /* Process the reloc section. */ static int -process_relocs (file) - FILE *file; +process_relocs (FILE *file) { unsigned long rel_size; unsigned long rel_offset; @@ -3748,53 +3702,51 @@ process_relocs (file) if (do_using_dynamic) { - int is_rela = FALSE; + int is_rela; + const char *name; + int has_dynamic_reloc; + unsigned int i; - rel_size = 0; - rel_offset = 0; + has_dynamic_reloc = 0; - if (dynamic_info[DT_REL]) - { - rel_offset = dynamic_info[DT_REL]; - rel_size = dynamic_info[DT_RELSZ]; - is_rela = FALSE; - } - else if (dynamic_info[DT_RELA]) - { - rel_offset = dynamic_info[DT_RELA]; - rel_size = dynamic_info[DT_RELASZ]; - is_rela = TRUE; - } - else if (dynamic_info[DT_JMPREL]) + for (i = 0; i < ARRAY_SIZE (dynamic_relocations); i++) { - rel_offset = dynamic_info[DT_JMPREL]; - rel_size = dynamic_info[DT_PLTRELSZ]; + is_rela = dynamic_relocations [i].rela; + name = dynamic_relocations [i].name; + rel_size = dynamic_info [dynamic_relocations [i].size]; + rel_offset = dynamic_info [dynamic_relocations [i].reloc]; + + has_dynamic_reloc |= rel_size; - switch (dynamic_info[DT_PLTREL]) + if (is_rela == UNKNOWN) { - case DT_REL: - is_rela = FALSE; - break; - case DT_RELA: - is_rela = TRUE; - break; - default: - is_rela = UNKNOWN; - break; + if (dynamic_relocations [i].reloc == DT_JMPREL) + switch (dynamic_info[DT_PLTREL]) + { + case DT_REL: + is_rela = FALSE; + break; + case DT_RELA: + is_rela = TRUE; + break; + } } - } - if (rel_size) - { - printf - (_("\nRelocation section at offset 0x%lx contains %ld bytes:\n"), - rel_offset, rel_size); - - dump_relocations (file, rel_offset - loadaddr, rel_size, - dynamic_symbols, num_dynamic_syms, dynamic_strings, - is_rela); + if (rel_size) + { + printf + (_("\n'%s' relocation section at offset 0x%lx contains %ld bytes:\n"), + name, rel_offset, rel_size); + + dump_relocations (file, + offset_from_vma (file, rel_offset, rel_size), + rel_size, + dynamic_symbols, num_dynamic_syms, + dynamic_strings, is_rela); + } } - else + + if (! has_dynamic_reloc) printf (_("\nThere are no dynamic relocations in this file.\n")); } else @@ -3848,9 +3800,8 @@ process_relocs (file) strsec = SECTION_HEADER (symsec->sh_link); - strtab = (char *) get_data (NULL, file, strsec->sh_offset, - strsec->sh_size, - _("string table")); + strtab = get_data (NULL, file, strsec->sh_offset, + strsec->sh_size, _("string table")); } is_rela = section->sh_type == SHT_RELA; @@ -3905,21 +3856,13 @@ struct unw_aux_info unsigned long strtab_size; /* Size of string table. */ }; -static void find_symbol_for_address - PARAMS ((struct unw_aux_info *, struct absaddr, const char **, bfd_vma *)); -static void dump_ia64_unwind - PARAMS ((struct unw_aux_info *)); -static int slurp_ia64_unwind_table - PARAMS ((FILE *, struct unw_aux_info *, Elf_Internal_Shdr *)); - static void -find_symbol_for_address (aux, addr, symname, offset) - struct unw_aux_info *aux; - struct absaddr addr; - const char **symname; - bfd_vma *offset; +find_symbol_for_address (struct unw_aux_info *aux, + struct absaddr addr, + const char **symname, + bfd_vma *offset) { - bfd_vma dist = (bfd_vma) 0x100000; + bfd_vma dist = 0x100000; Elf_Internal_Sym *sym, *best = NULL; unsigned long i; @@ -3949,8 +3892,7 @@ find_symbol_for_address (aux, addr, symname, offset) } static void -dump_ia64_unwind (aux) - struct unw_aux_info *aux; +dump_ia64_unwind (struct unw_aux_info *aux) { bfd_vma addr_size; struct unw_table_entry *tp; @@ -4008,20 +3950,18 @@ dump_ia64_unwind (aux) } static int -slurp_ia64_unwind_table (file, aux, sec) - FILE *file; - struct unw_aux_info *aux; - Elf_Internal_Shdr *sec; +slurp_ia64_unwind_table (FILE *file, + struct unw_aux_info *aux, + Elf_Internal_Shdr *sec) { unsigned long size, addr_size, nrelas, i; - Elf_Internal_Phdr *prog_hdrs, *seg; + Elf_Internal_Phdr *seg; struct unw_table_entry *tep; Elf_Internal_Shdr *relsec; Elf_Internal_Rela *rela, *rp; unsigned char *table, *tp; Elf_Internal_Sym *sym; const char *relname; - int result; addr_size = is_32bit_elf ? 4 : 8; @@ -4030,21 +3970,12 @@ slurp_ia64_unwind_table (file, aux, sec) if (elf_header.e_phnum) { - prog_hdrs = (Elf_Internal_Phdr *) - xmalloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr)); - - if (is_32bit_elf) - result = get_32bit_program_headers (file, prog_hdrs); - else - result = get_64bit_program_headers (file, prog_hdrs); - - if (!result) - { - free (prog_hdrs); + if (! get_program_headers (file)) return 0; - } - for (seg = prog_hdrs; seg < prog_hdrs + elf_header.e_phnum; ++seg) + for (seg = program_headers; + seg < program_headers + elf_header.e_phnum; + ++seg) { if (seg->p_type != PT_LOAD) continue; @@ -4056,14 +3987,11 @@ slurp_ia64_unwind_table (file, aux, sec) break; } } - - free (prog_hdrs); } /* Second, build the unwind table from the contents of the unwind section: */ size = sec->sh_size; - table = (char *) get_data (NULL, file, sec->sh_offset, - size, _("unwind table")); + table = get_data (NULL, file, sec->sh_offset, size, _("unwind table")); if (!table) return 0; @@ -4167,8 +4095,7 @@ slurp_ia64_unwind_table (file, aux, sec) } static int -process_unwind (file) - FILE *file; +process_unwind (FILE *file) { Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec; unsigned long i, addr_size, unwcount = 0, unwstart = 0; @@ -4196,8 +4123,8 @@ process_unwind (file) strsec = SECTION_HEADER (sec->sh_link); aux.strtab_size = strsec->sh_size; - aux.strtab = (char *) get_data (NULL, file, strsec->sh_offset, - aux.strtab_size, _("string table")); + aux.strtab = get_data (NULL, file, strsec->sh_offset, + aux.strtab_size, _("string table")); } else if (sec->sh_type == SHT_IA_64_UNWIND) unwcount++; @@ -4266,8 +4193,8 @@ process_unwind (file) { aux.info_size = sec->sh_size; aux.info_addr = sec->sh_addr; - aux.info = (char *) get_data (NULL, file, sec->sh_offset, - aux.info_size, _("unwind info")); + aux.info = get_data (NULL, file, sec->sh_offset, aux.info_size, + _("unwind info")); printf (_("\nUnwind section ")); @@ -4303,8 +4230,7 @@ process_unwind (file) } static void -dynamic_segment_mips_val (entry) - Elf_Internal_Dyn *entry; +dynamic_segment_mips_val (Elf_Internal_Dyn *entry) { switch (entry->d_tag) { @@ -4378,8 +4304,7 @@ dynamic_segment_mips_val (entry) static void -dynamic_segment_parisc_val (entry) - Elf_Internal_Dyn *entry; +dynamic_segment_parisc_val (Elf_Internal_Dyn *entry) { switch (entry->d_tag) { @@ -4434,16 +4359,34 @@ dynamic_segment_parisc_val (entry) putchar ('\n'); } +static void +dynamic_segment_ia64_val (Elf_Internal_Dyn *entry) +{ + switch (entry->d_tag) + { + case DT_IA_64_PLT_RESERVE: + /* First 3 slots reserved. */ + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + printf (" -- "); + print_vma (entry->d_un.d_ptr + (3 * 8), PREFIX_HEX); + break; + + default: + print_vma (entry->d_un.d_ptr, PREFIX_HEX); + break; + } + putchar ('\n'); +} + static int -get_32bit_dynamic_segment (file) - FILE *file; +get_32bit_dynamic_segment (FILE *file) { Elf32_External_Dyn *edyn; Elf_Internal_Dyn *entry; bfd_size_type i; - edyn = (Elf32_External_Dyn *) get_data (NULL, file, dynamic_addr, - dynamic_size, _("dynamic segment")); + edyn = get_data (NULL, file, dynamic_addr, dynamic_size, + _("dynamic segment")); if (!edyn) return 0; @@ -4454,8 +4397,7 @@ get_32bit_dynamic_segment (file) while (*(Elf32_Word *) edyn[dynamic_size++].d_tag != DT_NULL) ; - dynamic_segment = (Elf_Internal_Dyn *) - malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); + dynamic_segment = malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); if (dynamic_segment == NULL) { @@ -4478,15 +4420,14 @@ get_32bit_dynamic_segment (file) } static int -get_64bit_dynamic_segment (file) - FILE *file; +get_64bit_dynamic_segment (FILE *file) { Elf64_External_Dyn *edyn; Elf_Internal_Dyn *entry; bfd_size_type i; - edyn = (Elf64_External_Dyn *) get_data (NULL, file, dynamic_addr, - dynamic_size, _("dynamic segment")); + edyn = get_data (NULL, file, dynamic_addr, dynamic_size, + _("dynamic segment")); if (!edyn) return 0; @@ -4497,8 +4438,7 @@ get_64bit_dynamic_segment (file) while (*(bfd_vma *) edyn[dynamic_size++].d_tag != DT_NULL) ; - dynamic_segment = (Elf_Internal_Dyn *) - malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); + dynamic_segment = malloc (dynamic_size * sizeof (Elf_Internal_Dyn)); if (dynamic_segment == NULL) { @@ -4521,8 +4461,7 @@ get_64bit_dynamic_segment (file) } static const char * -get_dynamic_flags (flags) - bfd_vma flags; +get_dynamic_flags (bfd_vma flags) { static char buff[128]; char *p = buff; @@ -4555,8 +4494,7 @@ get_dynamic_flags (flags) /* Parse and display the contents of the dynamic segment. */ static int -process_dynamic_segment (file) - FILE *file; +process_dynamic_segment (FILE *file) { Elf_Internal_Dyn *entry; bfd_size_type i; @@ -4595,12 +4533,18 @@ process_dynamic_segment (file) we default to reading in the entire file (!) and processing that. This is overkill, I know, but it should work. */ - section.sh_offset = entry->d_un.d_val - loadaddr; + section.sh_offset = offset_from_vma (file, entry->d_un.d_val, 0); - if (fseek (file, 0, SEEK_END)) - error (_("Unable to seek to end of file!")); + if (archive_file_offset != 0) + section.sh_size = archive_file_size - section.sh_offset; + else + { + if (fseek (file, 0, SEEK_END)) + error (_("Unable to seek to end of file!")); + + section.sh_size = ftell (file) - section.sh_offset; + } - section.sh_size = ftell (file) - section.sh_offset; if (is_32bit_elf) section.sh_entsize = sizeof (Elf32_External_Sym); else @@ -4637,10 +4581,16 @@ process_dynamic_segment (file) 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\n")); - str_tab_len = ftell (file) - offset; + offset = offset_from_vma (file, entry->d_un.d_val, 0); + + if (archive_file_offset != 0) + str_tab_len = archive_file_size - offset; + else + { + if (fseek (file, 0, SEEK_END)) + error (_("Unable to seek to end of file\n")); + str_tab_len = ftell (file) - offset; + } if (str_tab_len < 1) { @@ -4649,8 +4599,8 @@ process_dynamic_segment (file) continue; } - dynamic_strings = (char *) get_data (NULL, file, offset, str_tab_len, - _("dynamic string table")); + dynamic_strings = get_data (NULL, file, offset, str_tab_len, + _("dynamic string table")); break; } } @@ -4673,7 +4623,8 @@ process_dynamic_segment (file) else if (entry->d_tag == DT_SYMINSZ) syminsz = entry->d_un.d_val; else if (entry->d_tag == DT_SYMINFO) - dynamic_syminfo_offset = entry->d_un.d_val - loadaddr; + dynamic_syminfo_offset = offset_from_vma (file, entry->d_un.d_val, + syminsz); } if (dynamic_syminfo_offset != 0 && syminsz != 0) @@ -4682,13 +4633,12 @@ process_dynamic_segment (file) Elf_Internal_Syminfo *syminfo; /* There is a syminfo section. Read the data. */ - extsyminfo = ((Elf_External_Syminfo *) - get_data (NULL, file, dynamic_syminfo_offset, - syminsz, _("symbol information"))); + extsyminfo = get_data (NULL, file, dynamic_syminfo_offset, syminsz, + _("symbol information")); if (!extsyminfo) return 0; - dynamic_syminfo = (Elf_Internal_Syminfo *) malloc (syminsz); + dynamic_syminfo = malloc (syminsz); if (dynamic_syminfo == NULL) { error (_("Out of memory\n")); @@ -4922,6 +4872,7 @@ process_dynamic_segment (file) break; case DT_PLTREL: + dynamic_info[entry->d_tag] = entry->d_un.d_val; if (do_dynamic) puts (get_dynamic_type (entry->d_un.d_val)); break; @@ -4996,6 +4947,7 @@ process_dynamic_segment (file) case DT_RELAENT : case DT_SYMENT : case DT_RELENT : + dynamic_info[entry->d_tag] = entry->d_un.d_val; case DT_PLTPADSZ: case DT_MOVEENT : case DT_MOVESZ : @@ -5083,6 +5035,9 @@ process_dynamic_segment (file) case EM_PARISC: dynamic_segment_parisc_val (entry); break; + case EM_IA_64: + dynamic_segment_ia64_val (entry); + break; default: print_vma (entry->d_un.d_val, PREFIX_HEX); putchar ('\n'); @@ -5096,8 +5051,7 @@ process_dynamic_segment (file) } static char * -get_ver_flags (flags) - unsigned int flags; +get_ver_flags (unsigned int flags) { static char buff[32]; @@ -5125,8 +5079,7 @@ get_ver_flags (flags) /* Display the contents of the version sections. */ static int -process_version_sections (file) - FILE *file; +process_version_sections (FILE *file) { Elf_Internal_Shdr *section; unsigned i; @@ -5159,10 +5112,8 @@ process_version_sections (file) (unsigned long) section->sh_offset, section->sh_link, SECTION_NAME (SECTION_HEADER (section->sh_link))); - edefs = ((Elf_External_Verdef *) - get_data (NULL, file, section->sh_offset, - section->sh_size, - _("version definition section"))); + edefs = get_data (NULL, file, section->sh_offset, section->sh_size, + _("version definition section")); if (!edefs) break; @@ -5250,9 +5201,8 @@ process_version_sections (file) (unsigned long) section->sh_offset, section->sh_link, SECTION_NAME (SECTION_HEADER (section->sh_link))); - eneed = ((Elf_External_Verneed *) - get_data (NULL, file, section->sh_offset, - section->sh_size, _("version need section"))); + eneed = get_data (NULL, file, section->sh_offset, section->sh_size, + _("version need section")); if (!eneed) break; @@ -5299,10 +5249,10 @@ process_version_sections (file) aux.vna_next = BYTE_GET (eaux->vna_next); if (dynamic_strings) - printf (_(" %#06x: Name: %s"), + printf (_(" %#06x: Name: %s"), isum, dynamic_strings + aux.vna_name); else - printf (_(" %#06x: Name index: %lx"), + printf (_(" %#06x: Name index: %lx"), isum, aux.vna_name); printf (_(" Flags: %s Version: %d\n"), @@ -5329,6 +5279,7 @@ process_version_sections (file) char *strtab; Elf_Internal_Sym *symbols; Elf_Internal_Shdr *string_sec; + long off; link_section = SECTION_HEADER (section->sh_link); total = section->sh_size / section->sh_entsize; @@ -5339,9 +5290,8 @@ process_version_sections (file) string_sec = SECTION_HEADER (link_section->sh_link); - strtab = (char *) get_data (NULL, file, string_sec->sh_offset, - string_sec->sh_size, - _("version string table")); + strtab = get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, _("version string table")); if (!strtab) break; @@ -5354,18 +5304,18 @@ process_version_sections (file) (unsigned long) section->sh_offset, section->sh_link, SECTION_NAME (link_section)); - edata = - ((unsigned char *) - get_data (NULL, file, - version_info[DT_VERSIONTAGIDX (DT_VERSYM)] - loadaddr, - total * sizeof (short), _("version symbol data"))); + off = offset_from_vma (file, + version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + total * sizeof (short)); + edata = get_data (NULL, file, off, total * sizeof (short), + _("version symbol data")); if (!edata) { free (strtab); break; } - data = (unsigned short *) malloc (total * sizeof (short)); + data = malloc (total * sizeof (short)); for (cnt = total; cnt --;) data[cnt] = byte_get (edata + cnt * sizeof (short), @@ -5413,8 +5363,9 @@ process_version_sections (file) Elf_Internal_Verneed ivn; unsigned long offset; - offset = version_info[DT_VERSIONTAGIDX (DT_VERNEED)] - - loadaddr; + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof (Elf_External_Verneed)); do { @@ -5469,8 +5420,9 @@ process_version_sections (file) Elf_External_Verdef evd; unsigned long offset; - offset = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)] - - loadaddr); + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof evd); do { @@ -5531,8 +5483,7 @@ process_version_sections (file) } static const char * -get_symbol_binding (binding) - unsigned int binding; +get_symbol_binding (unsigned int binding) { static char buff[32]; @@ -5553,8 +5504,7 @@ get_symbol_binding (binding) } static const char * -get_symbol_type (type) - unsigned int type; +get_symbol_type (unsigned int type) { static char buff[32]; @@ -5600,8 +5550,7 @@ get_symbol_type (type) } static const char * -get_symbol_visibility (visibility) - unsigned int visibility; +get_symbol_visibility (unsigned int visibility) { switch (visibility) { @@ -5614,8 +5563,7 @@ get_symbol_visibility (visibility) } static const char * -get_symbol_index_type (type) - unsigned int type; +get_symbol_index_type (unsigned int type) { static char buff[32]; @@ -5625,7 +5573,11 @@ get_symbol_index_type (type) case SHN_ABS: return "ABS"; case SHN_COMMON: return "COM"; default: - if (type >= SHN_LOPROC && type <= SHN_HIPROC) + if (type == SHN_IA_64_ANSI_COMMON + && elf_header.e_machine == EM_IA_64 + && elf_header.e_ident[EI_OSABI] == ELFOSABI_HPUX) + return "ANSI_COM"; + else if (type >= SHN_LOPROC && type <= SHN_HIPROC) sprintf (buff, "PRC[0x%04x]", type); else if (type >= SHN_LOOS && type <= SHN_HIOS) sprintf (buff, "OS [0x%04x]", type); @@ -5640,14 +5592,12 @@ get_symbol_index_type (type) } static int * -get_dynamic_data (file, number) - FILE *file; - unsigned int number; +get_dynamic_data (FILE *file, unsigned int number) { unsigned char *e_data; int *i_data; - e_data = (unsigned char *) malloc (number * 4); + e_data = malloc (number * 4); if (e_data == NULL) { @@ -5661,7 +5611,7 @@ get_dynamic_data (file, number) return NULL; } - i_data = (int *) malloc (number * sizeof (*i_data)); + i_data = malloc (number * sizeof (*i_data)); if (i_data == NULL) { @@ -5680,8 +5630,7 @@ get_dynamic_data (file, number) /* Dump the symbol table. */ static int -process_symbol_table (file) - FILE *file; +process_symbol_table (FILE *file) { Elf_Internal_Shdr *section; unsigned char nb[4]; @@ -5697,7 +5646,11 @@ process_symbol_table (file) if (dynamic_info[DT_HASH] && ((do_using_dynamic && dynamic_strings != NULL) || do_histogram)) { - if (fseek (file, dynamic_info[DT_HASH] - loadaddr, SEEK_SET)) + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, dynamic_info[DT_HASH], + sizeof nb + sizeof nc)), + SEEK_SET)) { error (_("Unable to seek to start of dynamic information")); return 0; @@ -5800,9 +5753,8 @@ process_symbol_table (file) string_sec = SECTION_HEADER (section->sh_link); - strtab = (char *) get_data (NULL, file, string_sec->sh_offset, - string_sec->sh_size, - _("string table")); + strtab = get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, _("string table")); } for (si = 0, psym = symtab; @@ -5828,8 +5780,9 @@ process_symbol_table (file) int is_nobits; int check_def; - offset = version_info[DT_VERSIONTAGIDX (DT_VERSYM)] - - loadaddr; + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERSYM)], + sizeof data + si * sizeof (vers_data)); get_data (&data, file, offset + si * sizeof (vers_data), sizeof (data), _("version data")); @@ -5851,8 +5804,9 @@ process_symbol_table (file) Elf_Internal_Vernaux ivna; /* We must test both. */ - offset = (version_info[DT_VERSIONTAGIDX (DT_VERNEED)] - - loadaddr); + offset = offset_from_vma + (file, version_info[DT_VERSIONTAGIDX (DT_VERNEED)], + sizeof evn); do { @@ -5912,9 +5866,10 @@ process_symbol_table (file) Elf_External_Verdaux evda; unsigned long offset; - offset - = (version_info[DT_VERSIONTAGIDX (DT_VERDEF)] - - loadaddr); + offset = offset_from_vma + (file, + version_info[DT_VERSIONTAGIDX (DT_VERDEF)], + sizeof (Elf_External_Verdef)); do { @@ -5975,7 +5930,7 @@ process_symbol_table (file) nbuckets); printf (_(" Length Number %% of total Coverage\n")); - lengths = (int *) calloc (nbuckets, sizeof (int)); + lengths = calloc (nbuckets, sizeof (int)); if (lengths == NULL) { error (_("Out of memory")); @@ -5994,7 +5949,7 @@ process_symbol_table (file) } } - counts = (int *) calloc (maxlength + 1, sizeof (int)); + counts = calloc (maxlength + 1, sizeof (int)); if (counts == NULL) { error (_("Out of memory")); @@ -6031,8 +5986,7 @@ process_symbol_table (file) } static int -process_syminfo (file) - FILE *file ATTRIBUTE_UNUSED; +process_syminfo (FILE *file ATTRIBUTE_UNUSED) { unsigned int i; @@ -6098,9 +6052,7 @@ process_syminfo (file) #ifdef SUPPORT_DISASSEMBLY static void -disassemble_section (section, file) - Elf_Internal_Shdr *section; - FILE *file; +disassemble_section (Elf_Internal_Shdr *section, FILE *file) { printf (_("\nAssembly dump of section %s\n"), SECTION_NAME (section)); @@ -6112,9 +6064,7 @@ disassemble_section (section, file) #endif static int -dump_section (section, file) - Elf_Internal_Shdr *section; - FILE *file; +dump_section (Elf_Internal_Shdr *section, FILE *file) { bfd_size_type bytes; bfd_vma addr; @@ -6123,7 +6073,7 @@ dump_section (section, file) bytes = section->sh_size; - if (bytes == 0) + if (bytes == 0 || section->sh_type == SHT_NOBITS) { printf (_("\nSection '%s' has no data to dump.\n"), SECTION_NAME (section)); @@ -6134,8 +6084,7 @@ dump_section (section, file) addr = section->sh_addr; - start = (unsigned char *) get_data (NULL, file, section->sh_offset, bytes, - _("section data")); + start = get_data (NULL, file, section->sh_offset, bytes, _("section data")); if (!start) return 0; @@ -6184,7 +6133,7 @@ dump_section (section, file) for (j = 0; j < lbytes; j++) { k = data[j]; - if (k >= ' ' && k < 0x80) + if (k >= ' ' && k < 0x7f) printf ("%c", k); else printf ("."); @@ -6204,10 +6153,7 @@ dump_section (section, file) static unsigned long int -read_leb128 (data, length_return, sign) - unsigned char *data; - int *length_return; - int sign; +read_leb128 (unsigned char *data, int *length_return, int sign) { unsigned long int result = 0; unsigned int num_read = 0; @@ -6252,8 +6198,7 @@ typedef struct State_Machine_Registers static SMR state_machine_regs; static void -reset_state_machine (is_stmt) - int is_stmt; +reset_state_machine (int is_stmt) { state_machine_regs.address = 0; state_machine_regs.file = 1; @@ -6268,10 +6213,7 @@ 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, pointer_size) - unsigned char *data; - int is_stmt; - int pointer_size; +process_extended_line_op (unsigned char *data, int is_stmt, int pointer_size) { unsigned char op_code; int bytes_read; @@ -6329,42 +6271,180 @@ process_extended_line_op (data, is_stmt, pointer_size) return len; } +/* Finds section NAME inside FILE and returns a + pointer to it, or NULL upon failure. */ + +static Elf_Internal_Shdr * +find_section (const char * name) +{ + Elf_Internal_Shdr *sec; + unsigned int i; + + for (i = elf_header.e_shnum, sec = section_headers + i - 1; + i; --i, --sec) + if (strcmp (SECTION_NAME (sec), name) == 0) + break; + + if (i && sec && sec->sh_size != 0) + return sec; + + return NULL; +} + /* 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 unsigned int * debug_line_pointer_sizes = NULL; +static unsigned int num_debug_line_pointer_sizes = 0; + +/* Locate and scan the .debug_info section in the file and record the pointer + sizes for the compilation units in it. Usually an executable will have + just one pointer size, but this is not guaranteed, and so we try not to + make any assumptions. Returns zero upon failure, or the number of + compilation units upon success. */ + +static unsigned int +get_debug_line_pointer_sizes (FILE * file) +{ + Elf_Internal_Shdr * section; + unsigned char * start; + unsigned char * end; + unsigned char * begin; + unsigned long length; + unsigned int num_units; + unsigned int unit; + + section = find_section (".debug_info"); + if (section == NULL) + return 0; + + length = section->sh_size; + start = get_data (NULL, file, section->sh_offset, section->sh_size, + _("extracting pointer sizes from .debug_info section")); + if (start == NULL) + return 0; + + end = start + section->sh_size; + /* First scan the section to get the number of comp units. */ + for (begin = start, num_units = 0; begin < end; num_units++) + { + /* Read the first 4 bytes. For a 32-bit DWARF section, this will + be the length. For a 64-bit DWARF section, it'll be the escape + code 0xffffffff followed by an 8 byte length. */ + length = byte_get (begin, 4); + + if (length == 0xffffffff) + { + length = byte_get (begin + 4, 8); + begin += length + 12; + } + else + begin += length + 4; + } + + if (num_units == 0) + { + error (_("No comp units in .debug_info section ?")); + free (start); + return 0; + } + + /* Then allocate an array to hold the pointer sizes. */ + debug_line_pointer_sizes = malloc (num_units * sizeof * debug_line_pointer_sizes); + if (debug_line_pointer_sizes == NULL) + { + error (_("Not enough memory for a pointer size array of %u entries"), + num_units); + free (start); + return 0; + } + + /* Populate the array. */ + for (begin = start, unit = 0; begin < end; unit++) + { + length = byte_get (begin, 4); + if (length == 0xffffffff) + { + /* For 64-bit DWARF, the 1-byte address_size field is 22 bytes + from the start of the section. This is computed as follows: + + unit_length: 12 bytes + version: 2 bytes + debug_abbrev_offset: 8 bytes + ----------------------------- + Total: 22 bytes */ + + debug_line_pointer_sizes [unit] = byte_get (begin + 22, 1); + length = byte_get (begin + 4, 8); + begin += length + 12; + } + else + { + /* For 32-bit DWARF, the 1-byte address_size field is 10 bytes from + the start of the section: + + unit_length: 4 bytes + version: 2 bytes + debug_abbrev_offset: 4 bytes + ----------------------------- + Total: 10 bytes */ + + debug_line_pointer_sizes [unit] = byte_get (begin + 10, 1); + begin += length + 4; + } + } + + free (start); + num_debug_line_pointer_sizes = num_units; + return num_units; +} static int -display_debug_lines (section, start, file) - Elf_Internal_Shdr *section; - unsigned char * start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_lines (Elf_Internal_Shdr *section, + unsigned char *start, FILE *file) { - DWARF2_External_LineInfo *external; + unsigned char *hdrptr; DWARF2_Internal_LineInfo info; unsigned char *standard_opcodes; unsigned char *data = start; unsigned char *end = start + section->sh_size; unsigned char *end_of_sequence; int i; + int offset_size; + int initial_length_size; + unsigned int comp_unit = 0; printf (_("\nDump of debug contents of section %s:\n\n"), SECTION_NAME (section)); + if (num_debug_line_pointer_sizes == 0) + get_debug_line_pointer_sizes (file); + while (data < end) { - external = (DWARF2_External_LineInfo *) data; + unsigned int pointer_size; + + hdrptr = data; /* Check the length of the block. */ - info.li_length = BYTE_GET (external->li_length); + info.li_length = byte_get (hdrptr, 4); + hdrptr += 4; if (info.li_length == 0xffffffff) { - warn (_("64-bit DWARF line info is not supported yet.\n")); - break; + /* This section is 64-bit DWARF 3. */ + info.li_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; } - if (info.li_length + sizeof (external->li_length) > section->sh_size) + if (info.li_length + initial_length_size > section->sh_size) { warn (_("The line info appears to be corrupt - the section is too small\n")); @@ -6372,24 +6452,44 @@ display_debug_lines (section, start, file) } /* Check its version number. */ - info.li_version = BYTE_GET (external->li_version); - if (info.li_version != 2) + info.li_version = byte_get (hdrptr, 2); + hdrptr += 2; + if (info.li_version != 2 && info.li_version != 3) { - warn (_("Only DWARF version 2 line info is currently supported.\n")); + warn (_("Only DWARF version 2 and 3 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); + info.li_prologue_length = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + info.li_min_insn_length = byte_get (hdrptr, 1); + hdrptr++; + info.li_default_is_stmt = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_base = byte_get (hdrptr, 1); + hdrptr++; + info.li_line_range = byte_get (hdrptr, 1); + hdrptr++; + info.li_opcode_base = byte_get (hdrptr, 1); + hdrptr++; /* Sign extend the line base field. */ info.li_line_base <<= 24; info.li_line_base >>= 24; + /* Get the pointer size from the comp unit associated + with this block of line number information. */ + if (comp_unit >= num_debug_line_pointer_sizes) + { + error (_("Not enough comp units for .debug_lines section\n")); + return 0; + } + else + { + pointer_size = debug_line_pointer_sizes [comp_unit]; + comp_unit ++; + } + printf (_(" Length: %ld\n"), info.li_length); printf (_(" DWARF Version: %d\n"), info.li_version); printf (_(" Prologue Length: %d\n"), info.li_prologue_length); @@ -6398,13 +6498,14 @@ display_debug_lines (section, start, file) printf (_(" Line Base: %d\n"), info.li_line_base); printf (_(" Line Range: %d\n"), info.li_line_range); printf (_(" Opcode Base: %d\n"), info.li_opcode_base); + printf (_(" (Pointer size: %u)\n"), pointer_size); - end_of_sequence = data + info.li_length + sizeof (external->li_length); + end_of_sequence = data + info.li_length + initial_length_size; reset_state_machine (info.li_default_is_stmt); /* Display the contents of the Opcodes table. */ - standard_opcodes = data + sizeof (*external); + standard_opcodes = hdrptr; printf (_("\n Opcodes:\n")); @@ -6490,7 +6591,7 @@ display_debug_lines (section, start, file) { case DW_LNS_extended_op: data += process_extended_line_op (data, info.li_default_is_stmt, - debug_line_pointer_size); + pointer_size); break; case DW_LNS_copy: @@ -6592,12 +6693,10 @@ display_debug_lines (section, start, file) } static int -display_debug_pubnames (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_pubnames (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { - DWARF2_External_PubNames *external; DWARF2_Internal_PubNames pubnames; unsigned char *end; @@ -6609,30 +6708,41 @@ display_debug_pubnames (section, start, file) { unsigned char *data; unsigned long offset; + int offset_size, initial_length_size; - external = (DWARF2_External_PubNames *) start; - - pubnames.pn_length = BYTE_GET (external->pn_length); - pubnames.pn_version = BYTE_GET (external->pn_version); - pubnames.pn_offset = BYTE_GET (external->pn_offset); - pubnames.pn_size = BYTE_GET (external->pn_size); - - data = start + sizeof (*external); - start += pubnames.pn_length + sizeof (external->pn_length); + data = start; + pubnames.pn_length = byte_get (data, 4); + data += 4; if (pubnames.pn_length == 0xffffffff) { - warn (_("64-bit DWARF pubnames are not supported yet.\n")); - break; + pubnames.pn_length = byte_get (data, 8); + data += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; } - if (pubnames.pn_version != 2) + pubnames.pn_version = byte_get (data, 2); + data += 2; + pubnames.pn_offset = byte_get (data, offset_size); + data += offset_size; + pubnames.pn_size = byte_get (data, offset_size); + data += offset_size; + + start += pubnames.pn_length + initial_length_size; + + if (pubnames.pn_version != 2 && pubnames.pn_version != 3) { static int warned = 0; if (! warned) { - warn (_("Only DWARF 2 pubnames are currently supported\n")); + warn (_("Only DWARF 2 and 3 pubnames are currently supported\n")); warned = 1; } @@ -6652,11 +6762,11 @@ display_debug_pubnames (section, start, file) do { - offset = byte_get (data, 4); + offset = byte_get (data, offset_size); if (offset != 0) { - data += 4; + data += offset_size; printf (" %ld\t\t%s\n", offset, data); data += strlen ((char *) data) + 1; } @@ -6669,8 +6779,7 @@ display_debug_pubnames (section, start, file) } static char * -get_TAG_name (tag) - unsigned long tag; +get_TAG_name (unsigned long tag) { switch (tag) { @@ -6750,8 +6859,7 @@ get_TAG_name (tag) } static char * -get_AT_name (attribute) - unsigned long attribute; +get_AT_name (unsigned long attribute) { switch (attribute) { @@ -6864,8 +6972,7 @@ get_AT_name (attribute) } static char * -get_FORM_name (form) - unsigned long form; +get_FORM_name (unsigned long form) { switch (form) { @@ -6900,7 +7007,7 @@ get_FORM_name (form) } } -/* FIXME: There are better and more effiecint ways to handle +/* FIXME: There are better and more efficient ways to handle these structures. For now though, I just want something that is simple to implement. */ typedef struct abbrev_attr @@ -6926,7 +7033,7 @@ static abbrev_entry *first_abbrev = NULL; static abbrev_entry *last_abbrev = NULL; static void -free_abbrevs () +free_abbrevs (void) { abbrev_entry *abbrev; @@ -6951,14 +7058,11 @@ free_abbrevs () } static void -add_abbrev (number, tag, children) - unsigned long number; - unsigned long tag; - int children; +add_abbrev (unsigned long number, unsigned long tag, int children) { abbrev_entry *entry; - entry = (abbrev_entry *) malloc (sizeof (*entry)); + entry = malloc (sizeof (*entry)); if (entry == NULL) /* ugg */ @@ -6980,13 +7084,11 @@ add_abbrev (number, tag, children) } static void -add_abbrev_attr (attribute, form) - unsigned long attribute; - unsigned long form; +add_abbrev_attr (unsigned long attribute, unsigned long form) { abbrev_attr *attr; - attr = (abbrev_attr *) malloc (sizeof (*attr)); + attr = malloc (sizeof (*attr)); if (attr == NULL) /* ugg */ @@ -7010,9 +7112,7 @@ add_abbrev_attr (attribute, form) an abbreviation set was found. */ static unsigned char * -process_abbrev_section (start, end) - unsigned char *start; - unsigned char *end; +process_abbrev_section (unsigned char *start, unsigned char *end) { if (first_abbrev != NULL) return NULL; @@ -7062,10 +7162,9 @@ process_abbrev_section (start, end) static int -display_debug_macinfo (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_macinfo (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { unsigned char *end = start + section->sh_size; unsigned char *curr = start; @@ -7136,10 +7235,9 @@ display_debug_macinfo (section, start, file) static int -display_debug_abbrev (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_abbrev (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { abbrev_entry *entry; unsigned char *end = start + section->sh_size; @@ -7183,9 +7281,7 @@ display_debug_abbrev (section, start, file) static unsigned char * -display_block (data, length) - unsigned char *data; - unsigned long length; +display_block (unsigned char *data, unsigned long length) { printf (_(" %lu byte block: "), length); @@ -7196,10 +7292,9 @@ display_block (data, length) } static void -decode_location_expression (data, pointer_size, length) - unsigned char * data; - unsigned int pointer_size; - unsigned long length; +decode_location_expression (unsigned char * data, + unsigned int pointer_size, + unsigned long length) { unsigned op; int bytes_read; @@ -7523,7 +7618,8 @@ decode_location_expression (data, pointer_size, length) } /* Separate the ops. */ - printf ("; "); + if (data < end) + printf ("; "); } } @@ -7531,35 +7627,27 @@ static const char *debug_loc_contents; static bfd_vma debug_loc_size; static void -load_debug_loc (file) - FILE *file; +load_debug_loc (FILE *file) { Elf_Internal_Shdr *sec; - unsigned int i; /* If it is already loaded, do nothing. */ if (debug_loc_contents != NULL) return; /* Locate the .debug_loc section. */ - for (i = 0, sec = section_headers; - i < elf_header.e_shnum; - i++, sec++) - if (strcmp (SECTION_NAME (sec), ".debug_loc") == 0) - break; - - if (i == elf_header.e_shnum || sec->sh_size == 0) + sec = find_section (".debug_loc"); + if (sec == NULL) return; debug_loc_size = sec->sh_size; - debug_loc_contents = ((char *) - get_data (NULL, file, sec->sh_offset, sec->sh_size, - _("debug_loc section data"))); + debug_loc_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_loc section data")); } static void -free_debug_loc () +free_debug_loc (void) { if (debug_loc_contents == NULL) return; @@ -7571,15 +7659,14 @@ free_debug_loc () static int -display_debug_loc (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_loc (Elf_Internal_Shdr *section, + unsigned char *start, FILE *file) { unsigned char *section_end; unsigned long bytes; unsigned char *section_begin = start; bfd_vma addr; + unsigned int comp_unit = 0; addr = section->sh_addr; bytes = section->sh_size; @@ -7591,6 +7678,9 @@ display_debug_loc (section, start, file) return 0; } + if (num_debug_line_pointer_sizes == 0) + get_debug_line_pointer_sizes (file); + printf (_("Contents of the .debug_loc section:\n\n")); printf (_("\n Offset Begin End Expression\n")); @@ -7600,26 +7690,37 @@ display_debug_loc (section, start, file) unsigned long end; unsigned short length; unsigned long offset; + unsigned int pointer_size; offset = start - section_begin; + /* Get the pointer size from the comp unit associated + with this block of location information. */ + if (comp_unit >= num_debug_line_pointer_sizes) + { + error (_("Not enough comp units for .debug_loc section\n")); + return 0; + } + else + { + pointer_size = debug_line_pointer_sizes [comp_unit]; + comp_unit ++; + } + while (1) { - /* Normally, the lists in the debug_loc section are related to a - given compilation unit, and thus, we would use the - pointer size of that compilation unit. However, since we are - displaying it seperately here, we either have to store - pointer sizes of all compilation units, or assume they don't - change. We assume, like the debug_line display, that - it doesn't change. */ - begin = byte_get (start, debug_line_pointer_size); - start += debug_line_pointer_size; - end = byte_get (start, debug_line_pointer_size); - start += debug_line_pointer_size; + begin = byte_get (start, pointer_size); + start += pointer_size; + end = byte_get (start, pointer_size); + start += pointer_size; if (begin == 0 && end == 0) break; + /* For now, skip any base address specifiers. */ + if (begin == 0xffffffff) + continue; + begin += addr; end += addr; @@ -7627,7 +7728,7 @@ display_debug_loc (section, start, file) start += 2; printf (" %8.8lx %8.8lx %8.8lx (", offset, begin, end); - decode_location_expression (start, debug_line_pointer_size, length); + decode_location_expression (start, pointer_size, length); printf (")\n"); start += length; @@ -7641,35 +7742,27 @@ static const char *debug_str_contents; static bfd_vma debug_str_size; static void -load_debug_str (file) - FILE *file; +load_debug_str (FILE *file) { Elf_Internal_Shdr *sec; - unsigned int i; /* If it is already loaded, do nothing. */ if (debug_str_contents != NULL) return; /* Locate the .debug_str section. */ - for (i = 0, sec = section_headers; - i < elf_header.e_shnum; - i++, sec++) - if (strcmp (SECTION_NAME (sec), ".debug_str") == 0) - break; - - if (i == elf_header.e_shnum || sec->sh_size == 0) + sec = find_section (".debug_str"); + if (sec == NULL) return; debug_str_size = sec->sh_size; - debug_str_contents = ((char *) - get_data (NULL, file, sec->sh_offset, sec->sh_size, - _("debug_str section data"))); + debug_str_contents = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_str section data")); } static void -free_debug_str () +free_debug_str (void) { if (debug_str_contents == NULL) return; @@ -7680,8 +7773,7 @@ free_debug_str () } static const char * -fetch_indirect_string (offset) - unsigned long offset; +fetch_indirect_string (unsigned long offset) { if (debug_str_contents == NULL) return _(""); @@ -7693,10 +7785,9 @@ fetch_indirect_string (offset) } static int -display_debug_str (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_str (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { unsigned long bytes; bfd_vma addr; @@ -7753,12 +7844,13 @@ display_debug_str (section, start, file) } static unsigned char * -read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) - unsigned long attribute; - unsigned long form; - unsigned char *data; - unsigned long cu_offset; - unsigned long pointer_size; +read_and_display_attr_value (unsigned long attribute, + unsigned long form, + unsigned char *data, + unsigned long cu_offset, + unsigned long pointer_size, + unsigned long offset_size, + int dwarf_version) { unsigned long uvalue = 0; unsigned char *block_start = NULL; @@ -7770,14 +7862,30 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) break; case DW_FORM_ref_addr: + if (dwarf_version == 2) + { + uvalue = byte_get (data, pointer_size); + data += pointer_size; + } + else if (dwarf_version == 3) + { + uvalue = byte_get (data, offset_size); + data += offset_size; + } + else + { + error (_("Internal error: DWARF version is not 2 or 3.\n")); + } + break; + case DW_FORM_addr: uvalue = byte_get (data, pointer_size); data += pointer_size; break; case DW_FORM_strp: - uvalue = byte_get (data, /* offset_size */ 4); - data += /* offset_size */ 4; + uvalue = byte_get (data, offset_size); + data += offset_size; break; case DW_FORM_ref1: @@ -7814,7 +7922,8 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) data += bytes_read; printf (" %s", get_FORM_name (form)); return read_and_display_attr_value (attribute, form, data, cu_offset, - pointer_size); + pointer_size, offset_size, + dwarf_version); } switch (form) @@ -7893,7 +8002,7 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) break; } - /* For some attributes we can display futher information. */ + /* For some attributes we can display further information. */ printf ("\t"); @@ -8054,7 +8163,7 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) decode_location_expression (block_start, pointer_size, uvalue); printf (")"); } - else if (form == DW_FORM_data4) + else if (form == DW_FORM_data4 || form == DW_FORM_data8) { printf ("("); printf ("location list"); @@ -8070,25 +8179,25 @@ read_and_display_attr_value (attribute, form, data, cu_offset, pointer_size) } static unsigned char * -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; +read_and_display_attr (unsigned long attribute, + unsigned long form, + unsigned char *data, + unsigned long cu_offset, + unsigned long pointer_size, + unsigned long offset_size, + int dwarf_version) { printf (" %-18s:", get_AT_name (attribute)); data = read_and_display_attr_value (attribute, form, data, cu_offset, - pointer_size); + pointer_size, offset_size, dwarf_version); printf ("\n"); return data; } static int -display_debug_info (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file; +display_debug_info (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file) { unsigned char *end = start + section->sh_size; unsigned char *section_begin = start; @@ -8100,29 +8209,38 @@ display_debug_info (section, start, file) while (start < end) { - DWARF2_External_CompUnit *external; DWARF2_Internal_CompUnit compunit; Elf_Internal_Shdr *relsec; + unsigned char *hdrptr; + unsigned char *cu_abbrev_offset_ptr; unsigned char *tags; - unsigned int i; int level; unsigned long cu_offset; + int offset_size; + int initial_length_size; - external = (DWARF2_External_CompUnit *) start; + hdrptr = start; - compunit.cu_length = BYTE_GET (external->cu_length); - compunit.cu_version = BYTE_GET (external->cu_version); - compunit.cu_abbrev_offset = BYTE_GET (external->cu_abbrev_offset); - compunit.cu_pointer_size = BYTE_GET (external->cu_pointer_size); + compunit.cu_length = byte_get (hdrptr, 4); + hdrptr += 4; if (compunit.cu_length == 0xffffffff) { - warn (_("64-bit DWARF debug info is not supported yet.\n")); - break; + compunit.cu_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; } - /* Check for RELA relocations in the - abbrev_offset address, and apply them. */ + compunit.cu_version = byte_get (hdrptr, 2); + hdrptr += 2; + + /* Apply addends of RELA relocations. */ for (relsec = section_headers; relsec < section_headers + elf_header.e_shnum; ++relsec) @@ -8147,9 +8265,13 @@ display_debug_info (section, start, file) for (rp = rela; rp < rela + nrelas; ++rp) { - if (rp->r_offset - != (bfd_vma) ((unsigned char *) &external->cu_abbrev_offset - - section_begin)) + unsigned char *loc; + + if (rp->r_offset >= (bfd_vma) (hdrptr - section_begin) + && section->sh_size > (bfd_vma) offset_size + && rp->r_offset <= section->sh_size - offset_size) + loc = section_begin + rp->r_offset; + else continue; if (is_32bit_elf) @@ -8177,17 +8299,23 @@ display_debug_info (section, start, file) } } - compunit.cu_abbrev_offset = rp->r_addend; - break; + byte_put (loc, rp->r_addend, offset_size); } free (rela); break; } - tags = start + sizeof (*external); + cu_abbrev_offset_ptr = hdrptr; + compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + + compunit.cu_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + + tags = hdrptr; cu_offset = start - section_begin; - start += compunit.cu_length + sizeof (external->cu_length); + start += compunit.cu_length + initial_length_size; printf (_(" Compilation Unit @ %lx:\n"), cu_offset); printf (_(" Length: %ld\n"), compunit.cu_length); @@ -8195,9 +8323,9 @@ display_debug_info (section, start, file) printf (_(" Abbrev Offset: %ld\n"), compunit.cu_abbrev_offset); printf (_(" Pointer Size: %d\n"), compunit.cu_pointer_size); - if (compunit.cu_version != 2) + if (compunit.cu_version != 2 && compunit.cu_version != 3) { - warn (_("Only version 2 DWARF debug information is currently supported.\n")); + warn (_("Only version 2 and 3 DWARF debug information is currently supported.\n")); continue; } @@ -8209,21 +8337,15 @@ display_debug_info (section, start, file) unsigned char *begin; /* Locate the .debug_abbrev section and process it. */ - for (i = 0, sec = section_headers; - i < elf_header.e_shnum; - i++, sec++) - if (strcmp (SECTION_NAME (sec), ".debug_abbrev") == 0) - break; - - if (i == elf_header.e_shnum || sec->sh_size == 0) + sec = find_section (".debug_abbrev"); + if (sec == NULL) { warn (_("Unable to locate .debug_abbrev section!\n")); return 0; } - begin = ((unsigned char *) - get_data (NULL, file, sec->sh_offset, sec->sh_size, - _("debug_abbrev section data"))); + begin = get_data (NULL, file, sec->sh_offset, sec->sh_size, + _("debug_abbrev section data")); if (!begin) return 0; @@ -8275,7 +8397,9 @@ display_debug_info (section, start, file) tags = read_and_display_attr (attr->attribute, attr->form, tags, cu_offset, - compunit.cu_pointer_size); + compunit.cu_pointer_size, + offset_size, + compunit.cu_version); if (entry->children) ++level; @@ -8291,10 +8415,9 @@ display_debug_info (section, start, file) } static int -display_debug_aranges (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_aranges (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { unsigned char *end = start + section->sh_size; @@ -8302,30 +8425,48 @@ display_debug_aranges (section, start, file) while (start < end) { - DWARF2_External_ARange *external; + unsigned char *hdrptr; DWARF2_Internal_ARange arange; unsigned char *ranges; unsigned long length; unsigned long address; int excess; + int offset_size; + int initial_length_size; - external = (DWARF2_External_ARange *) start; + hdrptr = start; - arange.ar_length = BYTE_GET (external->ar_length); - arange.ar_version = BYTE_GET (external->ar_version); - arange.ar_info_offset = BYTE_GET (external->ar_info_offset); - arange.ar_pointer_size = BYTE_GET (external->ar_pointer_size); - arange.ar_segment_size = BYTE_GET (external->ar_segment_size); + arange.ar_length = byte_get (hdrptr, 4); + hdrptr += 4; if (arange.ar_length == 0xffffffff) { - warn (_("64-bit DWARF aranges are not supported yet.\n")); - break; + arange.ar_length = byte_get (hdrptr, 8); + hdrptr += 8; + offset_size = 8; + initial_length_size = 12; } + else + { + offset_size = 4; + initial_length_size = 4; + } + + arange.ar_version = byte_get (hdrptr, 2); + hdrptr += 2; - if (arange.ar_version != 2) + arange.ar_info_offset = byte_get (hdrptr, offset_size); + hdrptr += offset_size; + + arange.ar_pointer_size = byte_get (hdrptr, 1); + hdrptr += 1; + + arange.ar_segment_size = byte_get (hdrptr, 1); + hdrptr += 1; + + if (arange.ar_version != 2 && arange.ar_version != 3) { - warn (_("Only DWARF 2 aranges are currently supported.\n")); + warn (_("Only DWARF 2 and 3 aranges are currently supported.\n")); break; } @@ -8337,10 +8478,10 @@ display_debug_aranges (section, start, file) printf (_("\n Address Length\n")); - ranges = start + sizeof (*external); + ranges = hdrptr; /* Must pad to an alignment boundary that is twice the pointer size. */ - excess = sizeof (*external) % (2 * arange.ar_pointer_size); + excess = (hdrptr - start) % (2 * arange.ar_pointer_size); if (excess) ranges += (2 * arange.ar_pointer_size) - excess; @@ -8361,7 +8502,7 @@ display_debug_aranges (section, start, file) printf (" %8.8lx %lu\n", address, length); } - start += arange.ar_length + sizeof (external->ar_length); + start += arange.ar_length + initial_length_size; } printf ("\n"); @@ -8386,6 +8527,7 @@ typedef struct Frame_Chunk int cfa_offset; int ra; unsigned char fde_encoding; + unsigned char cfa_exp; } Frame_Chunk; @@ -8393,14 +8535,8 @@ Frame_Chunk; in the frame info. */ #define DW_CFA_unreferenced (-1) -static void frame_need_space PARAMS ((Frame_Chunk *, int)); -static void frame_display_row PARAMS ((Frame_Chunk *, int *, int *)); -static int size_of_encoded_value PARAMS ((int)); - static void -frame_need_space (fc, reg) - Frame_Chunk *fc; - int reg; +frame_need_space (Frame_Chunk *fc, int reg) { int prev = fc->ncols; @@ -8408,10 +8544,8 @@ frame_need_space (fc, reg) return; fc->ncols = reg + 1; - fc->col_type = (short int *) xrealloc (fc->col_type, - fc->ncols * sizeof (short int)); - fc->col_offset = (int *) xrealloc (fc->col_offset, - fc->ncols * sizeof (int)); + fc->col_type = xrealloc (fc->col_type, fc->ncols * sizeof (short int)); + fc->col_offset = xrealloc (fc->col_offset, fc->ncols * sizeof (int)); while (prev < fc->ncols) { @@ -8422,10 +8556,7 @@ frame_need_space (fc, reg) } static void -frame_display_row (fc, need_col_headers, max_regs) - Frame_Chunk *fc; - int *need_col_headers; - int *max_regs; +frame_display_row (Frame_Chunk *fc, int *need_col_headers, int *max_regs) { int r; char tmp[100]; @@ -8452,7 +8583,10 @@ frame_display_row (fc, need_col_headers, max_regs) } printf ("%08lx ", fc->pc_begin); - sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset); + if (fc->cfa_exp) + strcpy (tmp, "exp"); + else + sprintf (tmp, "r%d%+d", fc->cfa_reg, fc->cfa_offset); printf ("%-8s ", tmp); for (r = 0; r < fc->ncols; r++) @@ -8473,6 +8607,9 @@ frame_display_row (fc, need_col_headers, max_regs) case DW_CFA_register: sprintf (tmp, "r%d", fc->col_offset[r]); break; + case DW_CFA_expression: + strcpy (tmp, "exp"); + break; default: strcpy (tmp, "n/a"); break; @@ -8484,8 +8621,7 @@ frame_display_row (fc, need_col_headers, max_regs) } static int -size_of_encoded_value (encoding) - int encoding; +size_of_encoded_value (int encoding) { switch (encoding & 0x7) { @@ -8497,15 +8633,24 @@ size_of_encoded_value (encoding) } } +static bfd_vma +get_encoded_value (unsigned char *data, int encoding) +{ + int size = size_of_encoded_value (encoding); + if (encoding & DW_EH_PE_signed) + return byte_get_signed (data, size); + else + return byte_get (data, size); +} + #define GET(N) byte_get (start, N); start += N #define LEB() read_leb128 (start, & length_return, 0); start += length_return #define SLEB() read_leb128 (start, & length_return, 1); start += length_return static int -display_debug_frames (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start; - FILE *file ATTRIBUTE_UNUSED; +display_debug_frames (Elf_Internal_Shdr *section, + unsigned char *start, + FILE *file ATTRIBUTE_UNUSED) { unsigned char *end = start + section->sh_size; unsigned char *section_start = start; @@ -8531,6 +8676,8 @@ display_debug_frames (section, start, file) unsigned char *augmentation_data = NULL; unsigned long augmentation_data_len = 0; int encoded_ptr_size = addr_size; + int offset_size; + int initial_length_size; saved_start = start; length = byte_get (start, 4); start += 4; @@ -8544,26 +8691,33 @@ display_debug_frames (section, start, file) if (length == 0xffffffff) { - warn (_("64-bit DWARF format frames are not supported yet.\n")); - break; + length = byte_get (start, 8); + start += 8; + offset_size = 8; + initial_length_size = 12; + } + else + { + offset_size = 4; + initial_length_size = 4; } - block_end = saved_start + length + 4; - cie_id = byte_get (start, 4); start += 4; + block_end = saved_start + length + initial_length_size; + cie_id = byte_get (start, offset_size); start += offset_size; if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID)) { int version; - fc = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); + fc = xmalloc (sizeof (Frame_Chunk)); memset (fc, 0, sizeof (Frame_Chunk)); fc->next = chunks; chunks = fc; fc->chunk_start = saved_start; fc->ncols = 0; - fc->col_type = (short int *) xmalloc (sizeof (short int)); - fc->col_offset = (int *) xmalloc (sizeof (int)); + fc->col_type = xmalloc (sizeof (short int)); + fc->col_offset = xmalloc (sizeof (int)); frame_need_space (fc, max_regs-1); version = *start++; @@ -8666,8 +8820,8 @@ display_debug_frames (section, start, file) cie_id, saved_start); start = block_end; fc->ncols = 0; - fc->col_type = (short int *) xmalloc (sizeof (short int)); - fc->col_offset = (int *) xmalloc (sizeof (int)); + fc->col_type = xmalloc (sizeof (short int)); + fc->col_offset = xmalloc (sizeof (int)); frame_need_space (fc, max_regs - 1); cie = fc; fc->augmentation = ""; @@ -8676,8 +8830,8 @@ display_debug_frames (section, start, file) else { fc->ncols = cie->ncols; - fc->col_type = (short int *) xmalloc (fc->ncols * sizeof (short int)); - fc->col_offset = (int *) xmalloc (fc->ncols * sizeof (int)); + fc->col_type = xmalloc (fc->ncols * sizeof (short int)); + fc->col_offset = xmalloc (fc->ncols * sizeof (int)); memcpy (fc->col_type, cie->col_type, fc->ncols * sizeof (short int)); memcpy (fc->col_offset, cie->col_offset, fc->ncols * sizeof (int)); fc->augmentation = cie->augmentation; @@ -8693,7 +8847,7 @@ display_debug_frames (section, start, file) if (fc->fde_encoding) encoded_ptr_size = size_of_encoded_value (fc->fde_encoding); - fc->pc_begin = byte_get (start, encoded_ptr_size); + fc->pc_begin = get_encoded_value (start, fc->fde_encoding); if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) fc->pc_begin += section->sh_addr + (start - section_start); start += encoded_ptr_size; @@ -8724,8 +8878,12 @@ display_debug_frames (section, start, file) /* At this point, fc is the current chunk, cie (if any) is set, and we're about to interpret instructions for the chunk. */ - - if (do_debug_frames_interp) + /* ??? At present we need to do this always, since this sizes the + fc->col_type and fc->col_offset arrays, which we write into always. + We should probably split the interpreted and non-interpreted bits + into two different routines, since there's so much that doesn't + really overlap between them. */ + if (1 || do_debug_frames_interp) { /* Start by making a pass over the chunk, allocating storage and taking note of what registers are used. */ @@ -8734,7 +8892,7 @@ display_debug_frames (section, start, file) while (start < block_end) { unsigned op, opa; - unsigned long reg; + unsigned long reg, tmp; op = *start++; opa = op & 0x3f; @@ -8802,6 +8960,17 @@ display_debug_frames (section, start, file) case DW_CFA_def_cfa_offset: LEB (); break; + case DW_CFA_def_cfa_expression: + tmp = LEB (); + start += tmp; + break; + case DW_CFA_expression: + reg = LEB (); + tmp = LEB (); + start += tmp; + frame_need_space (fc, reg); + fc->col_type[reg] = DW_CFA_undefined; + break; case DW_CFA_offset_extended_sf: reg = LEB (); SLEB (); frame_need_space (fc, reg); @@ -8813,6 +8982,9 @@ display_debug_frames (section, start, file) case DW_CFA_def_cfa_offset_sf: SLEB (); break; + case DW_CFA_MIPS_advance_loc8: + start += 8; + break; case DW_CFA_GNU_args_size: LEB (); break; @@ -8874,7 +9046,7 @@ display_debug_frames (section, start, file) break; case DW_CFA_set_loc: - vma = byte_get (start, encoded_ptr_size); + vma = get_encoded_value (start, fc->fde_encoding); if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel) vma += section->sh_addr + (start - section_start); start += encoded_ptr_size; @@ -8956,7 +9128,7 @@ display_debug_frames (section, start, file) reg = LEB (); roffs = LEB (); if (! do_debug_frames_interp) - printf (" DW_CFA_register: r%ld\n", reg); + printf (" DW_CFA_register: r%ld in r%ld\n", reg, roffs); fc->col_type[reg] = DW_CFA_register; fc->col_offset[reg] = roffs; break; @@ -8964,10 +9136,10 @@ display_debug_frames (section, start, file) case DW_CFA_remember_state: if (! do_debug_frames_interp) printf (" DW_CFA_remember_state\n"); - rs = (Frame_Chunk *) xmalloc (sizeof (Frame_Chunk)); + rs = xmalloc (sizeof (Frame_Chunk)); rs->ncols = fc->ncols; - rs->col_type = (short int *) xmalloc (rs->ncols * sizeof (short int)); - rs->col_offset = (int *) xmalloc (rs->ncols * sizeof (int)); + rs->col_type = xmalloc (rs->ncols * sizeof (short int)); + rs->col_offset = xmalloc (rs->ncols * sizeof (int)); memcpy (rs->col_type, fc->col_type, rs->ncols); memcpy (rs->col_offset, fc->col_offset, rs->ncols * sizeof (int)); rs->next = remembered_state; @@ -8978,18 +9150,25 @@ display_debug_frames (section, start, file) if (! do_debug_frames_interp) printf (" DW_CFA_restore_state\n"); rs = remembered_state; - remembered_state = rs->next; - frame_need_space (fc, rs->ncols-1); - memcpy (fc->col_type, rs->col_type, rs->ncols); - memcpy (fc->col_offset, rs->col_offset, rs->ncols * sizeof (int)); - free (rs->col_type); - free (rs->col_offset); - free (rs); + if (rs) + { + remembered_state = rs->next; + frame_need_space (fc, rs->ncols-1); + memcpy (fc->col_type, rs->col_type, rs->ncols); + memcpy (fc->col_offset, rs->col_offset, + rs->ncols * sizeof (int)); + free (rs->col_type); + free (rs->col_offset); + free (rs); + } + else if (do_debug_frames_interp) + printf ("Mismatched DW_CFA_restore_state\n"); break; case DW_CFA_def_cfa: fc->cfa_reg = LEB (); fc->cfa_offset = LEB (); + fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa: r%d ofs %d\n", fc->cfa_reg, fc->cfa_offset); @@ -8997,6 +9176,7 @@ display_debug_frames (section, start, file) case DW_CFA_def_cfa_register: fc->cfa_reg = LEB (); + fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_reg: r%d\n", fc->cfa_reg); break; @@ -9012,6 +9192,31 @@ display_debug_frames (section, start, file) printf (" DW_CFA_nop\n"); break; + case DW_CFA_def_cfa_expression: + ul = LEB (); + if (! do_debug_frames_interp) + { + printf (" DW_CFA_def_cfa_expression ("); + decode_location_expression (start, addr_size, ul); + printf (")\n"); + } + fc->cfa_exp = 1; + start += ul; + break; + + case DW_CFA_expression: + reg = LEB (); + ul = LEB (); + if (! do_debug_frames_interp) + { + printf (" DW_CFA_expression: r%ld (", reg); + decode_location_expression (start, addr_size, ul); + printf (")\n"); + } + fc->col_type[reg] = DW_CFA_expression; + start += ul; + break; + case DW_CFA_offset_extended_sf: reg = LEB (); l = SLEB (); @@ -9026,6 +9231,7 @@ display_debug_frames (section, start, file) case DW_CFA_def_cfa_sf: fc->cfa_reg = LEB (); fc->cfa_offset = SLEB (); + fc->cfa_exp = 0; if (! do_debug_frames_interp) printf (" DW_CFA_def_cfa_sf: r%d ofs %d\n", fc->cfa_reg, fc->cfa_offset); @@ -9037,6 +9243,17 @@ display_debug_frames (section, start, file) printf (" DW_CFA_def_cfa_offset_sf: %d\n", fc->cfa_offset); break; + case DW_CFA_MIPS_advance_loc8: + ofs = byte_get (start, 8); start += 8; + if (do_debug_frames_interp) + frame_display_row (fc, &need_col_headers, &max_regs); + else + printf (" DW_CFA_MIPS_advance_loc8: %ld to %08lx\n", + ofs * fc->code_factor, + fc->pc_begin + ofs * fc->code_factor); + fc->pc_begin += ofs * fc->code_factor; + break; + case DW_CFA_GNU_window_save: if (! do_debug_frames_interp) printf (" DW_CFA_GNU_window_save\n"); @@ -9059,17 +9276,6 @@ display_debug_frames (section, start, file) fc->col_offset[reg] = l * fc->data_factor; break; - /* FIXME: How do we handle these? */ - case DW_CFA_def_cfa_expression: - fprintf (stderr, "unsupported DW_CFA_def_cfa_expression\n"); - start = block_end; - break; - - case DW_CFA_expression: - fprintf (stderr, "unsupported DW_CFA_expression\n"); - start = block_end; - break; - default: fprintf (stderr, "unsupported or unknown DW_CFA_%d\n", op); start = block_end; @@ -9092,10 +9298,9 @@ display_debug_frames (section, start, file) #undef SLEB static int -display_debug_not_supported (section, start, file) - Elf_Internal_Shdr *section; - unsigned char *start ATTRIBUTE_UNUSED; - FILE *file ATTRIBUTE_UNUSED; +display_debug_not_supported (Elf_Internal_Shdr *section, + 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)); @@ -9103,57 +9308,35 @@ 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) - Elf_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. The third field is a prescan - function to be run over the section before displaying any of the - sections. */ +/* A structure containing the name of a debug section + and a pointer to a function that can decode it. */ struct { const char *const name; - int (*display) PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); - int (*prescan) PARAMS ((Elf_Internal_Shdr *, unsigned char *, FILE *)); + int (*display) (Elf_Internal_Shdr *, unsigned char *, FILE *); } debug_displays[] = { - { ".debug_abbrev", display_debug_abbrev, NULL }, - { ".debug_aranges", display_debug_aranges, NULL }, - { ".debug_frame", display_debug_frames, NULL }, - { ".debug_info", display_debug_info, prescan_debug_info }, - { ".debug_line", display_debug_lines, NULL }, - { ".debug_pubnames", display_debug_pubnames, NULL }, - { ".eh_frame", display_debug_frames, NULL }, - { ".debug_macinfo", display_debug_macinfo, NULL }, - { ".debug_str", display_debug_str, NULL }, - { ".debug_loc", display_debug_loc, NULL }, - { ".debug_pubtypes", display_debug_not_supported, NULL }, - { ".debug_ranges", 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 } + { ".debug_abbrev", display_debug_abbrev }, + { ".debug_aranges", display_debug_aranges }, + { ".debug_frame", display_debug_frames }, + { ".debug_info", display_debug_info }, + { ".debug_line", display_debug_lines }, + { ".debug_pubnames", display_debug_pubnames }, + { ".eh_frame", display_debug_frames }, + { ".debug_macinfo", display_debug_macinfo }, + { ".debug_str", display_debug_str }, + { ".debug_loc", display_debug_loc }, + { ".debug_pubtypes", display_debug_not_supported }, + { ".debug_ranges", 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 } }; static int -display_debug_section (section, file) - Elf_Internal_Shdr *section; - FILE *file; +display_debug_section (Elf_Internal_Shdr *section, FILE *file) { char *name = SECTION_NAME (section); bfd_size_type length; @@ -9167,8 +9350,8 @@ display_debug_section (section, file) return 0; } - start = (unsigned char *) get_data (NULL, file, section->sh_offset, length, - _("debug section data")); + start = get_data (NULL, file, section->sh_offset, length, + _("debug section data")); if (!start) return 0; @@ -9196,8 +9379,7 @@ display_debug_section (section, file) } static int -process_section_contents (file) - FILE *file; +process_section_contents (FILE *file) { Elf_Internal_Shdr *section; unsigned int i; @@ -9205,43 +9387,6 @@ process_section_contents (file) 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; - start = ((unsigned char *) - get_data (NULL, file, section->sh_offset, length, - _("debug section data"))); - if (!start) - return 0; - - 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++, section++) @@ -9264,8 +9409,7 @@ process_section_contents (file) } static void -process_mips_fpe_exception (mask) - int mask; +process_mips_fpe_exception (int mask) { if (mask) { @@ -9286,8 +9430,7 @@ process_mips_fpe_exception (mask) } static int -process_mips_specific (file) - FILE *file; +process_mips_specific (FILE *file) { Elf_Internal_Dyn *entry; size_t liblist_offset = 0; @@ -9305,16 +9448,20 @@ process_mips_specific (file) switch (entry->d_tag) { case DT_MIPS_LIBLIST: - liblist_offset = entry->d_un.d_val - loadaddr; + liblist_offset + = offset_from_vma (file, entry->d_un.d_val, + liblistno * sizeof (Elf32_External_Lib)); break; case DT_MIPS_LIBLISTNO: liblistno = entry->d_un.d_val; break; case DT_MIPS_OPTIONS: - options_offset = entry->d_un.d_val - loadaddr; + options_offset = offset_from_vma (file, entry->d_un.d_val, 0); break; case DT_MIPS_CONFLICT: - conflicts_offset = entry->d_un.d_val - loadaddr; + conflicts_offset + = offset_from_vma (file, entry->d_un.d_val, + conflictsno * sizeof (Elf32_External_Conflict)); break; case DT_MIPS_CONFLICTNO: conflictsno = entry->d_un.d_val; @@ -9328,10 +9475,9 @@ process_mips_specific (file) Elf32_External_Lib *elib; size_t cnt; - elib = ((Elf32_External_Lib *) - get_data (NULL, file, liblist_offset, - liblistno * sizeof (Elf32_External_Lib), - _("liblist"))); + elib = get_data (NULL, file, liblist_offset, + liblistno * sizeof (Elf32_External_Lib), + _("liblist")); if (elib) { printf ("\nSection '.liblist' contains %lu entries:\n", @@ -9415,12 +9561,11 @@ process_mips_specific (file) while (sect->sh_type != SHT_MIPS_OPTIONS) ++sect; - eopt = (Elf_External_Options *) get_data (NULL, file, options_offset, - sect->sh_size, _("options")); + eopt = get_data (NULL, file, options_offset, sect->sh_size, + _("options")); if (eopt) { - iopt = ((Elf_Internal_Options *) - malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt))); + iopt = malloc ((sect->sh_size / sizeof (eopt)) * sizeof (*iopt)); if (iopt == NULL) { error (_("Out of memory")); @@ -9612,7 +9757,7 @@ process_mips_specific (file) return 0; } - iconf = (Elf32_Conflict *) malloc (conflictsno * sizeof (*iconf)); + iconf = malloc (conflictsno * sizeof (*iconf)); if (iconf == NULL) { error (_("Out of memory")); @@ -9623,10 +9768,8 @@ process_mips_specific (file) { Elf32_External_Conflict *econf32; - econf32 = ((Elf32_External_Conflict *) - get_data (NULL, file, conflicts_offset, - conflictsno * sizeof (*econf32), - _("conflict"))); + econf32 = get_data (NULL, file, conflicts_offset, + conflictsno * sizeof (*econf32), _("conflict")); if (!econf32) return 0; @@ -9639,10 +9782,8 @@ process_mips_specific (file) { Elf64_External_Conflict *econf64; - econf64 = ((Elf64_External_Conflict *) - get_data (NULL, file, conflicts_offset, - conflictsno * sizeof (*econf64), - _("conflict"))); + econf64 = get_data (NULL, file, conflicts_offset, + conflictsno * sizeof (*econf64), _("conflict")); if (!econf64) return 0; @@ -9652,8 +9793,8 @@ process_mips_specific (file) free (econf64); } - printf (_("\nSection '.conflict' contains %ld entries:\n"), - (long) conflictsno); + printf (_("\nSection '.conflict' contains %lu entries:\n"), + (unsigned long) conflictsno); puts (_(" Num: Index Value Name")); for (cnt = 0; cnt < conflictsno; ++cnt) @@ -9674,8 +9815,7 @@ process_mips_specific (file) } static int -process_gnu_liblist (file) - FILE *file; +process_gnu_liblist (FILE *file) { Elf_Internal_Shdr *section, *string_sec; Elf32_External_Lib *elib; @@ -9693,17 +9833,15 @@ process_gnu_liblist (file) switch (section->sh_type) { case SHT_GNU_LIBLIST: - elib = ((Elf32_External_Lib *) - get_data (NULL, file, section->sh_offset, section->sh_size, - _("liblist"))); + elib = get_data (NULL, file, section->sh_offset, section->sh_size, + _("liblist")); if (elib == NULL) break; string_sec = SECTION_HEADER (section->sh_link); - strtab = (char *) get_data (NULL, file, string_sec->sh_offset, - string_sec->sh_size, - _("liblist string table")); + strtab = get_data (NULL, file, string_sec->sh_offset, + string_sec->sh_size, _("liblist string table")); if (strtab == NULL || section->sh_entsize != sizeof (Elf32_External_Lib)) @@ -9754,13 +9892,13 @@ process_gnu_liblist (file) } static const char * -get_note_type (e_type) - unsigned e_type; +get_note_type (unsigned e_type) { static char buff[64]; switch (e_type) { + case NT_AUXV: return _("NT_AUXV (auxiliary vector)"); 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)"); @@ -9779,8 +9917,7 @@ get_note_type (e_type) } static const char * -get_netbsd_elfcore_note_type (e_type) - unsigned e_type; +get_netbsd_elfcore_note_type (unsigned e_type) { static char buff[64]; @@ -9846,8 +9983,7 @@ get_netbsd_elfcore_note_type (e_type) If the value of namesz is zero, there is no name present. */ static int -process_note (pnote) - Elf_Internal_Note *pnote; +process_note (Elf_Internal_Note *pnote) { const char *nt; @@ -9877,10 +10013,7 @@ process_note (pnote) static int -process_corefile_note_segment (file, offset, length) - FILE *file; - bfd_vma offset; - bfd_vma length; +process_corefile_note_segment (FILE *file, bfd_vma offset, bfd_vma length) { Elf_External_Note *pnotes; Elf_External_Note *external; @@ -9889,8 +10022,7 @@ process_corefile_note_segment (file, offset, length) if (length <= 0) return 0; - pnotes = (Elf_External_Note *) get_data (NULL, file, offset, length, - _("notes")); + pnotes = get_data (NULL, file, offset, length, _("notes")); if (!pnotes) return 0; @@ -9963,33 +10095,14 @@ process_corefile_note_segment (file, offset, length) } static int -process_corefile_note_segments (file) - FILE *file; +process_corefile_note_segments (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); + if (! get_program_headers (file)) return 0; - } for (i = 0, segment = program_headers; i < elf_header.e_phnum; @@ -10001,14 +10114,11 @@ process_corefile_note_segments (file) (bfd_vma) segment->p_filesz); } - free (program_headers); - return res; } static int -process_corefile_contents (file) - FILE *file; +process_corefile_contents (FILE *file) { /* If we have not been asked to display the notes then do nothing. */ if (! do_notes) @@ -10029,8 +10139,7 @@ process_corefile_contents (file) } static int -process_arch_specific (file) - FILE *file; +process_arch_specific (FILE *file) { if (! do_arch) return 1; @@ -10048,8 +10157,7 @@ process_arch_specific (file) } static int -get_file_header (file) - FILE *file; +get_file_header (FILE *file) { /* Read in the identity array. */ if (fread (elf_header.e_ident, EI_NIDENT, 1, file) != 1) @@ -10060,8 +10168,14 @@ get_file_header (file) { 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; + case ELFDATA2LSB: + byte_get = byte_get_little_endian; + byte_put = byte_put_little_endian; + break; + case ELFDATA2MSB: + byte_get = byte_get_big_endian; + byte_put = byte_put_big_endian; + break; } /* For now we only support 32 bit and 64 bit ELF files. */ @@ -10096,7 +10210,7 @@ get_file_header (file) /* 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. */ + overwriting things. */ if (sizeof (bfd_vma) < 8) { error (_("This instance of readelf has been built without support for a\n\ @@ -10135,31 +10249,18 @@ get_file_header (file) return 1; } +/* Process one ELF object file according to the command line options. + This file may actually be stored in an archive. The file is + positioned at the start of the ELF object. */ + static int -process_file (file_name) - char *file_name; +process_object (char *file_name, FILE *file) { - FILE *file; - struct stat statbuf; unsigned int i; - if (stat (file_name, & statbuf) < 0) - { - error (_("Cannot stat input file %s.\n"), file_name); - return 1; - } - - file = fopen (file_name, "rb"); - if (file == NULL) - { - error (_("Input file %s not found.\n"), file_name); - return 1; - } - if (! get_file_header (file)) { error (_("%s: Failed to read file header\n"), file_name); - fclose (file); return 1; } @@ -10175,10 +10276,7 @@ process_file (file_name) printf (_("\nFile: %s\n"), file_name); if (! process_file_header ()) - { - fclose (file); - return 1; - } + return 1; if (! process_section_headers (file)) { @@ -10211,7 +10309,11 @@ process_file (file_name) process_arch_specific (file); - fclose (file); + if (program_headers) + { + free (program_headers); + program_headers = NULL; + } if (section_headers) { @@ -10248,6 +10350,230 @@ process_file (file_name) return 0; } +/* Process an ELF archive. The file is positioned just after the + ARMAG string. */ + +static int +process_archive (char *file_name, FILE *file) +{ + struct ar_hdr arhdr; + size_t got; + unsigned long size; + char *longnames = NULL; + unsigned long longnames_size = 0; + size_t file_name_size; + int ret; + + show_name = 1; + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + + if (memcmp (arhdr.ar_name, "/ ", 16) == 0) + { + /* This is the archive symbol table. Skip it. + FIXME: We should have an option to dump it. */ + size = strtoul (arhdr.ar_size, NULL, 10); + if (fseek (file, size + (size & 1), SEEK_CUR) != 0) + { + error (_("%s: failed to skip archive symbol table\n"), file_name); + return 1; + } + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + } + + if (memcmp (arhdr.ar_name, "// ", 16) == 0) + { + /* This is the archive string table holding long member + names. */ + + longnames_size = strtoul (arhdr.ar_size, NULL, 10); + + longnames = malloc (longnames_size); + if (longnames == NULL) + { + error (_("Out of memory\n")); + return 1; + } + + if (fread (longnames, longnames_size, 1, file) != 1) + { + free (longnames); + error(_("%s: failed to read string table\n"), file_name); + return 1; + } + + if ((longnames_size & 1) != 0) + getc (file); + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + free (longnames); + + if (got == 0) + return 0; + + error (_("%s: failed to read archive header\n"), file_name); + return 1; + } + } + + file_name_size = strlen (file_name); + ret = 0; + + while (1) + { + char *name; + char *nameend; + char *namealc; + + if (arhdr.ar_name[0] == '/') + { + unsigned long off; + + off = strtoul (arhdr.ar_name + 1, NULL, 10); + if (off >= longnames_size) + { + error (_("%s: invalid archive string table offset %lu\n"), off); + ret = 1; + break; + } + + name = longnames + off; + nameend = memchr (name, '/', longnames_size - off); + } + else + { + name = arhdr.ar_name; + nameend = memchr (name, '/', 16); + } + + if (nameend == NULL) + { + error (_("%s: bad archive file name\n")); + ret = 1; + break; + } + + namealc = malloc (file_name_size + (nameend - name) + 3); + if (namealc == NULL) + { + error (_("Out of memory\n")); + ret = 1; + break; + } + + memcpy (namealc, file_name, file_name_size); + namealc[file_name_size] = '('; + memcpy (namealc + file_name_size + 1, name, nameend - name); + namealc[file_name_size + 1 + (nameend - name)] = ')'; + namealc[file_name_size + 2 + (nameend - name)] = '\0'; + + archive_file_offset = ftell (file); + archive_file_size = strtoul (arhdr.ar_size, NULL, 10); + + ret |= process_object (namealc, file); + + free (namealc); + + if (fseek (file, + (archive_file_offset + + archive_file_size + + (archive_file_size & 1)), + SEEK_SET) != 0) + { + error (_("%s: failed to seek to next archive header\n"), file_name); + ret = 1; + break; + } + + got = fread (&arhdr, 1, sizeof arhdr, file); + if (got != sizeof arhdr) + { + if (got == 0) + break; + + error (_("%s: failed to read archive header\n"), file_name); + ret = 1; + break; + } + } + + if (longnames != 0) + free (longnames); + + return ret; +} + +static int +process_file (char *file_name) +{ + FILE *file; + struct stat statbuf; + char armag[SARMAG]; + int ret; + + if (stat (file_name, &statbuf) < 0) + { + if (errno == ENOENT) + error (_("'%s': No such file\n"), file_name); + else + error (_("Could not locate '%s'. System error message: %s\n"), + file_name, strerror (errno)); + return 1; + } + + if (! S_ISREG (statbuf.st_mode)) + { + error (_("'%s' is not an ordinary file\n"), file_name); + return 1; + } + + file = fopen (file_name, "rb"); + if (file == NULL) + { + error (_("Input file '%s' is not readable.\n"), file_name); + return 1; + } + + if (fread (armag, SARMAG, 1, file) != 1) + { + error (_("%s: Failed to read file header\n"), file_name); + fclose (file); + return 1; + } + + if (memcmp (armag, ARMAG, SARMAG) == 0) + ret = process_archive (file_name, file); + else + { + rewind (file); + archive_file_size = archive_file_offset = 0; + ret = process_object (file_name, file); + } + + fclose (file); + + return ret; +} + #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 @@ -10267,14 +10593,12 @@ db_task_printsym (unsigned int addr) } #endif -int main PARAMS ((int, char **)); - int -main (argc, argv) - int argc; - char **argv; +main (int argc, char **argv) { int err; + char *cmdline_dump_sects = NULL; + unsigned num_cmdline_dump_sects = 0; #if defined (HAVE_SETLOCALE) && defined (HAVE_LC_MESSAGES) setlocale (LC_MESSAGES, ""); @@ -10290,12 +10614,38 @@ main (argc, argv) if (optind < (argc - 1)) show_name = 1; + /* When processing more than one file remember the dump requests + issued on command line to reset them after each file. */ + if (optind + 1 < argc && dump_sects != NULL) + { + cmdline_dump_sects = malloc (num_dump_sects); + if (cmdline_dump_sects == NULL) + error (_("Out of memory allocating dump request table.")); + else + { + memcpy (cmdline_dump_sects, dump_sects, num_dump_sects); + num_cmdline_dump_sects = num_dump_sects; + } + } + err = 0; while (optind < argc) - err |= process_file (argv[optind++]); + { + err |= process_file (argv[optind++]); + + /* Reset dump requests. */ + if (optind < argc && dump_sects != NULL) + { + num_dump_sects = num_cmdline_dump_sects; + if (num_cmdline_dump_sects > 0) + memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); + } + } if (dump_sects != NULL) free (dump_sects); + if (cmdline_dump_sects != NULL) + free (cmdline_dump_sects); return err; }