/* 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 <eric@andante.jic.com>
ELF file than is provided by objdump. In particular it can display DWARF
debugging information which (at the moment) objdump cannot. */
\f
+#include "sysdep.h"
#include <assert.h>
-#include <sys/types.h>
#include <sys/stat.h>
-#include <stdio.h>
#include <time.h>
+/* for PATH_MAX */
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifndef PATH_MAX
+/* for MAXPATHLEN */
+# ifdef HAVE_SYS_PARAM_H
+# include <sys/param.h>
+# 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.
#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() */
#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"
#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"
#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"
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];
/* 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)
\f
static void *
get_data (void *var, FILE *file, long offset, size_t size, size_t nmemb,
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;
if (relas == NULL)
{
free (erelas);
- error (_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs\n"));
return 0;
}
if (relas == NULL)
{
free (erelas);
- error (_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs\n"));
return 0;
}
if (rels == NULL)
{
free (erels);
- error (_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs\n"));
return 0;
}
if (rels == NULL)
{
free (erels);
- error (_("out of memory parsing relocs"));
+ error (_("out of memory parsing relocs\n"));
return 0;
}
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);
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;
rtype = elf_bfin_reloc_type (type);
break;
+ case EM_CYGNUS_MEP:
+ rtype = elf_mep_reloc_type (type);
+ break;
}
if (rtype == NULL)
printf (do_wide ? "%-22.22s" : "%-17.17s", rtype);
if (elf_header.e_machine == EM_ALPHA
+ && rtype != NULL
&& streq (rtype, "R_ALPHA_LITUSE")
&& is_rela)
{
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');
}
}
+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)
{
case EM_ALPHA:
result = get_alpha_dynamic_type (type);
break;
+ case EM_SCORE:
+ result = get_score_dynamic_type (type);
+ break;
default:
result = NULL;
break;
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";
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";
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), _("<unknown>: %x"), e_machine);
+ snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
return buff;
}
}
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");
char const *additional = NULL;
-
- switch (e_flags & EF_M68K_ISA_MASK)
+
+ switch (e_flags & EF_M68K_CF_ISA_MASK)
{
- case EF_M68K_ISA_A_NODIV:
+ case EF_M68K_CF_ISA_A_NODIV:
isa = "A";
additional = ", nodiv";
break;
- case EF_M68K_ISA_A:
+ 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_NOUSP:
+ case EF_M68K_CF_ISA_B_NOUSP:
isa = "B";
additional = ", nousp";
break;
- case EF_M68K_ISA_B:
+ case EF_M68K_CF_ISA_B:
isa = "B";
break;
}
strcat (buf, isa);
if (additional)
strcat (buf, additional);
- if (e_flags & EF_M68K_FLOAT)
+ if (e_flags & EF_M68K_CF_FLOAT)
strcat (buf, ", float");
- switch (e_flags & EF_M68K_MAC_MASK)
+ 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;
}
case EM_CYGNUS_M32R:
if ((e_flags & EF_M32R_ARCH) == E_M32R_ARCH)
strcat (buf, ", m32r");
-
break;
case EM_MIPS:
};
static void
-usage (void)
+usage (FILE *stream)
{
- fprintf (stdout, _("Usage: readelf <option(s)> 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 <option(s)> 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\
--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=<number>\n\
Disassemble the contents of section <number>\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\
@<file> Read options from <file>\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
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. */
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;
int c;
if (argc < 2)
- usage ();
+ usage (stderr);
while ((c = getopt_long
(argc, argv, "ersuahnldSDAINtgw::x:i:vVWH", options, NULL)) != EOF)
/* Long options. */
break;
case 'H':
- usage ();
+ usage (stdout);
break;
case 'a':
error (_("Invalid option '-%c'\n"), c);
/* Drop through. */
case '?':
- usage ();
+ usage (stderr);
}
}
&& !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);
}
}
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;
}
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
{
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]"),
|| 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;
}
/* 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);
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;
}
/* 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;
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;
}
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)
{
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;
}
check_def = 0;
}
else if (! is_nobits)
- error (_("bad dynamic symbol"));
+ error (_("bad dynamic symbol\n"));
else
check_def = 1;
}
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)
counts = calloc (maxlength + 1, sizeof (*counts));
if (counts == NULL)
{
- error (_("Out of memory"));
+ error (_("Out of memory\n"));
return 0;
}
sizeof nb)),
SEEK_SET))
{
- error (_("Unable to seek to start of dynamic information"));
+ error (_("Unable to seek to start of dynamic information\n"));
return 0;
}
+ offset_from_vma (file, buckets_vma, 4)),
SEEK_SET))
{
- error (_("Unable to seek to start of dynamic information"));
+ error (_("Unable to seek to start of dynamic information\n"));
return 0;
}
+ 4 * (ngnubuckets + maxchain), 4)),
SEEK_SET))
{
- error (_("Unable to seek to start of dynamic information"));
+ error (_("Unable to seek to start of dynamic information\n"));
return 0;
}
+ offset_from_vma (file, buckets_vma + 4 * ngnubuckets, 4)),
SEEK_SET))
{
- error (_("Unable to seek to start of dynamic information"));
+ error (_("Unable to seek to start of dynamic information\n"));
return 0;
}
lengths = calloc (ngnubuckets, sizeof (*lengths));
if (lengths == NULL)
{
- error (_("Out of memory"));
+ error (_("Out of memory\n"));
return 0;
}
counts = calloc (maxlength + 1, sizeof (*counts));
if (counts == NULL)
{
- error (_("Out of memory"));
+ error (_("Out of memory\n"));
return 0;
}
static int
dump_section (Elf_Internal_Shdr *section, FILE *file)
{
+ Elf_Internal_Shdr *relsec;
bfd_size_type bytes;
bfd_vma addr;
unsigned char *data;
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)
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++)
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 <elf/h8.h> 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
{
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;
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)
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. */
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"),
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. */
iopt = cmalloc ((sect->sh_size / sizeof (eopt)), sizeof (*iopt));
if (iopt == NULL)
{
- error (_("Out of memory"));
+ error (_("Out of memory\n"));
return 0;
}
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;
}
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);
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. */
}
}
- if (memcmp (arhdr.ar_name, "// ", 16) == 0)
+ if (const_strneq (arhdr.ar_name, "// "))
{
/* This is the archive string table holding long member
names. */
/* 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);