ELF file than is provided by objdump. In particular it can display DWARF
debugging information which (at the moment) objdump cannot. */
\f
+#include "config.h"
#include "sysdep.h"
#include <assert.h>
#include <sys/stat.h>
#include <time.h>
+#ifdef HAVE_ZLIB_H
+#include <zlib.h>
+#endif
-/* for PATH_MAX */
+/* For PATH_MAX. */
#ifdef HAVE_LIMITS_H
#include <limits.h>
#endif
#ifndef PATH_MAX
-/* for MAXPATHLEN */
+/* For MAXPATHLEN. */
# ifdef HAVE_SYS_PARAM_H
# include <sys/param.h>
# endif
#include "elf/i960.h"
#include "elf/ia64.h"
#include "elf/ip2k.h"
+#include "elf/lm32.h"
#include "elf/iq2000.h"
#include "elf/m32c.h"
#include "elf/m32r.h"
#include "safe-ctype.h"
char *program_name = "readelf";
+int do_wide;
static long archive_file_offset;
static unsigned long archive_file_size;
static unsigned long dynamic_addr;
static int do_header;
static int do_dump;
static int do_version;
-static int do_wide;
static int do_histogram;
static int do_debugging;
static int do_arch;
if (fseek (file, archive_file_offset + offset, SEEK_SET))
{
error (_("Unable to seek to 0x%lx for %s\n"),
- archive_file_offset + offset, reason);
+ (unsigned long) archive_file_offset + offset, reason);
return NULL;
}
}
}
-#if defined BFD64 && !BFD_HOST_64BIT_LONG && !BFD_HOST_64BIT_LONG_LONG
+/* Print a VMA value. */
+
static int
-print_dec_vma (bfd_vma vma, int is_signed)
+print_vma (bfd_vma vma, print_mode mode)
{
- char buf[40];
- char *bufp = buf;
int nc = 0;
- if (is_signed && (bfd_signed_vma) vma < 0)
+ switch (mode)
{
- vma = -vma;
- putchar ('-');
- nc = 1;
- }
+ case FULL_HEX:
+ nc = printf ("0x");
+ /* Drop through. */
- do
- {
- *bufp++ = '0' + vma % 10;
- vma /= 10;
- }
- while (vma != 0);
- nc += bufp - buf;
+ case LONG_HEX:
+#ifdef BFD64
+ if (is_32bit_elf)
+ return nc + printf ("%8.8" BFD_VMA_FMT "x", vma);
+#endif
+ printf_vma (vma);
+ return nc + 16;
+
+ case DEC_5:
+ if (vma <= 99999)
+ return printf ("%5" BFD_VMA_FMT "d", vma);
+ /* Drop through. */
+
+ case PREFIX_HEX:
+ nc = printf ("0x");
+ /* Drop through. */
+
+ case HEX:
+ return nc + printf ("%" BFD_VMA_FMT "x", vma);
+
+ case DEC:
+ return printf ("%" BFD_VMA_FMT "d", vma);
- while (bufp > buf)
- putchar (*--bufp);
- return nc;
+ case UNSIGNED:
+ return printf ("%" BFD_VMA_FMT "u", vma);
+ }
+ return 0;
}
-static int
-print_hex_vma (bfd_vma vma)
+/* Display a symbol on stdout. Handles the display of non-printing characters.
+
+ If DO_WIDE is not true then format the symbol to be at most WIDTH characters,
+ truncating as necessary. If WIDTH is negative then format the string to be
+ exactly - WIDTH characters, truncating or padding as necessary.
+
+ Returns the number of emitted characters. */
+
+static unsigned int
+print_symbol (int width, const char *symbol)
{
- char buf[32];
- char *bufp = buf;
- int nc;
+ const char * c;
+ bfd_boolean extra_padding = FALSE;
+ unsigned int num_printed = 0;
- do
+ if (do_wide)
{
- char digit = '0' + (vma & 0x0f);
- if (digit > '9')
- digit += 'a' - '0' - 10;
- *bufp++ = digit;
- vma >>= 4;
+ /* Set the width to a very large value. This simplifies the code below. */
+ width = INT_MAX;
+ }
+ else if (width < 0)
+ {
+ /* Keep the width positive. This also helps. */
+ width = - width;
+ extra_padding = TRUE;
}
- while (vma != 0);
- nc = bufp - buf;
-
- while (bufp > buf)
- putchar (*--bufp);
- return nc;
-}
-#endif
-/* Print a VMA value. */
-static int
-print_vma (bfd_vma vma, print_mode mode)
-{
-#ifdef BFD64
- if (is_32bit_elf)
-#endif
+ while (width)
{
- switch (mode)
- {
- case FULL_HEX:
- return printf ("0x%8.8lx", (unsigned long) vma);
+ int len;
- case LONG_HEX:
- return printf ("%8.8lx", (unsigned long) vma);
+ c = symbol;
- case DEC_5:
- if (vma <= 99999)
- return printf ("%5ld", (long) vma);
- /* Drop through. */
+ /* Look for non-printing symbols inside the symbol's name.
+ This test is triggered in particular by the names generated
+ by the assembler for local labels. */
+ while (ISPRINT (* c))
+ c++;
- case PREFIX_HEX:
- return printf ("0x%lx", (unsigned long) vma);
+ len = c - symbol;
- case HEX:
- return printf ("%lx", (unsigned long) vma);
+ if (len)
+ {
+ if (len > width)
+ len = width;
- case DEC:
- return printf ("%ld", (unsigned long) vma);
+ printf ("%.*s", len, symbol);
- case UNSIGNED:
- return printf ("%lu", (unsigned long) vma);
+ width -= len;
+ num_printed += len;
}
- }
-#ifdef BFD64
- else
- {
- int nc = 0;
- switch (mode)
- {
- case FULL_HEX:
- nc = printf ("0x");
- /* Drop through. */
-
- case LONG_HEX:
- printf_vma (vma);
- return nc + 16;
+ if (* c == 0 || width == 0)
+ break;
- case PREFIX_HEX:
- nc = printf ("0x");
- /* Drop through. */
+ /* Now display the non-printing character, if
+ there is room left in which to dipslay it. */
+ if (*c < 32)
+ {
+ if (width < 2)
+ break;
- case HEX:
-#if BFD_HOST_64BIT_LONG
- return nc + printf ("%lx", vma);
-#elif BFD_HOST_64BIT_LONG_LONG
-#ifndef __MSVCRT__
- return nc + printf ("%llx", vma);
-#else
- return nc + printf ("%I64x", vma);
-#endif
-#else
- return nc + print_hex_vma (vma);
-#endif
+ printf ("^%c", *c + 0x40);
- case DEC:
-#if BFD_HOST_64BIT_LONG
- return printf ("%ld", vma);
-#elif BFD_HOST_64BIT_LONG_LONG
-#ifndef __MSVCRT__
- return printf ("%lld", vma);
-#else
- return printf ("%I64d", vma);
-#endif
-#else
- return print_dec_vma (vma, 1);
-#endif
+ width -= 2;
+ num_printed += 2;
+ }
+ else
+ {
+ if (width < 6)
+ break;
- case DEC_5:
-#if BFD_HOST_64BIT_LONG
- if (vma <= 99999)
- return printf ("%5ld", vma);
- else
- return printf ("%#lx", vma);
-#elif BFD_HOST_64BIT_LONG_LONG
-#ifndef __MSVCRT__
- if (vma <= 99999)
- return printf ("%5lld", vma);
- else
- return printf ("%#llx", vma);
-#else
- if (vma <= 99999)
- return printf ("%5I64d", vma);
- else
- return printf ("%#I64x", vma);
-#endif
-#else
- if (vma <= 99999)
- return printf ("%5ld", _bfd_int64_low (vma));
- else
- return print_hex_vma (vma);
-#endif
+ printf ("<0x%.2x>", *c);
- case UNSIGNED:
-#if BFD_HOST_64BIT_LONG
- return printf ("%lu", vma);
-#elif BFD_HOST_64BIT_LONG_LONG
-#ifndef __MSVCRT__
- return printf ("%llu", vma);
-#else
- return printf ("%I64u", vma);
-#endif
-#else
- return print_dec_vma (vma, 0);
-#endif
+ width -= 6;
+ num_printed += 6;
}
+
+ symbol = c + 1;
}
-#endif
- return 0;
-}
-/* Display a symbol on stdout. If do_wide is not true then
- format the symbol to be at most WIDTH characters,
- truncating as necessary. If WIDTH is negative then
- format the string to be exactly - WIDTH characters,
- truncating or padding as necessary. */
+ if (extra_padding && width > 0)
+ {
+ /* Fill in the remaining spaces. */
+ printf ("%-*s", width, " ");
+ num_printed += 2;
+ }
-static void
-print_symbol (int width, const char *symbol)
-{
- if (do_wide)
- printf ("%s", symbol);
- else if (width < 0)
- printf ("%-*.*s", width, width, symbol);
- else
- printf ("%-.*s", width, symbol);
+ return num_printed;
}
static void
case EM_AVR_OLD:
case EM_BLACKFIN:
case EM_CR16:
+ case EM_CR16_OLD:
case EM_CRIS:
case EM_CRX:
case EM_D30V:
case EM_IP2K:
case EM_IP2K_OLD:
case EM_IQ2000:
+ case EM_LATTICEMICO32:
+ case EM_M32C_OLD:
case EM_M32C:
case EM_M32R:
case EM_MCORE:
relas[i].r_offset = BYTE_GET (erelas[i].r_offset);
relas[i].r_info = BYTE_GET (erelas[i].r_info);
relas[i].r_addend = BYTE_GET (erelas[i].r_addend);
+
+ /* 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
+ && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+ {
+ /* 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. */
+ bfd_vma info = relas[i].r_info;
+ info = (((info & 0xffffffff) << 32)
+ | ((info >> 56) & 0xff)
+ | ((info >> 40) & 0xff00)
+ | ((info >> 24) & 0xff0000)
+ | ((info >> 8) & 0xff000000));
+ relas[i].r_info = info;
+ }
+#endif /* BFD64 */
}
free (erelas);
rels[i].r_offset = BYTE_GET (erels[i].r_offset);
rels[i].r_info = BYTE_GET (erels[i].r_info);
rels[i].r_addend = 0;
+
+ /* 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
+ && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
+ {
+ /* 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. */
+ bfd_vma info = rels[i].r_info;
+ info = (((info & 0xffffffff) << 32)
+ | ((info >> 56) & 0xff)
+ | ((info >> 40) & 0xff00)
+ | ((info >> 24) & 0xff0000)
+ | ((info >> 8) & 0xff000000));
+ rels[i].r_info = info;
+ }
+#endif /* BFD64 */
}
free (erels);
offset = rels[i].r_offset;
info = rels[i].r_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
- if (!is_32bit_elf
- && elf_header.e_machine == EM_MIPS
- && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
- {
- /* 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. */
- info = (((info & 0xffffffff) << 32)
- | ((info >> 56) & 0xff)
- | ((info >> 40) & 0xff00)
- | ((info >> 24) & 0xff0000)
- | ((info >> 8) & 0xff000000));
- }
-#endif /* BFD64 */
-
type = get_reloc_type (info);
symtab_index = get_reloc_symindex (info);
rtype = elf_xtensa_reloc_type (type);
break;
+ case EM_LATTICEMICO32:
+ rtype = elf_lm32_reloc_type (type);
+ break;
+
+ case EM_M32C_OLD:
case EM_M32C:
rtype = elf_m32c_reloc_type (type);
break;
break;
case EM_CR16:
+ case EM_CR16_OLD:
rtype = elf_cr16_reloc_type (type);
break;
}
psym = symtab + symtab_index;
printf (" ");
+
print_vma (psym->st_value, LONG_HEX);
+
printf (is_32bit_elf ? " " : " ");
if (psym->st_name == 0)
&& psym->st_shndx == SHN_IA_64_ANSI_COMMON)
sec_name = "ANSI_COM";
else if (elf_header.e_machine == EM_IA_64
- && (elf_header.e_ident[EI_OSABI]
+ && (elf_header.e_ident[EI_OSABI]
== ELFOSABI_OPENVMS)
&& psym->st_shndx == SHN_IA_64_VMS_SYMVEC)
sec_name = "VMS_SYMVEC";
print_symbol (22, strtab + psym->st_name);
if (is_rela)
- printf (" + %lx", (unsigned long) rels[i].r_addend);
+ {
+ long offset = (long) (bfd_signed_vma) rels[i].r_addend;
+
+ if (offset < 0)
+ printf (" - %lx", - offset);
+ else
+ printf (" + %lx", offset);
+ }
}
}
else if (is_rela)
case DT_MIPS_COMPACT_SIZE: return "MIPS_COMPACT_SIZE";
case DT_MIPS_GP_VALUE: return "MIPS_GP_VALUE";
case DT_MIPS_AUX_DYNAMIC: return "MIPS_AUX_DYNAMIC";
+ case DT_MIPS_PLTGOT: return "MIPS_PLTGOT";
+ case DT_MIPS_RWPLT: return "MIPS_RWPLT";
default:
return NULL;
}
case EM_IQ2000: return "Vitesse IQ2000";
case EM_XTENSA_OLD:
case EM_XTENSA: return "Tensilica Xtensa Processor";
+ case EM_LATTICEMICO32: return "Lattice Mico32";
+ case EM_M32C_OLD:
case EM_M32C: return "Renesas M32c";
case EM_MT: return "Morpho Techologies MT processor";
case EM_BLACKFIN: return "Analog Devices Blackfin";
case EM_ALTERA_NIOS2: return "Altera Nios II";
case EM_XC16X: return "Infineon Technologies xc16x";
case EM_CYGNUS_MEP: return "Toshiba MeP Media Engine";
- case EM_CR16: return "National Semiconductor's CR16";
+ case EM_CR16:
+ case EM_CR16_OLD: return "National Semiconductor's CR16";
default:
snprintf (buff, sizeof (buff), _("<unknown>: 0x%x"), e_machine);
return buff;
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_AROS: return "AROS";
case ELFOSABI_STANDALONE: return _("Standalone App");
case ELFOSABI_ARM: return "ARM";
default:
Dump the contents of section <number|name> as bytes\n\
-p --string-dump=<number|name>\n\
Dump the contents of section <number|name> as strings\n\
- -w[liaprmfFsoR] or\n\
- --debug-dump[=line,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
+ -w[lLiaprmfFsoR] or\n\
+ --debug-dump[=rawline,=decodedline,=info,=abbrev,=pubnames,=aranges,=macro,=frames,=str,=loc,=Ranges]\n\
Display the contents of DWARF2 debug sections\n"));
#ifdef SUPPORT_DISASSEMBLY
fprintf (stream, _("\
do_debug_lines = 1;
break;
+ case 'L':
+ do_debug_lines_decoded = 1;
+ break;
+
case 'p':
do_debug_pubnames = 1;
break;
{ "frames", & do_debug_frames },
{ "frames-interp", & do_debug_frames_interp },
{ "info", & do_debug_info },
- { "line", & do_debug_lines },
+ { "line", & do_debug_lines }, /* For backwards compatibility. */
+ { "rawline", & do_debug_lines },
+ { "decodedline", & do_debug_lines_decoded },
{ "loc", & do_debug_loc },
{ "macro", & do_debug_macinfo },
{ "pubnames", & do_debug_pubnames },
Elf_Internal_Shdr *section;
segment = program_headers + i;
- section = section_headers;
+ section = section_headers + 1;
printf (" %2.2d ", i);
}
warn (_("Virtual address 0x%lx not located in any PT_LOAD segment.\n"),
- (long) vma);
+ (unsigned long) vma);
return (long) vma;
}
}
break;
+ case EM_M32C_OLD:
case EM_M32C:
switch (elf_header.e_flags & EF_M32C_CPU_MASK)
{
else if (section->sh_type == SHT_RELA)
CHECK_ENTSIZE (section, i, Rela);
else if ((do_debugging || do_debug_info || do_debug_abbrevs
- || do_debug_lines || do_debug_pubnames || do_debug_aranges
- || do_debug_frames || do_debug_macinfo || do_debug_str
- || do_debug_loc || do_debug_ranges)
- && const_strneq (name, ".debug_"))
+ || do_debug_lines || do_debug_lines_decoded || do_debug_pubnames
+ || do_debug_aranges || do_debug_frames || do_debug_macinfo
+ || do_debug_str || do_debug_loc || do_debug_ranges)
+ && (const_strneq (name, ".debug_")
+ || const_strneq (name, ".zdebug_")))
{
- name += 7;
+ if (name[1] == 'z')
+ name += sizeof (".zdebug_") - 1;
+ else
+ name += sizeof (".debug_") - 1;
if (do_debugging
|| (do_debug_info && streq (name, "info"))
|| (do_debug_abbrevs && streq (name, "abbrev"))
- || (do_debug_lines && streq (name, "line"))
+ || ((do_debug_lines || do_debug_lines_decoded)
+ && streq (name, "line"))
|| (do_debug_pubnames && streq (name, "pubnames"))
|| (do_debug_aranges && streq (name, "aranges"))
|| (do_debug_ranges && streq (name, "ranges"))
)
request_dump_bynumber (i, DEBUG_DUMP);
}
- /* linkonce section to be combined with .debug_info at link time. */
+ /* Linkonce section to be combined with .debug_info at link time. */
else if ((do_debugging || do_debug_info)
&& const_strneq (name, ".gnu.linkonce.wi."))
request_dump_bynumber (i, DEBUG_DUMP);
get_section_type_name (section->sh_type));
}
else
- printf (" [%2u] %-17.17s %-15.15s ",
+ printf ((do_wide ? " [%2u] %-17s %-15s "
+ : " [%2u] %-17.17s %-15.15s "),
i,
SECTION_NAME (section),
get_section_type_name (section->sh_type));
break;
default:
- printf ("%#lx\n", (long) entry->d_un.d_ptr);
+ printf ("%#lx\n", (unsigned long) entry->d_un.d_ptr);
}
}
{
case STO_OPTIONAL: return "OPTIONAL";
case STO_MIPS16: return "MIPS16";
+ case STO_MIPS_PLT: return "MIPS PLT";
+ case STO_MIPS_PIC: return "MIPS PIC";
default: return NULL;
}
}
return reloc_type == 1; /* R_ARC_32. */
case EM_ARM:
return reloc_type == 2; /* R_ARM_ABS32 */
- case EM_AVR_OLD:
+ case EM_AVR_OLD:
case EM_AVR:
return reloc_type == 1;
case EM_BLACKFIN:
case EM_CRIS:
return reloc_type == 3; /* R_CRIS_32. */
case EM_CR16:
+ case EM_CR16_OLD:
return reloc_type == 3; /* R_CR16_NUM32. */
case EM_CRX:
return reloc_type == 15; /* R_CRX_NUM32. */
return reloc_type == 2; /* R_IP2K_32. */
case EM_IQ2000:
return reloc_type == 2; /* R_IQ2000_32. */
+ case EM_LATTICEMICO32:
+ return reloc_type == 3; /* R_LM32_32. */
+ case EM_M32C_OLD:
case EM_M32C:
return reloc_type == 3; /* R_M32C_32. */
case EM_M32R:
case EM_ARM:
return reloc_type == 3; /* R_ARM_REL32 */
case EM_PARISC:
- return reloc_type == 0; /* R_PARISC_NONE. *//* FIXME: This reloc is generated, but it may be a bug. */
+ return reloc_type == 9; /* R_PARISC_PCREL32. */
case EM_PPC:
return reloc_type == 26; /* R_PPC_REL32. */
case EM_PPC64:
case EM_S390_OLD:
case EM_S390:
return reloc_type == 22; /* R_S390_64 */
+ case EM_MIPS:
+ return reloc_type == 18; /* R_MIPS_64 */
+ default:
+ return FALSE;
+ }
+}
+
+/* Like is_32bit_pcrel_reloc except that it returns TRUE iff RELOC_TYPE is
+ a 64-bit pc-relative RELA relocation used in DWARF debug sections. */
+
+static bfd_boolean
+is_64bit_pcrel_reloc (unsigned int reloc_type)
+{
+ switch (elf_header.e_machine)
+ {
+ case EM_ALPHA:
+ return reloc_type == 11; /* R_ALPHA_SREL64 */
+ case EM_IA_64:
+ return reloc_type == 0x4f; /* R_IA64_PCREL64LSB */
+ case EM_PARISC:
+ return reloc_type == 72; /* R_PARISC_PCREL64 */
+ case EM_PPC64:
+ return reloc_type == 44; /* R_PPC64_REL64 */
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPARC:
+ return reloc_type == 46; /* R_SPARC_DISP64 */
+ case EM_X86_64:
+ return reloc_type == 24; /* R_X86_64_PC64 */
+ case EM_S390_OLD:
+ case EM_S390:
+ return reloc_type == 23; /* R_S390_PC64 */
default:
return FALSE;
}
case EM_IP2K_OLD:
case EM_IP2K:
return reloc_type == 1; /* R_IP2K_16. */
+ case EM_M32C_OLD:
case EM_M32C:
return reloc_type == 1; /* R_M32C_16 */
case EM_MSP430_OLD:
}
}
+/* Returns TRUE iff RELOC_TYPE is a NONE relocation used for discarded
+ relocation entries (possibly formerly used for SHT_GROUP sections). */
+
+static bfd_boolean
+is_none_reloc (unsigned int reloc_type)
+{
+ switch (elf_header.e_machine)
+ {
+ case EM_68K: /* R_68K_NONE. */
+ case EM_386: /* R_386_NONE. */
+ case EM_SPARC32PLUS:
+ case EM_SPARCV9:
+ case EM_SPARC: /* R_SPARC_NONE. */
+ case EM_MIPS: /* R_MIPS_NONE. */
+ case EM_PARISC: /* R_PARISC_NONE. */
+ case EM_ALPHA: /* R_ALPHA_NONE. */
+ case EM_PPC: /* R_PPC_NONE. */
+ case EM_PPC64: /* R_PPC64_NONE. */
+ case EM_ARM: /* R_ARM_NONE. */
+ case EM_IA_64: /* R_IA64_NONE. */
+ case EM_SH: /* R_SH_NONE. */
+ case EM_S390_OLD:
+ case EM_S390: /* R_390_NONE. */
+ case EM_CRIS: /* R_CRIS_NONE. */
+ case EM_X86_64: /* R_X86_64_NONE. */
+ case EM_MN10300: /* R_MN10300_NONE. */
+ case EM_M32R: /* R_M32R_NONE. */
+ return reloc_type == 0;
+ }
+ return FALSE;
+}
+
+/* Uncompresses a section that was compressed using zlib, in place.
+ This is a copy of bfd_uncompress_section_contents, in bfd/compress.c */
+
+static int
+uncompress_section_contents (unsigned char **buffer, dwarf_size_type *size)
+{
+#ifndef HAVE_ZLIB_H
+ /* These are just to quiet gcc. */
+ buffer = 0;
+ size = 0;
+ return FALSE;
+#else
+ dwarf_size_type compressed_size = *size;
+ unsigned char * compressed_buffer = *buffer;
+ dwarf_size_type uncompressed_size;
+ unsigned char * uncompressed_buffer;
+ z_stream strm;
+ int rc;
+ dwarf_size_type header_size = 12;
+
+ /* Read the zlib header. In this case, it should be "ZLIB" followed
+ by the uncompressed section size, 8 bytes in big-endian order. */
+ if (compressed_size < header_size
+ || ! streq ((char *) compressed_buffer, "ZLIB"))
+ return 0;
+
+ uncompressed_size = compressed_buffer[4]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[5]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[6]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[7]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[8]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[9]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[10]; uncompressed_size <<= 8;
+ uncompressed_size += compressed_buffer[11];
+
+ /* It is possible the section consists of several compressed
+ buffers concatenated together, so we uncompress in a loop. */
+ strm.zalloc = NULL;
+ strm.zfree = NULL;
+ strm.opaque = NULL;
+ strm.avail_in = compressed_size - header_size;
+ strm.next_in = (Bytef *) compressed_buffer + header_size;
+ strm.avail_out = uncompressed_size;
+ uncompressed_buffer = xmalloc (uncompressed_size);
+
+ rc = inflateInit (& strm);
+ while (strm.avail_in > 0)
+ {
+ if (rc != Z_OK)
+ goto fail;
+ strm.next_out = ((Bytef *) uncompressed_buffer
+ + (uncompressed_size - strm.avail_out));
+ rc = inflate (&strm, Z_FINISH);
+ if (rc != Z_STREAM_END)
+ goto fail;
+ rc = inflateReset (& strm);
+ }
+ rc = inflateEnd (& strm);
+ if (rc != Z_OK
+ || strm.avail_out != 0)
+ goto fail;
+
+ free (compressed_buffer);
+ *buffer = uncompressed_buffer;
+ *size = uncompressed_size;
+ return 1;
+
+ fail:
+ free (uncompressed_buffer);
+ return 0;
+#endif /* HAVE_ZLIB_H */
+}
+
/* Apply relocations to a debug section. */
static void
unsigned int reloc_size;
unsigned char * loc;
- /* In MIPS 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 (!is_32bit_elf
- && elf_header.e_machine == EM_MIPS
- && elf_header.e_ident[EI_DATA] != ELFDATA2MSB)
- rp->r_info = (((rp->r_info & 0xffffffff) << 32)
- | ((rp->r_info >> 56) & 0xff)
- | ((rp->r_info >> 40) & 0xff00)
- | ((rp->r_info >> 24) & 0xff0000)
- | ((rp->r_info >> 8) & 0xff000000));
-
reloc_type = get_reloc_type (rp->r_info);
+ if (is_none_reloc (reloc_type))
+ continue;
+
if (is_32bit_abs_reloc (reloc_type)
|| is_32bit_pcrel_reloc (reloc_type))
reloc_size = 4;
- else if (is_64bit_abs_reloc (reloc_type))
+ else if (is_64bit_abs_reloc (reloc_type)
+ || is_64bit_pcrel_reloc (reloc_type))
reloc_size = 8;
else if (is_16bit_abs_reloc (reloc_type))
reloc_size = 2;
}
addend = is_rela ? rp->r_addend : byte_get (loc, reloc_size);
-
- if (is_32bit_pcrel_reloc (reloc_type))
- byte_put (loc, (addend + sym->st_value) - rp->r_offset,
- reloc_size);
+
+ if (is_32bit_pcrel_reloc (reloc_type)
+ || is_64bit_pcrel_reloc (reloc_type))
+ {
+ /* On HPPA, all pc-relative relocations are biased by 8. */
+ if (elf_header.e_machine == EM_PARISC)
+ addend -= 8;
+ byte_put (loc, (addend + sym->st_value) - rp->r_offset,
+ reloc_size);
+ }
else
byte_put (loc, addend + sym->st_value, reloc_size);
}
}
}
-int
-load_debug_section (enum dwarf_section_display_enum debug, void *file)
+static int
+load_specific_debug_section (enum dwarf_section_display_enum debug,
+ Elf_Internal_Shdr *sec, void *file)
{
struct dwarf_section *section = &debug_displays [debug].section;
- Elf_Internal_Shdr *sec;
char buf [64];
+ int section_is_compressed;
/* If it is already loaded, do nothing. */
if (section->start != NULL)
return 1;
- /* Locate the debug section. */
- sec = find_section (section->name);
- if (sec == NULL)
- return 0;
+ section_is_compressed = section->name == section->compressed_name;
snprintf (buf, sizeof (buf), _("%s section data"), section->name);
section->address = sec->sh_addr;
section->size = sec->sh_size;
section->start = get_data (NULL, file, sec->sh_offset, 1,
sec->sh_size, buf);
+ if (section->start == NULL)
+ return 0;
+
+ if (section_is_compressed)
+ if (! uncompress_section_contents (§ion->start, §ion->size))
+ return 0;
if (debug_displays [debug].relocate)
debug_apply_relocations (file, sec, section->start);
- return section->start != NULL;
+ return 1;
+}
+
+int
+load_debug_section (enum dwarf_section_display_enum debug, void *file)
+{
+ struct dwarf_section *section = &debug_displays [debug].section;
+ Elf_Internal_Shdr *sec;
+
+ /* Locate the debug section. */
+ sec = find_section (section->uncompressed_name);
+ if (sec != NULL)
+ section->name = section->uncompressed_name;
+ else
+ {
+ sec = find_section (section->compressed_name);
+ if (sec != NULL)
+ section->name = section->compressed_name;
+ }
+ if (sec == NULL)
+ return 0;
+
+ return load_specific_debug_section (debug, sec, file);
}
void
/* See if we know how to display the contents of this section. */
for (i = 0; i < max; i++)
- if (streq (debug_displays[i].section.name, name))
+ if (streq (debug_displays[i].section.uncompressed_name, name)
+ || streq (debug_displays[i].section.compressed_name, name))
{
struct dwarf_section *sec = &debug_displays [i].section;
+ int secondary = (section != find_section (name));
+
+ if (secondary)
+ free_debug_section (i);
- if (load_debug_section (i, file))
+ if (streq (debug_displays[i].section.uncompressed_name, name))
+ sec->name = sec->uncompressed_name;
+ else
+ sec->name = sec->compressed_name;
+ if (load_specific_debug_section (i, section, file))
{
result &= debug_displays[i].display (sec, file);
- if (i != info && i != abbrev)
+ if (secondary || (i != info && i != abbrev))
free_debug_section (i);
}
static const char *arm_attr_tag_CPU_arch[] =
{"Pre-v4", "v4", "v4T", "v5T", "v5TE", "v5TEJ", "v6", "v6KZ", "v6T2",
- "v6K", "v7"};
+ "v6K", "v7", "v6-M", "v6S-M"};
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", "VFPv3", "VFPv3-D16"};
-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[] =
+static const char *arm_attr_tag_WMMX_arch[] = {"No", "WMMXv1", "WMMXv2"};
+static const char *arm_attr_tag_Advanced_SIMD_arch[] = {"No", "NEONv1"};
+static const char *arm_attr_tag_PCS_config[] =
{"None", "Bare platform", "Linux application", "Linux DSO", "PalmOS 2004",
"PalmOS (reserved)", "SymbianOS 2004", "SymbianOS (reserved)"};
static const char *arm_attr_tag_ABI_PCS_R9_use[] =
{"V6", "SB", "TLS", "Unused"};
static const char *arm_attr_tag_ABI_PCS_RW_data[] =
{"Absolute", "PC-relative", "SB-relative", "None"};
-static const char *arm_attr_tag_ABI_PCS_RO_DATA[] =
+static const char *arm_attr_tag_ABI_PCS_RO_data[] =
{"Absolute", "PC-relative", "None"};
static const char *arm_attr_tag_ABI_PCS_GOT_use[] =
{"None", "direct", "GOT-indirect"};
static const char *arm_attr_tag_ABI_PCS_wchar_t[] =
{"None", "??? 1", "2", "??? 3", "4"};
static const char *arm_attr_tag_ABI_FP_rounding[] = {"Unused", "Needed"};
-static const char *arm_attr_tag_ABI_FP_denormal[] = {"Unused", "Needed"};
+static const char *arm_attr_tag_ABI_FP_denormal[] =
+ {"Unused", "Needed", "Sign only"};
static const char *arm_attr_tag_ABI_FP_exceptions[] = {"Unused", "Needed"};
static const char *arm_attr_tag_ABI_FP_user_exceptions[] = {"Unused", "Needed"};
static const char *arm_attr_tag_ABI_FP_number_model[] =
static const char *arm_attr_tag_ABI_FP_optimization_goals[] =
{"None", "Prefer Speed", "Aggressive Speed", "Prefer Size",
"Aggressive Size", "Prefer Accuracy", "Aggressive Accuracy"};
+static const char *arm_attr_tag_CPU_unaligned_access[] = {"None", "v6"};
+static const char *arm_attr_tag_VFP_HP_extension[] =
+ {"Not Allowed", "Allowed"};
+static const char *arm_attr_tag_ABI_FP_16bit_format[] =
+ {"None", "IEEE 754", "Alternative Format"};
+static const char *arm_attr_tag_T2EE_use[] = {"Not Allowed", "Allowed"};
+static const char *arm_attr_tag_Virtualization_use[] =
+ {"Not Allowed", "Allowed"};
+static const char *arm_attr_tag_MPextension_use[] = {"Not Allowed", "Allowed"};
#define LOOKUP(id, name) \
{id, #name, 0x80 | ARRAY_SIZE(arm_attr_tag_##name), arm_attr_tag_##name}
LOOKUP(9, THUMB_ISA_use),
LOOKUP(10, VFP_arch),
LOOKUP(11, WMMX_arch),
- LOOKUP(12, NEON_arch),
- LOOKUP(13, ABI_PCS_config),
+ LOOKUP(12, Advanced_SIMD_arch),
+ LOOKUP(13, PCS_config),
LOOKUP(14, ABI_PCS_R9_use),
LOOKUP(15, ABI_PCS_RW_data),
- LOOKUP(16, ABI_PCS_RO_DATA),
+ LOOKUP(16, ABI_PCS_RO_data),
LOOKUP(17, ABI_PCS_GOT_use),
LOOKUP(18, ABI_PCS_wchar_t),
LOOKUP(19, ABI_FP_rounding),
LOOKUP(29, ABI_WMMX_args),
LOOKUP(30, ABI_optimization_goals),
LOOKUP(31, ABI_FP_optimization_goals),
- {32, "compatibility", 0, NULL}
+ {32, "compatibility", 0, NULL},
+ LOOKUP(34, CPU_unaligned_access),
+ LOOKUP(36, VFP_HP_extension),
+ LOOKUP(38, ABI_FP_16bit_format),
+ {64, "nodefaults", 0, NULL},
+ {65, "also_compatible_with", 0, NULL},
+ LOOKUP(66, T2EE_use),
+ {67, "conformance", 1, NULL},
+ LOOKUP(68, Virtualization_use),
+ LOOKUP(70, MPextension_use)
};
#undef LOOKUP
p += strlen((char *)p) + 1;
break;
+ case 64: /* Tag_nodefaults. */
+ p++;
+ printf ("True\n");
+ break;
+
+ case 65: /* Tag_also_compatible_with. */
+ val = read_uleb128 (p, &len);
+ p += len;
+ if (val == 6 /* Tag_CPU_arch. */)
+ {
+ val = read_uleb128 (p, &len);
+ p += len;
+ if ((unsigned int)val >= ARRAY_SIZE(arm_attr_tag_CPU_arch))
+ printf ("??? (%d)\n", val);
+ else
+ printf ("%s\n", arm_attr_tag_CPU_arch[val]);
+ }
+ else
+ printf ("???\n");
+ while (*(p++) != '\0' /* NUL terminator. */);
+ break;
+
default:
abort();
}
case 2:
printf ("Soft float\n");
break;
+ case 3:
+ printf ("Single-precision hard float\n");
+ break;
default:
printf ("??? (%d)\n", val);
break;
return p;
}
+ if (tag == Tag_GNU_Power_ABI_Struct_Return)
+ {
+ val = read_uleb128 (p, &len);
+ p += len;
+ printf (" Tag_GNU_Power_ABI_Struct_Return: ");
+ switch (val)
+ {
+ case 0:
+ printf ("Any\n");
+ break;
+ case 1:
+ printf ("r3/r4\n");
+ break;
+ case 2:
+ printf ("Memory\n");
+ break;
+ default:
+ printf ("??? (%d)\n", val);
+ break;
+ }
+ return p;
+ }
+
if (tag & 1)
type = 1; /* String. */
else
display_power_gnu_attribute);
}
+/* DATA points to the contents of a MIPS GOT that starts at VMA PLTGOT.
+ Print the Address, Access and Initial fields of an entry at VMA ADDR
+ and return the VMA of the next entry. */
+
+static bfd_vma
+print_mips_got_entry (unsigned char *data, bfd_vma pltgot, bfd_vma addr)
+{
+ printf (" ");
+ print_vma (addr, LONG_HEX);
+ printf (" ");
+ if (addr < pltgot + 0xfff0)
+ printf ("%6d(gp)", (int) (addr - pltgot - 0x7ff0));
+ else
+ printf ("%10s", "");
+ printf (" ");
+ if (data == NULL)
+ printf ("%*s", is_32bit_elf ? 8 : 16, "<unknown>");
+ else
+ {
+ bfd_vma entry;
+
+ entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+ print_vma (entry, LONG_HEX);
+ }
+ return addr + (is_32bit_elf ? 4 : 8);
+}
+
+/* DATA points to the contents of a MIPS PLT GOT that starts at VMA
+ PLTGOT. Print the Address and Initial fields of an entry at VMA
+ ADDR and return the VMA of the next entry. */
+
+static bfd_vma
+print_mips_pltgot_entry (unsigned char *data, bfd_vma pltgot, bfd_vma addr)
+{
+ printf (" ");
+ print_vma (addr, LONG_HEX);
+ printf (" ");
+ if (data == NULL)
+ printf ("%*s", is_32bit_elf ? 8 : 16, "<unknown>");
+ else
+ {
+ bfd_vma entry;
+
+ entry = byte_get (data + addr - pltgot, is_32bit_elf ? 4 : 8);
+ print_vma (entry, LONG_HEX);
+ }
+ return addr + (is_32bit_elf ? 4 : 8);
+}
+
static int
process_mips_specific (FILE *file)
{
size_t conflictsno = 0;
size_t options_offset = 0;
size_t conflicts_offset = 0;
+ size_t pltrelsz = 0;
+ size_t pltrel = 0;
+ bfd_vma pltgot = 0;
+ bfd_vma mips_pltgot = 0;
+ bfd_vma jmprel = 0;
+ bfd_vma local_gotno = 0;
+ bfd_vma gotsym = 0;
+ bfd_vma symtabno = 0;
process_attributes (file, NULL, SHT_GNU_ATTRIBUTES, NULL,
display_mips_gnu_attribute);
case DT_MIPS_CONFLICTNO:
conflictsno = entry->d_un.d_val;
break;
+ case DT_PLTGOT:
+ pltgot = entry->d_un.d_ptr;
+ break;
+ case DT_MIPS_LOCAL_GOTNO:
+ local_gotno = entry->d_un.d_val;
+ break;
+ case DT_MIPS_GOTSYM:
+ gotsym = entry->d_un.d_val;
+ break;
+ case DT_MIPS_SYMTABNO:
+ symtabno = entry->d_un.d_val;
+ break;
+ case DT_MIPS_PLTGOT:
+ mips_pltgot = entry->d_un.d_ptr;
+ break;
+ case DT_PLTREL:
+ pltrel = entry->d_un.d_val;
+ break;
+ case DT_PLTRELSZ:
+ pltrelsz = entry->d_un.d_val;
+ break;
+ case DT_JMPREL:
+ jmprel = entry->d_un.d_ptr;
+ break;
default:
break;
}
free (iconf);
}
+ if (pltgot != 0 && local_gotno != 0)
+ {
+ bfd_vma entry, local_end, global_end;
+ size_t i, offset;
+ unsigned char *data;
+ int addr_size;
+
+ entry = pltgot;
+ addr_size = (is_32bit_elf ? 4 : 8);
+ local_end = pltgot + local_gotno * addr_size;
+ global_end = local_end + (symtabno - gotsym) * addr_size;
+
+ offset = offset_from_vma (file, pltgot, global_end - pltgot);
+ data = get_data (NULL, file, offset, global_end - pltgot, 1, _("GOT"));
+ printf (_("\nPrimary GOT:\n"));
+ printf (_(" Canonical gp value: "));
+ print_vma (pltgot + 0x7ff0, LONG_HEX);
+ printf ("\n\n");
+
+ printf (_(" Reserved entries:\n"));
+ printf (_(" %*s %10s %*s Purpose\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial");
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" Lazy resolver\n");
+ if (data
+ && (byte_get (data + entry - pltgot, addr_size)
+ >> (addr_size * 8 - 1)) != 0)
+ {
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" Module pointer (GNU extension)\n");
+ }
+ printf ("\n");
+
+ if (entry < local_end)
+ {
+ printf (_(" Local entries:\n"));
+ printf (_(" %*s %10s %*s\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial");
+ while (entry < local_end)
+ {
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf ("\n");
+ }
+ printf ("\n");
+ }
+
+ if (gotsym < symtabno)
+ {
+ int sym_width;
+
+ printf (_(" Global entries:\n"));
+ printf (_(" %*s %10s %*s %*s %-7s %3s %s\n"),
+ addr_size * 2, "Address", "Access",
+ addr_size * 2, "Initial",
+ addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name");
+ sym_width = (is_32bit_elf ? 80 : 160) - 28 - addr_size * 6 - 1;
+ for (i = gotsym; i < symtabno; i++)
+ {
+ Elf_Internal_Sym *psym;
+
+ psym = dynamic_symbols + i;
+ entry = print_mips_got_entry (data, pltgot, entry);
+ printf (" ");
+ print_vma (psym->st_value, LONG_HEX);
+ printf (" %-7s %3s ",
+ get_symbol_type (ELF_ST_TYPE (psym->st_info)),
+ get_symbol_index_type (psym->st_shndx));
+ if (VALID_DYNAMIC_NAME (psym->st_name))
+ print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
+ else
+ printf ("<corrupt: %14ld>", psym->st_name);
+ printf ("\n");
+ }
+ printf ("\n");
+ }
+
+ if (data)
+ free (data);
+ }
+
+ if (mips_pltgot != 0 && jmprel != 0 && pltrel != 0 && pltrelsz != 0)
+ {
+ bfd_vma entry, end;
+ size_t offset, rel_offset;
+ unsigned long count, i;
+ unsigned char *data;
+ int addr_size, sym_width;
+ Elf_Internal_Rela *rels;
+
+ rel_offset = offset_from_vma (file, jmprel, pltrelsz);
+ if (pltrel == DT_RELA)
+ {
+ if (!slurp_rela_relocs (file, rel_offset, pltrelsz, &rels, &count))
+ return 0;
+ }
+ else
+ {
+ if (!slurp_rel_relocs (file, rel_offset, pltrelsz, &rels, &count))
+ return 0;
+ }
+
+ entry = mips_pltgot;
+ addr_size = (is_32bit_elf ? 4 : 8);
+ end = mips_pltgot + (2 + count) * addr_size;
+
+ offset = offset_from_vma (file, mips_pltgot, end - mips_pltgot);
+ data = get_data (NULL, file, offset, end - mips_pltgot, 1, _("PLT GOT"));
+ printf (_("\nPLT GOT:\n\n"));
+ printf (_(" Reserved entries:\n"));
+ printf (_(" %*s %*s Purpose\n"),
+ addr_size * 2, "Address", addr_size * 2, "Initial");
+ entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+ printf (" PLT lazy resolver\n");
+ entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+ printf (" Module pointer\n");
+ printf ("\n");
+
+ printf (_(" Entries:\n"));
+ printf (_(" %*s %*s %*s %-7s %3s %s\n"),
+ addr_size * 2, "Address",
+ addr_size * 2, "Initial",
+ addr_size * 2, "Sym.Val.", "Type", "Ndx", "Name");
+ sym_width = (is_32bit_elf ? 80 : 160) - 17 - addr_size * 6 - 1;
+ for (i = 0; i < count; i++)
+ {
+ Elf_Internal_Sym *psym;
+
+ psym = dynamic_symbols + get_reloc_symindex (rels[i].r_info);
+ entry = print_mips_pltgot_entry (data, mips_pltgot, entry);
+ printf (" ");
+ print_vma (psym->st_value, LONG_HEX);
+ printf (" %-7s %3s ",
+ get_symbol_type (ELF_ST_TYPE (psym->st_info)),
+ get_symbol_index_type (psym->st_shndx));
+ if (VALID_DYNAMIC_NAME (psym->st_name))
+ print_symbol (sym_width, GET_DYNAMIC_NAME (psym->st_name));
+ else
+ printf ("<corrupt: %14ld>", psym->st_name);
+ printf ("\n");
+ }
+ printf ("\n");
+
+ if (data)
+ free (data);
+ free (rels);
+ }
+
return 1;
}
printf (_("\nLibrary list section '%s' contains %lu entries:\n"),
SECTION_NAME (section),
- (long) (section->sh_size / sizeof (Elf32_External_Lib)));
+ (unsigned long) (section->sh_size / sizeof (Elf32_External_Lib)));
puts (" Library Time Stamp Checksum Version Flags");
return _("NT_PRXFPREG (user_xfpregs structure)");
case NT_PPC_VMX:
return _("NT_PPC_VMX (ppc Altivec registers)");
+ case NT_PPC_VSX:
+ return _("NT_PPC_VSX (ppc VSX registers)");
case NT_PSTATUS:
return _("NT_PSTATUS (pstatus structure)");
case NT_FPREGS:
return _("NT_GNU_HWCAP (DSO-supplied software HWCAP info)");
case NT_GNU_BUILD_ID:
return _("NT_GNU_BUILD_ID (unique build ID bitstring)");
+ case NT_GNU_GOLD_VERSION:
+ return _("NT_GNU_GOLD_VERSION (gold version)");
default:
break;
}
if (((char *) next) > (((char *) pnotes) + length))
{
warn (_("corrupt note found at offset %lx into core notes\n"),
- (long)((char *)external - (char *)pnotes));
+ (unsigned long) ((char *) external - (char *) pnotes));
warn (_(" type: %lx, namesize: %08lx, descsize: %08lx\n"),
inote.type, inote.namesz, inote.descsz);
break;
size -= index_num * SIZEOF_AR_INDEX_NUMBERS;
/* Convert the index numbers into the host's numeric format. */
- index_array = malloc (index_num * sizeof (* index_array));
+ index_array = malloc (index_num * sizeof (* index_array));
if (index_array == NULL)
{
free (index_buffer);
error (_("%s: failed to read archive index symbol table\n"), file_name);
ret = 1;
goto out;
- }
+ }
}
else
{
{
error (_("%s: end of the symbol table reached before the end of the index\n"),
file_name);
- break;
+ break;
}
printf ("\t%s\n", sym_table + l);
l += strlen (sym_table + l) + 1;