X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=binutils%2Freadelf.c;h=14dbb52f6730206265ea9e8ceca43c5a7e336200;hb=26144df5d2c0b2fa0244f3fb95f8ed2686ac0815;hp=208b6d43e49eaffd89b8538b35198098956ecbe2;hpb=84d1d6507cd684f6c517bd4d5056128b3fc7ef71;p=deliverable%2Fbinutils-gdb.git diff --git a/binutils/readelf.c b/binutils/readelf.c index 208b6d43e4..14dbb52f67 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, 2003, 2004, 2005, 2006 + Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007 Free Software Foundation, Inc. Originally developed by Eric Youngdale @@ -41,12 +41,30 @@ ELF file than is provided by objdump. In particular it can display DWARF debugging information which (at the moment) objdump cannot. */ +#include "sysdep.h" #include -#include #include -#include #include +/* for PATH_MAX */ +#ifdef HAVE_LIMITS_H +#include +#endif + +#ifndef PATH_MAX +/* for MAXPATHLEN */ +# ifdef HAVE_SYS_PARAM_H +# include +# endif +# ifndef PATH_MAX +# ifdef MAXPATHLEN +# define PATH_MAX MAXPATHLEN +# else +# define PATH_MAX 1024 +# endif +# endif +#endif + #if __GNUC__ >= 2 /* Define BFD64 here, even if our default architecture is 32 bit ELF as this will allow us to read in and parse 64bit and 32bit ELF files. @@ -55,12 +73,32 @@ #define BFD64 #endif +#include "bfd.h" +#include "bucomm.h" #include "dwarf.h" #include "elf/common.h" #include "elf/external.h" #include "elf/internal.h" + +/* Included here, before RELOC_MACROS_GEN_FUNC is defined, so that + we can obtain the H8 reloc numbers. We need these for the + get_reloc_size() function. We include h8.h again after defining + RELOC_MACROS_GEN_FUNC so that we get the naming function as well. */ + +#include "elf/h8.h" +#undef _ELF_H8_H + +/* Undo the effects of #including reloc-macros.h. */ + +#undef START_RELOC_NUMBERS +#undef RELOC_NUMBER +#undef FAKE_RELOC +#undef EMPTY_RELOC +#undef END_RELOC_NUMBERS +#undef _RELOC_MACROS_H + /* The following headers use the elf/reloc-macros.h file to automatically generate relocation recognition functions such as elf_mips_reloc_type() */ @@ -73,6 +111,7 @@ #include "elf/avr.h" #include "elf/bfin.h" #include "elf/cris.h" +#include "elf/crx.h" #include "elf/d10v.h" #include "elf/d30v.h" #include "elf/dlx.h" @@ -86,11 +125,13 @@ #include "elf/i960.h" #include "elf/ia64.h" #include "elf/ip2k.h" +#include "elf/iq2000.h" #include "elf/m32c.h" #include "elf/m32r.h" #include "elf/m68k.h" #include "elf/m68hc11.h" #include "elf/mcore.h" +#include "elf/mep.h" #include "elf/mips.h" #include "elf/mmix.h" #include "elf/mn10200.h" @@ -102,19 +143,18 @@ #include "elf/ppc.h" #include "elf/ppc64.h" #include "elf/s390.h" +#include "elf/score.h" #include "elf/sh.h" #include "elf/sparc.h" +#include "elf/spu.h" #include "elf/v850.h" #include "elf/vax.h" #include "elf/x86-64.h" #include "elf/xstormy16.h" -#include "elf/crx.h" -#include "elf/iq2000.h" #include "elf/xtensa.h" #include "aout/ar.h" -#include "bucomm.h" #include "getopt.h" #include "libiberty.h" @@ -133,8 +173,9 @@ static Elf_Internal_Sym *dynamic_symbols; static Elf_Internal_Syminfo *dynamic_syminfo; static unsigned long dynamic_syminfo_offset; static unsigned int dynamic_syminfo_nent; -static char program_interpreter[64]; +static char program_interpreter[PATH_MAX]; static bfd_vma dynamic_info[DT_JMPREL + 1]; +static bfd_vma dynamic_info_DT_GNU_HASH; static bfd_vma version_info[16]; static Elf_Internal_Ehdr elf_header; static Elf_Internal_Shdr *section_headers; @@ -222,9 +263,11 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); #define UNKNOWN -1 -#define SECTION_NAME(X) ((X) == NULL ? "" : \ - ((X)->sh_name >= string_table_length \ - ? "" : string_table + (X)->sh_name)) +#define SECTION_NAME(X) \ + ((X) == NULL ? "" \ + : string_table == NULL ? "" \ + : ((X)->sh_name >= string_table_length ? "" \ + : string_table + (X)->sh_name)) /* Given st_shndx I, map to section_headers index. */ #define SECTION_HEADER_INDEX(I) \ @@ -260,6 +303,7 @@ static void (*byte_put) (unsigned char *, bfd_vma, int); /* This is just a bit of syntatic sugar. */ #define streq(a,b) (strcmp ((a), (b)) == 0) #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) +#define const_strneq(a,b) (strncmp ((a), (b), sizeof (b) - 1) == 0) static void * get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb, @@ -550,88 +594,91 @@ guess_is_rela (unsigned long e_machine) switch (e_machine) { /* Targets that use REL relocations. */ - case EM_ARM: case EM_386: case EM_486: case EM_960: - case EM_DLX: - case EM_OPENRISC: - case EM_OR32: - case EM_CYGNUS_M32R: + case EM_ARM: case EM_D10V: case EM_CYGNUS_D10V: + case EM_DLX: case EM_MIPS: case EM_MIPS_RS3_LE: + case EM_CYGNUS_M32R: + case EM_OPENRISC: + case EM_OR32: + case EM_SCORE: return FALSE; /* Targets that use RELA relocations. */ case EM_68K: - case EM_H8_300: - case EM_H8_300H: - case EM_H8S: - case EM_SPARC32PLUS: - case EM_SPARCV9: - case EM_SPARC: - case EM_PPC: - case EM_PPC64: - case EM_V850: - case EM_CYGNUS_V850: + case EM_860: + case EM_ALPHA: + case EM_ALTERA_NIOS2: + case EM_AVR: + case EM_AVR_OLD: + case EM_BLACKFIN: + case EM_CRIS: + case EM_CRX: case EM_D30V: case EM_CYGNUS_D30V: - case EM_MN10200: - case EM_CYGNUS_MN10200: - case EM_MN10300: - case EM_CYGNUS_MN10300: case EM_FR30: case EM_CYGNUS_FR30: case EM_CYGNUS_FRV: - case EM_SH: - case EM_ALPHA: - case EM_MCORE: + case EM_H8S: + case EM_H8_300: + case EM_H8_300H: case EM_IA_64: - case EM_AVR: - case EM_AVR_OLD: - case EM_CRIS: - case EM_860: - case EM_X86_64: - case EM_S390: - case EM_S390_OLD: - case EM_MMIX: - case EM_MSP430: - case EM_MSP430_OLD: - case EM_XSTORMY16: - case EM_CRX: - case EM_VAX: case EM_IP2K: case EM_IP2K_OLD: case EM_IQ2000: - case EM_XTENSA: - case EM_XTENSA_OLD: - case EM_M32R: case EM_M32C: + case EM_M32R: + case EM_MCORE: + case EM_CYGNUS_MEP: + case EM_MMIX: + case EM_MN10200: + case EM_CYGNUS_MN10200: + case EM_MN10300: + case EM_CYGNUS_MN10300: + case EM_MSP430: + case EM_MSP430_OLD: case EM_MT: - case EM_BLACKFIN: case EM_NIOS32: - case EM_ALTERA_NIOS2: + case EM_PPC64: + case EM_PPC: + case EM_S390: + case EM_S390_OLD: + case EM_SH: + case EM_SPARC: + case EM_SPARC32PLUS: + case EM_SPARCV9: + case EM_SPU: + case EM_V850: + case EM_CYGNUS_V850: + case EM_VAX: + case EM_X86_64: + case EM_XSTORMY16: + case EM_XTENSA: + case EM_XTENSA_OLD: return TRUE; + case EM_68HC05: + case EM_68HC08: + case EM_68HC11: + case EM_68HC16: + case EM_FX66: + case EM_ME16: case EM_MMA: - case EM_PCP: case EM_NCPU: case EM_NDR1: - case EM_STARCORE: - case EM_ME16: + case EM_PCP: case EM_ST100: - case EM_TINYJ: - case EM_FX66: - case EM_ST9PLUS: + case EM_ST19: case EM_ST7: - case EM_68HC16: - case EM_68HC11: - case EM_68HC08: - case EM_68HC05: + case EM_ST9PLUS: + case EM_STARCORE: case EM_SVX: - case EM_ST19: + case EM_TINYJ: default: warn (_("Don't know about relocations on this machine architecture\n")); return FALSE; @@ -664,7 +711,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { free (erelas); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -692,7 +739,7 @@ slurp_rela_relocs (FILE *file, if (relas == NULL) { free (erelas); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -736,7 +783,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { free (erels); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -764,7 +811,7 @@ slurp_rel_relocs (FILE *file, if (rels == NULL) { free (erels); - error (_("out of memory parsing relocs")); + error (_("out of memory parsing relocs\n")); return 0; } @@ -966,6 +1013,10 @@ dump_relocations (FILE *file, rtype = elf_sparc_reloc_type (type); break; + case EM_SPU: + rtype = elf_spu_reloc_type (type); + break; + case EM_V850: case EM_CYGNUS_V850: rtype = v850_reloc_type (type); @@ -1095,6 +1146,10 @@ dump_relocations (FILE *file, rtype = elf_s390_reloc_type (type); break; + case EM_SCORE: + rtype = elf_score_reloc_type (type); + break; + case EM_XSTORMY16: rtype = elf_xstormy16_reloc_type (type); break; @@ -1133,6 +1188,9 @@ dump_relocations (FILE *file, rtype = elf_bfin_reloc_type (type); break; + case EM_CYGNUS_MEP: + rtype = elf_mep_reloc_type (type); + break; } if (rtype == NULL) @@ -1145,6 +1203,7 @@ dump_relocations (FILE *file, printf (do_wide ? "%-22.22s" : "%-17.17s", rtype); if (elf_header.e_machine == EM_ALPHA + && rtype != NULL && streq (rtype, "R_ALPHA_LITUSE") && is_rela) { @@ -1203,6 +1262,12 @@ dump_relocations (FILE *file, sec_name = "ABS"; else if (psym->st_shndx == SHN_COMMON) sec_name = "COMMON"; + else if (elf_header.e_machine == EM_MIPS + && psym->st_shndx == SHN_MIPS_SCOMMON) + sec_name = "SCOMMON"; + else if (elf_header.e_machine == EM_MIPS + && psym->st_shndx == SHN_MIPS_SUNDEFINED) + sec_name = "SUNDEF"; else if (elf_header.e_machine == EM_X86_64 && psym->st_shndx == SHN_X86_64_LCOMMON) sec_name = "LARGE_COMMON"; @@ -1237,7 +1302,9 @@ dump_relocations (FILE *file, print_vma (rels[i].r_addend, LONG_HEX); } - if (elf_header.e_machine == EM_SPARCV9 && streq (rtype, "R_SPARC_OLO10")) + if (elf_header.e_machine == EM_SPARCV9 + && rtype != NULL + && streq (rtype, "R_SPARC_OLO10")) printf (" + %lx", (unsigned long) ELF64_R_TYPE_DATA (info)); putchar ('\n'); @@ -1419,6 +1486,23 @@ get_alpha_dynamic_type (unsigned long type) } } +static const char * +get_score_dynamic_type (unsigned long type) +{ + switch (type) + { + case DT_SCORE_BASE_ADDRESS: return "SCORE_BASE_ADDRESS"; + case DT_SCORE_LOCAL_GOTNO: return "SCORE_LOCAL_GOTNO"; + case DT_SCORE_SYMTABNO: return "SCORE_SYMTABNO"; + case DT_SCORE_GOTSYM: return "SCORE_GOTSYM"; + case DT_SCORE_UNREFEXTNO: return "SCORE_UNREFEXTNO"; + case DT_SCORE_HIPAGENO: return "SCORE_HIPAGENO"; + default: + return NULL; + } +} + + static const char * get_dynamic_type (unsigned long type) { @@ -1499,6 +1583,7 @@ get_dynamic_type (unsigned long type) case DT_GNU_CONFLICTSZ: return "GNU_CONFLICTSZ"; case DT_GNU_LIBLIST: return "GNU_LIBLIST"; case DT_GNU_LIBLISTSZ: return "GNU_LIBLISTSZ"; + case DT_GNU_HASH: return "GNU_HASH"; default: if ((type >= DT_LOPROC) && (type <= DT_HIPROC)) @@ -1526,6 +1611,9 @@ get_dynamic_type (unsigned long type) case EM_ALPHA: result = get_alpha_dynamic_type (type); break; + case EM_SCORE: + result = get_score_dynamic_type (type); + break; default: result = NULL; break; @@ -1599,6 +1687,7 @@ get_machine_name (unsigned e_machine) case EM_NONE: return _("None"); case EM_M32: return "WE32100"; case EM_SPARC: return "Sparc"; + case EM_SPU: return "SPU"; case EM_386: return "Intel 80386"; case EM_68K: return "MC68000"; case EM_88K: return "MC88000"; @@ -1680,6 +1769,7 @@ get_machine_name (unsigned e_machine) case EM_X86_64: return "Advanced Micro Devices X86-64"; case EM_S390_OLD: case EM_S390: return "IBM S/390"; + case EM_SCORE: return "SUNPLUS S+Core"; case EM_XSTORMY16: return "Sanyo Xstormy16 CPU core"; case EM_OPENRISC: case EM_OR32: return "OpenRISC"; @@ -1695,8 +1785,10 @@ get_machine_name (unsigned e_machine) case EM_BLACKFIN: return "Analog Devices Blackfin"; case EM_NIOS32: return "Altera Nios"; case EM_ALTERA_NIOS2: return "Altera Nios II"; + case EM_XC16X: return "Infineon Technologies xc16x"; + case EM_CYGNUS_MEP: return "Toshiba MeP Media Engine"; default: - snprintf (buff, sizeof (buff), _(": %x"), e_machine); + snprintf (buff, sizeof (buff), _(": 0x%x"), e_machine); return buff; } } @@ -1792,6 +1884,11 @@ decode_ARM_machine_flags (unsigned e_flags, char buf[]) case EF_ARM_EABI_VER4: strcat (buf, ", Version4 EABI"); + goto eabi; + + case EF_ARM_EABI_VER5: + strcat (buf, ", Version5 EABI"); + eabi: while (e_flags) { unsigned flag; @@ -1940,40 +2037,53 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) break; case EM_68K: - if (e_flags & EF_M68K_CPU32) - strcat (buf, ", cpu32"); - if (e_flags & EF_M68K_M68000) + if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_M68000) strcat (buf, ", m68000"); - if (e_flags & EF_M68K_ISA_MASK) + else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_CPU32) + strcat (buf, ", cpu32"); + else if ((e_flags & EF_M68K_ARCH_MASK) == EF_M68K_FIDO) + strcat (buf, ", fido_a"); + else { char const *isa = _("unknown"); char const *mac = _("unknown mac"); - - switch (e_flags & EF_M68K_ISA_MASK) + char const *additional = NULL; + + switch (e_flags & EF_M68K_CF_ISA_MASK) { - case EF_M68K_ISA_A: + case EF_M68K_CF_ISA_A_NODIV: + isa = "A"; + additional = ", nodiv"; + break; + case EF_M68K_CF_ISA_A: isa = "A"; break; - case EF_M68K_ISA_A_PLUS: + case EF_M68K_CF_ISA_A_PLUS: isa = "A+"; break; - case EF_M68K_ISA_B: + case EF_M68K_CF_ISA_B_NOUSP: + isa = "B"; + additional = ", nousp"; + break; + case EF_M68K_CF_ISA_B: isa = "B"; break; } strcat (buf, ", cf, isa "); strcat (buf, isa); - if (e_flags & EF_M68K_HW_DIV) - strcat (buf, ", hwdiv"); - switch (e_flags & EF_M68K_MAC_MASK) + if (additional) + strcat (buf, additional); + if (e_flags & EF_M68K_CF_FLOAT) + strcat (buf, ", float"); + switch (e_flags & EF_M68K_CF_MAC_MASK) { case 0: mac = NULL; break; - case EF_M68K_MAC: + case EF_M68K_CF_MAC: mac = "mac"; break; - case EF_M68K_EMAC: + case EF_M68K_CF_EMAC: mac = "emac"; break; } @@ -1982,10 +2092,6 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) strcat (buf, ", "); strcat (buf, mac); } - if (e_flags & EF_M68K_USP) - strcat (buf, ", usp"); - if (e_flags & EF_M68K_FLOAT) - strcat (buf, ", float"); } break; @@ -2023,7 +2129,6 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) case EM_CYGNUS_M32R: if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH) strcat (buf, ", m32r"); - break; case EM_MIPS: @@ -2124,6 +2229,12 @@ get_machine_flags (unsigned e_flags, unsigned e_machine) case EF_SH4_NOFPU: strcat (buf, ", sh4-nofpu"); break; case EF_SH4A_NOFPU: strcat (buf, ", sh4a-nofpu"); break; case EF_SH2A_NOFPU: strcat (buf, ", sh2a-nofpu"); break; + case EF_SH3_NOMMU: strcat (buf, ", sh3-nommu"); break; + case EF_SH4_NOMMU_NOFPU: strcat (buf, ", sh4-nommu-nofpu"); break; + case EF_SH2A_SH4_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh4-nommu-nofpu"); break; + case EF_SH2A_SH3_NOFPU: strcat (buf, ", sh2a-nofpu-or-sh3-nommu"); break; + case EF_SH2A_SH4: strcat (buf, ", sh2a-or-sh4"); break; + case EF_SH2A_SH3E: strcat (buf, ", sh2a-or-sh3e"); break; default: strcat (buf, ", unknown ISA"); break; } @@ -2550,6 +2661,7 @@ get_section_type_name (unsigned int sh_type) case SHT_INIT_ARRAY: return "INIT_ARRAY"; case SHT_FINI_ARRAY: return "FINI_ARRAY"; case SHT_PREINIT_ARRAY: return "PREINIT_ARRAY"; + case SHT_GNU_HASH: return "GNU_HASH"; case SHT_GROUP: return "GROUP"; case SHT_SYMTAB_SHNDX: return "SYMTAB SECTION INDICIES"; case SHT_GNU_verdef: return "VERDEF"; @@ -2642,11 +2754,11 @@ static struct option options[] = }; static void -usage (void) +usage (FILE *stream) { - fprintf (stdout, _("Usage: readelf elf-file(s)\n")); - fprintf (stdout, _(" Display information about the contents of ELF format files\n")); - fprintf (stdout, _(" Options are:\n\ + fprintf (stream, _("Usage: readelf elf-file(s)\n")); + fprintf (stream, _(" Display information about the contents of ELF format files\n")); + fprintf (stream, _(" Options are:\n\ -a --all Equivalent to: -h -l -S -s -r -d -V -A -I\n\ -h --file-header Display the ELF file header\n\ -l --program-headers Display the program headers\n\ @@ -2670,19 +2782,21 @@ usage (void) --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\ Display the contents of DWARF2 debug sections\n")); #ifdef SUPPORT_DISASSEMBLY - fprintf (stdout, _("\ + fprintf (stream, _("\ -i --instruction-dump=\n\ Disassemble the contents of section \n")); #endif - fprintf (stdout, _("\ + fprintf (stream, _("\ -I --histogram Display histogram of bucket list lengths\n\ -W --wide Allow output width to exceed 80 characters\n\ @ Read options from \n\ -H --help Display this information\n\ -v --version Display the version number of readelf\n")); - fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); + + if (REPORT_BUGS_TO[0] && stream == stdout) + fprintf (stdout, _("Report bugs to %s\n"), REPORT_BUGS_TO); - exit (0); + exit (stream == stdout ? 0 : 1); } /* Record the fact that the user wants the contents of section number @@ -2700,7 +2814,7 @@ request_dump (unsigned int section, int type) new_dump_sects = calloc (section + 1, 1); if (new_dump_sects == NULL) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); else { /* Copy current flag settings. */ @@ -2728,11 +2842,11 @@ request_dump_byname (const char *section, int type) new_request = malloc (sizeof (struct dump_list_entry)); if (!new_request) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); new_request->name = strdup (section); if (!new_request->name) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); new_request->type = type; @@ -2746,7 +2860,7 @@ parse_args (int argc, char **argv) int c; if (argc < 2) - usage (); + usage (stderr); while ((c = getopt_long (argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF) @@ -2760,7 +2874,7 @@ parse_args (int argc, char **argv) /* Long options. */ break; case 'H': - usage (); + usage (stdout); break; case 'a': @@ -3001,7 +3115,7 @@ parse_args (int argc, char **argv) error (_("Invalid option '-%c'\n"), c); /* Drop through. */ case '?': - usage (); + usage (stderr); } } @@ -3009,11 +3123,11 @@ parse_args (int argc, char **argv) && !do_segments && !do_header && !do_dump && !do_version && !do_histogram && !do_debugging && !do_arch && !do_notes && !do_section_groups) - usage (); + usage (stderr); else if (argc < 3) { warn (_("Nothing to do.\n")); - usage (); + usage (stderr); } } @@ -3123,6 +3237,11 @@ process_file_header (void) (long) elf_header.e_shstrndx); if (section_headers != NULL && elf_header.e_shstrndx == SHN_XINDEX) printf (" (%ld)", (long) section_headers[0].sh_link); + else if (elf_header.e_shstrndx != SHN_UNDEF + && (elf_header.e_shstrndx >= elf_header.e_shnum + || (elf_header.e_shstrndx >= SHN_LORESERVE + && elf_header.e_shstrndx <= SHN_HIRESERVE))) + printf (" "); putc ('\n', stdout); } @@ -3132,6 +3251,11 @@ process_file_header (void) elf_header.e_shnum = section_headers[0].sh_size; if (elf_header.e_shstrndx == SHN_XINDEX) elf_header.e_shstrndx = section_headers[0].sh_link; + else if (elf_header.e_shstrndx != SHN_UNDEF + && (elf_header.e_shstrndx >= elf_header.e_shnum + || (elf_header.e_shstrndx >= SHN_LORESERVE + && elf_header.e_shstrndx <= SHN_HIRESERVE))) + elf_header.e_shstrndx = SHN_UNDEF; free (section_headers); section_headers = NULL; } @@ -3388,7 +3512,7 @@ process_program_headers (FILE *file) sec = find_section (".dynamic"); if (sec == NULL || sec->sh_size == 0) { - error (_("no .dynamic section in the dynamic segment")); + error (_("no .dynamic section in the dynamic segment\n")); break; } @@ -3397,9 +3521,9 @@ process_program_headers (FILE *file) if (dynamic_addr < segment->p_offset || dynamic_addr > segment->p_offset + segment->p_filesz) - warn (_("the .dynamic section is not contained within the dynamic segment")); + warn (_("the .dynamic section is not contained within the dynamic segment\n")); else if (dynamic_addr > segment->p_offset) - warn (_("the .dynamic section is not the first section in the dynamic segment.")); + warn (_("the .dynamic section is not the first section in the dynamic segment.\n")); } else { @@ -3416,8 +3540,15 @@ process_program_headers (FILE *file) error (_("Unable to find program interpreter name\n")); else { + char fmt [32]; + int ret = snprintf (fmt, sizeof (fmt), "%%%ds", PATH_MAX); + + if (ret >= (int) sizeof (fmt) || ret < 0) + error (_("Internal error: failed to create format string to display program interpreter\n")); + program_interpreter[0] = 0; - fscanf (file, "%63s", program_interpreter); + if (fscanf (file, fmt, program_interpreter) <= 0) + error (_("Unable to read program interpreter name\n")); if (do_segments) printf (_("\n [Requesting program interpreter: %s]"), @@ -3901,7 +4032,8 @@ process_section_headers (FILE *file) return 0; /* Read in the string table, so that we have names to display. */ - if (SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum) + if (elf_header.e_shstrndx != SHN_UNDEF + && SECTION_HEADER_INDEX (elf_header.e_shstrndx) < elf_header.e_shnum) { section = SECTION_HEADER (elf_header.e_shstrndx); @@ -3939,6 +4071,23 @@ process_section_headers (FILE *file) && find_section (".gcc_compiled_long32") == NULL) eh_addr_size = 8; break; + + case EM_H8_300: + case EM_H8_300H: + switch (elf_header.e_flags & EF_H8_MACH) + { + case E_H8_MACH_H8300: + case E_H8_MACH_H8300HN: + case E_H8_MACH_H8300SN: + case E_H8_MACH_H8300SXN: + eh_addr_size = 2; + break; + case E_H8_MACH_H8300H: + case E_H8_MACH_H8300S: + case E_H8_MACH_H8300SX: + eh_addr_size = 4; + break; + } } #define CHECK_ENTSIZE_VALUES(section, i, size32, size64) \ @@ -4009,7 +4158,7 @@ process_section_headers (FILE *file) || do_debug_lines || do_debug_pubnames || do_debug_aranges || do_debug_frames || do_debug_macinfo || do_debug_str || do_debug_loc || do_debug_ranges) - && strneq (name, ".debug_", 7)) + && const_strneq (name, ".debug_")) { name += 7; @@ -4029,7 +4178,7 @@ process_section_headers (FILE *file) } /* linkonce section to be combined with .debug_info at link time. */ else if ((do_debugging || do_debug_info) - && strneq (name, ".gnu.linkonce.wi.", 17)) + && const_strneq (name, ".gnu.linkonce.wi.")) request_dump (i, DEBUG_DUMP); else if (do_debug_frames && streq (name, ".eh_frame")) request_dump (i, DEBUG_DUMP); @@ -4865,7 +5014,7 @@ slurp_ia64_unwind_table (FILE *file, sym = aux->symtab + ELF64_R_SYM (rp->r_info); } - if (! strneq (relname, "R_IA64_SEGREL", 13)) + if (! const_strneq (relname, "R_IA64_SEGREL")) { warn (_("Skipping unexpected relocation type %s\n"), relname); continue; @@ -5278,7 +5427,7 @@ slurp_hppa_unwind_table (FILE *file, } /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64. */ - if (strncmp (relname, "R_PARISC_SEGREL", 15) != 0) + if (! const_strneq (relname, "R_PARISC_SEGREL")) { warn (_("Skipping unexpected relocation type %s\n"), relname); continue; @@ -5716,7 +5865,7 @@ process_dynamic_section (FILE *file) else { if (fseek (file, 0, SEEK_END)) - error (_("Unable to seek to end of file!")); + error (_("Unable to seek to end of file!\n")); section.sh_size = ftell (file) - section.sh_offset; } @@ -6196,6 +6345,15 @@ process_dynamic_section (FILE *file) } break; + case DT_GNU_HASH: + dynamic_info_DT_GNU_HASH = entry->d_un.d_val; + if (do_dynamic) + { + print_vma (entry->d_un.d_val, PREFIX_HEX); + putchar ('\n'); + } + break; + default: if ((entry->d_tag >= DT_VERSYM) && (entry->d_tag <= DT_VERNEEDNUM)) version_info[DT_VERSIONTAGIDX (entry->d_tag)] = @@ -6713,6 +6871,8 @@ get_symbol_type (unsigned int type) case STT_FILE: return "FILE"; case STT_COMMON: return "COMMON"; case STT_TLS: return "TLS"; + case STT_RELC: return "RELC"; + case STT_SRELC: return "SRELC"; default: if (type >= STT_LOPROC && type <= STT_HIPROC) { @@ -6811,6 +6971,12 @@ get_symbol_index_type (unsigned int type) else if (elf_header.e_machine == EM_X86_64 && type == SHN_X86_64_LCOMMON) return "LARGE_COM"; + else if (type == SHN_MIPS_SCOMMON + && elf_header.e_machine == EM_MIPS) + return "SCOM"; + else if (type == SHN_MIPS_SUNDEFINED + && elf_header.e_machine == EM_MIPS) + return "SUND"; else if (type >= SHN_LOPROC && type <= SHN_HIPROC) sprintf (buff, "PRC[0x%04x]", type); else if (type >= SHN_LOOS && type <= SHN_HIOS) @@ -6871,6 +7037,9 @@ process_symbol_table (FILE *file) bfd_vma nchains = 0; bfd_vma *buckets = NULL; bfd_vma *chains = NULL; + bfd_vma ngnubuckets = 0; + bfd_vma *gnubuckets = NULL; + bfd_vma *gnuchains = NULL; if (! do_syms && !do_histogram) return 1; @@ -6894,7 +7063,7 @@ process_symbol_table (FILE *file) sizeof nb + sizeof nc)), SEEK_SET)) { - error (_("Unable to seek to start of dynamic information")); + error (_("Unable to seek to start of dynamic information\n")); return 0; } @@ -7120,7 +7289,7 @@ process_symbol_table (FILE *file) check_def = 0; } else if (! is_nobits) - error (_("bad dynamic symbol")); + error (_("bad dynamic symbol\n")); else check_def = 1; } @@ -7203,7 +7372,7 @@ process_symbol_table (FILE *file) lengths = calloc (nbuckets, sizeof (*lengths)); if (lengths == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } for (hn = 0; hn < nbuckets; ++hn) @@ -7219,7 +7388,7 @@ process_symbol_table (FILE *file) counts = calloc (maxlength + 1, sizeof (*counts)); if (counts == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -7250,6 +7419,166 @@ process_symbol_table (FILE *file) free (chains); } + if (do_histogram && dynamic_info_DT_GNU_HASH) + { + unsigned char nb[16]; + bfd_vma i, maxchain = 0xffffffff, symidx, bitmaskwords; + unsigned long *lengths; + unsigned long *counts; + unsigned long hn; + unsigned long maxlength = 0; + unsigned long nzero_counts = 0; + unsigned long nsyms = 0; + bfd_vma buckets_vma; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, dynamic_info_DT_GNU_HASH, + sizeof nb)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + return 0; + } + + if (fread (nb, 16, 1, file) != 1) + { + error (_("Failed to read in number of buckets\n")); + return 0; + } + + ngnubuckets = byte_get (nb, 4); + symidx = byte_get (nb + 4, 4); + bitmaskwords = byte_get (nb + 8, 4); + buckets_vma = dynamic_info_DT_GNU_HASH + 16; + if (is_32bit_elf) + buckets_vma += bitmaskwords * 4; + else + buckets_vma += bitmaskwords * 8; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma, 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + return 0; + } + + gnubuckets = get_dynamic_data (file, ngnubuckets, 4); + + if (gnubuckets == NULL) + return 0; + + for (i = 0; i < ngnubuckets; i++) + if (gnubuckets[i] != 0) + { + if (gnubuckets[i] < symidx) + return 0; + + if (maxchain == 0xffffffff || gnubuckets[i] > maxchain) + maxchain = gnubuckets[i]; + } + + if (maxchain == 0xffffffff) + return 0; + + maxchain -= symidx; + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma + + 4 * (ngnubuckets + maxchain), 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + return 0; + } + + do + { + if (fread (nb, 4, 1, file) != 1) + { + error (_("Failed to determine last chain length\n")); + return 0; + } + + if (maxchain + 1 == 0) + return 0; + + ++maxchain; + } + while ((byte_get (nb, 4) & 1) == 0); + + if (fseek (file, + (archive_file_offset + + offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)), + SEEK_SET)) + { + error (_("Unable to seek to start of dynamic information\n")); + return 0; + } + + gnuchains = get_dynamic_data (file, maxchain, 4); + + if (gnuchains == NULL) + return 0; + + lengths = calloc (ngnubuckets, sizeof (*lengths)); + if (lengths == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + printf (_("\nHistogram for `.gnu.hash' bucket list length (total of %lu buckets):\n"), + (unsigned long) ngnubuckets); + printf (_(" Length Number %% of total Coverage\n")); + + for (hn = 0; hn < ngnubuckets; ++hn) + if (gnubuckets[hn] != 0) + { + bfd_vma off, length = 1; + + for (off = gnubuckets[hn] - symidx; + (gnuchains[off] & 1) == 0; ++off) + ++length; + lengths[hn] = length; + if (length > maxlength) + maxlength = length; + nsyms += length; + } + + counts = calloc (maxlength + 1, sizeof (*counts)); + if (counts == NULL) + { + error (_("Out of memory\n")); + return 0; + } + + for (hn = 0; hn < ngnubuckets; ++hn) + ++counts[lengths[hn]]; + + if (ngnubuckets > 0) + { + unsigned long j; + printf (" 0 %-10lu (%5.1f%%)\n", + counts[0], (counts[0] * 100.0) / ngnubuckets); + for (j = 1; j <= maxlength; ++j) + { + nzero_counts += counts[j] * j; + printf ("%7lu %-10lu (%5.1f%%) %5.1f%%\n", + j, counts[j], (counts[j] * 100.0) / ngnubuckets, + (nzero_counts * 100.0) / nsyms); + } + } + + free (counts); + free (lengths); + free (gnubuckets); + free (gnuchains); + } + return 1; } @@ -7335,6 +7664,7 @@ disassemble_section (Elf_Internal_Shdr *section, FILE *file) static int dump_section (Elf_Internal_Shdr *section, FILE *file) { + Elf_Internal_Shdr *relsec; bfd_size_type bytes; bfd_vma addr; unsigned char *data; @@ -7358,6 +7688,26 @@ dump_section (Elf_Internal_Shdr *section, FILE *file) if (!start) return 0; + /* If the section being dumped has relocations against it the user might + be expecting these relocations to have been applied. Check for this + case and issue a warning message in order to avoid confusion. + FIXME: Maybe we ought to have an option that dumps a section with + relocs applied ? */ + for (relsec = section_headers; + relsec < section_headers + elf_header.e_shnum; + ++relsec) + { + if ((relsec->sh_type != SHT_RELA && relsec->sh_type != SHT_REL) + || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum + || SECTION_HEADER (relsec->sh_info) != section + || relsec->sh_size == 0 + || SECTION_HEADER_INDEX (relsec->sh_link) >= elf_header.e_shnum) + continue; + + printf (_(" NOTE: This section has relocations against it, but these have NOT been applied to this dump.\n")); + break; + } + data = start; while (bytes) @@ -7370,34 +7720,15 @@ dump_section (Elf_Internal_Shdr *section, FILE *file) printf (" 0x%8.8lx ", (unsigned long) addr); - switch (elf_header.e_ident[EI_DATA]) + for (j = 0; j < 16; j++) { - default: - case ELFDATA2LSB: - for (j = 15; j >= 0; j --) - { - if (j < lbytes) - printf ("%2.2x", data[j]); - else - printf (" "); - - if (!(j & 0x3)) - printf (" "); - } - break; - - case ELFDATA2MSB: - for (j = 0; j < 16; j++) - { - if (j < lbytes) - printf ("%2.2x", data[j]); - else - printf (" "); + if (j < lbytes) + printf ("%2.2x", data[j]); + else + printf (" "); - if ((j & 3) == 3) - printf (" "); - } - break; + if ((j & 3) == 3) + printf (" "); } for (j = 0; j < lbytes; j++) @@ -7418,9 +7749,47 @@ dump_section (Elf_Internal_Shdr *section, FILE *file) free (start); + putchar ('\n'); return 1; } +/* Return the number of bytes affected by a given reloc. + This information is architecture and reloc dependent. + Returns 4 by default, although this is not always correct. + It should return 0 if a decision cannot be made. + FIXME: This is not the correct way to solve this problem. + The proper way is to have target specific reloc sizing functions + created by the reloc-macros.h header, in the same way that it + already creates the reloc naming functions. */ + +static unsigned int +get_reloc_size (Elf_Internal_Rela * reloc) +{ + switch (elf_header.e_machine) + { + case EM_H8S: + case EM_H8_300: + case EM_H8_300H: + case EM_H8_500: + switch (ELF32_R_TYPE (reloc->r_info)) + { + /* PR gas/3800 - without this information we do not correctly + decode the debug information generated by the h8300 assembler. */ + case R_H8_DIR16: + return 2; + default: + return 4; + } + default: + /* FIXME: We need to extend this switch statement to cope with other + architecture's relocs. (When those relocs are used against debug + sections, and when their size is not 4). But see the multiple + inclusions of for an example of the hoops that we need + to jump through in order to obtain the reloc numbers. */ + return 4; + } +} + /* Apply addends of RELA relocations. */ static int @@ -7430,14 +7799,13 @@ debug_apply_rela_addends (void *file, { Elf_Internal_Shdr *relsec; unsigned char *end = start + section->sh_size; - /* FIXME: The relocation field size is relocation type dependent. */ - unsigned int reloc_size = 4; if (!is_relocatable) return 1; - if (section->sh_size < reloc_size) - return 1; + /* SH uses RELA but uses in place value instead of the addend field. */ + if (elf_header.e_machine == EM_SH) + return 0; for (relsec = section_headers; relsec < section_headers + elf_header.e_shnum; @@ -7466,6 +7834,16 @@ debug_apply_rela_addends (void *file, for (rp = rela; rp < rela + nrelas; ++rp) { unsigned char *loc; + unsigned int reloc_size; + + reloc_size = get_reloc_size (rp); + if (reloc_size == 0) + { + warn (_("skipping relocation of unknown size against offset 0x%lx in section %s\n"), + (unsigned long) rp->r_offset, + SECTION_NAME (section)); + continue; + } loc = start + rp->r_offset; if ((loc + reloc_size) > end) @@ -7482,6 +7860,10 @@ debug_apply_rela_addends (void *file, if (ELF32_R_SYM (rp->r_info) != 0 && ELF32_ST_TYPE (sym->st_info) != STT_SECTION + /* Relocations against symbols without type can happen. + Gcc -feliminate-dwarf2-dups may generate symbols + without type for debug info. */ + && ELF32_ST_TYPE (sym->st_info) != STT_NOTYPE /* Relocations against object symbols can happen, eg when referencing a global array. For an example of this see the _clz.o binary in libgcc.a. */ @@ -7511,6 +7893,7 @@ debug_apply_rela_addends (void *file, if (ELF64_R_SYM (rp->r_info) != 0 && ELF64_ST_TYPE (sym->st_info) != STT_SECTION + && ELF64_ST_TYPE (sym->st_info) != STT_NOTYPE && ELF64_ST_TYPE (sym->st_info) != STT_OBJECT) { warn (_("skipping unexpected symbol type %s in relocation in section .rela.%s\n"), @@ -7587,7 +7970,7 @@ display_debug_section (Elf_Internal_Shdr *section, FILE *file) return 0; } - if (strneq (name, ".gnu.linkonce.wi.", 17)) + if (const_strneq (name, ".gnu.linkonce.wi.")) name = ".debug_info"; /* See if we know how to display the contents of this section. */ @@ -7712,7 +8095,8 @@ static const char *arm_attr_tag_CPU_arch[] = static const char *arm_attr_tag_ARM_ISA_use[] = {"No", "Yes"}; static const char *arm_attr_tag_THUMB_ISA_use[] = {"No", "Thumb-1", "Thumb-2"}; -static const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2"}; +/* FIXME: VFPv3 encoding was extrapolated! */ +static const char *arm_attr_tag_VFP_arch[] = {"No", "VFPv1", "VFPv2", "VFPv3"}; static const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1"}; static const char *arm_attr_tag_NEON_arch[] = {"No", "NEONv1"}; static const char *arm_attr_tag_ABI_PCS_config[] = @@ -7754,7 +8138,7 @@ static const char *arm_attr_tag_ABI_FP_optimization_goals[] = #define LOOKUP(id, name) \ {id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name} -static arm_attr_public_tag arm_attr_public_tags[] = +static arm_attr_public_tag arm_attr_public_tags[] = { {4, "CPU_raw_name", 1, NULL}, {5, "CPU_name", 1, NULL}, @@ -7931,7 +8315,7 @@ process_arm_specific (FILE *file) contents = get_data (NULL, file, sect->sh_offset, 1, sect->sh_size, _("attributes")); - + if (!contents) continue; p = contents; @@ -8021,7 +8405,7 @@ process_arm_specific (FILE *file) { printf (_("Unknown format '%c'\n"), *p); } - + free(contents); } return 1; @@ -8170,7 +8554,7 @@ process_mips_specific (FILE *file) iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt)); if (iopt == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -8355,14 +8739,14 @@ process_mips_specific (FILE *file) if (dynamic_symbols == NULL) { - error (_("conflict list found without a dynamic symbol table")); + error (_("conflict list found without a dynamic symbol table\n")); return 0; } iconf = cmalloc (conflictsno, sizeof (*iconf)); if (iconf == NULL) { - error (_("Out of memory")); + error (_("Out of memory\n")); return 0; } @@ -8631,7 +9015,7 @@ process_note (Elf_Internal_Note *pnote) note type strings. */ nt = get_note_type (pnote->type); - else if (strneq (pnote->namedata, "NetBSD-CORE", 11)) + else if (const_strneq (pnote->namedata, "NetBSD-CORE")) /* NetBSD-specific core file notes. */ nt = get_netbsd_elfcore_note_type (pnote->type); @@ -8945,7 +9329,7 @@ process_object (char *file_name, FILE *file) assert (num_dump_sects >= num_cmdline_dump_sects); memcpy (dump_sects, cmdline_dump_sects, num_cmdline_dump_sects); } - + if (! process_file_header ()) return 1; @@ -9079,7 +9463,7 @@ process_archive (char *file_name, FILE *file) return 1; } - if (memcmp (arhdr.ar_name, "/ ", 16) == 0) + if (const_strneq (arhdr.ar_name, "/ ")) { /* This is the archive symbol table. Skip it. FIXME: We should have an option to dump it. */ @@ -9101,7 +9485,7 @@ process_archive (char *file_name, FILE *file) } } - if (memcmp (arhdr.ar_name, "// ", 16) == 0) + if (const_strneq (arhdr.ar_name, "// ")) { /* This is the archive string table holding long member names. */ @@ -9191,7 +9575,7 @@ process_archive (char *file_name, FILE *file) archive_file_offset = ftell (file); archive_file_size = strtoul (arhdr.ar_size, NULL, 10); - + ret |= process_object (namealc, file); free (namealc); @@ -9319,7 +9703,7 @@ main (int argc, char **argv) /* Make a copy of the dump_sects array. */ cmdline_dump_sects = malloc (num_dump_sects); if (cmdline_dump_sects == NULL) - error (_("Out of memory allocating dump request table.")); + error (_("Out of memory allocating dump request table.\n")); else { memcpy (cmdline_dump_sects, dump_sects, num_dump_sects);