/* readelf.c -- display contents of an ELF format file
- Copyright 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
+ Copyright 1998, 1999, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
Originally developed by Eric Youngdale <eric@andante.jic.com>
Modifications by Nick Clifton <nickc@redhat.com>
#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"
unsigned long archive_file_size;
unsigned long dynamic_addr;
bfd_size_type dynamic_size;
+unsigned int dynamic_nent;
char *dynamic_strings;
char *string_table;
unsigned long string_table_length;
Elf_Internal_Ehdr elf_header;
Elf_Internal_Shdr *section_headers;
Elf_Internal_Phdr *program_headers;
-Elf_Internal_Dyn *dynamic_segment;
+Elf_Internal_Dyn *dynamic_section;
Elf_Internal_Shdr *symtab_shndx_hdr;
int show_name;
int do_dynamic;
int do_syms;
int do_reloc;
int do_sections;
+int do_section_groups;
int do_segments;
int do_unwind;
int do_using_dynamic;
int do_notes;
int is_32bit_elf;
+struct group_list
+{
+ struct group_list *next;
+ unsigned int section_index;
+};
+
+struct group
+{
+ struct group_list *root;
+ unsigned int group_index;
+};
+
+struct group *section_groups;
+size_t group_count = 0;
+
+struct group **section_headers_groups;
+
/* A dynamic array of flags indicating which sections require dumping. */
char *dump_sects = NULL;
unsigned int num_dump_sects = 0;
static bfd_vma (*byte_get) (unsigned char *, int);
static void (*byte_put) (unsigned char *, bfd_vma, int);
-typedef int Elf32_Word;
-
#define UNKNOWN -1
#define SECTION_NAME(X) ((X) == NULL ? "<none>" : \
case EM_MSP430:
case EM_MSP430_OLD:
case EM_XSTORMY16:
+ case EM_CRX:
case EM_VAX:
case EM_IP2K:
case EM_IP2K_OLD:
rtype = elf_i386_reloc_type (type);
break;
- case EM_68HC11:
- case EM_68HC12:
- rtype = elf_m68hc11_reloc_type (type);
- break;
+ case EM_68HC11:
+ case EM_68HC12:
+ rtype = elf_m68hc11_reloc_type (type);
+ break;
case EM_68K:
rtype = elf_m68k_reloc_type (type);
rtype = elf_fr30_reloc_type (type);
break;
- case EM_CYGNUS_FRV:
- rtype = elf_frv_reloc_type (type);
- break;
+ case EM_CYGNUS_FRV:
+ rtype = elf_frv_reloc_type (type);
+ break;
case EM_MCORE:
rtype = elf_mcore_reloc_type (type);
rtype = elf_xstormy16_reloc_type (type);
break;
+ case EM_CRX:
+ rtype = elf_crx_reloc_type (type);
+ break;
+
case EM_VAX:
rtype = elf_vax_reloc_type (type);
break;
if (psym->st_shndx < SHN_LORESERVE)
sec_index = psym->st_shndx;
- else if (psym->st_shndx > SHN_LORESERVE)
+ else if (psym->st_shndx > SHN_HIRESERVE)
sec_index = psym->st_shndx - (SHN_HIRESERVE + 1
- SHN_LORESERVE);
{
case ET_NONE: return _("NONE (None)");
case ET_REL: return _("REL (Relocatable file)");
- case ET_EXEC: return _("EXEC (Executable file)");
- case ET_DYN: return _("DYN (Shared object file)");
- case ET_CORE: return _("CORE (Core file)");
+ case ET_EXEC: return _("EXEC (Executable file)");
+ case ET_DYN: return _("DYN (Shared object file)");
+ case ET_CORE: return _("CORE (Core file)");
default:
if ((e_type >= ET_LOPROC) && (e_type <= ET_HIPROC))
case EM_XSTORMY16: return "Sanyo Xstormy16 CPU core";
case EM_OPENRISC:
case EM_OR32: return "OpenRISC";
+ case EM_CRX: return "National Semiconductor CRX microprocessor";
case EM_DLX: return "OpenDLX";
case EM_IP2K_OLD:
case EM_IP2K: return "Ubicom IP2xxx 8-bit microcontrollers";
strcat (buf, ", software FP");
break;
+ case EF_ARM_VFP_FLOAT:
+ strcat (buf, ", VFP");
+ break;
+
case EF_ARM_MAVERICK_FLOAT:
strcat (buf, ", Maverick FP");
break;
break;
+ case EM_SH:
+ switch ((e_flags & EF_SH_MACH_MASK))
+ {
+ case EF_SH1: strcat (buf, ", sh1"); break;
+ case EF_SH2: strcat (buf, ", sh2"); break;
+ case EF_SH3: strcat (buf, ", sh3"); break;
+ case EF_SH_DSP: strcat (buf, ", sh-dsp"); break;
+ case EF_SH3_DSP: strcat (buf, ", sh3-dsp"); break;
+ case EF_SH4AL_DSP: strcat (buf, ", sh4al-dsp"); break;
+ case EF_SH3E: strcat (buf, ", sh3e"); break;
+ case EF_SH4: strcat (buf, ", sh4"); break;
+ case EF_SH5: strcat (buf, ", sh5"); break;
+ case EF_SH2E: strcat (buf, ", sh2e"); break;
+ case EF_SH4A: strcat (buf, ", sh4a"); break;
+ case EF_SH2A: strcat (buf, ", sh2a"); break;
+ 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;
+ default: strcat (buf, ", unknown ISA"); break;
+ }
+
+ break;
+
case EM_SPARCV9:
if (e_flags & EF_SPARC_32PLUS)
strcat (buf, ", v8+");
case PT_GNU_EH_FRAME:
return "GNU_EH_FRAME";
- case PT_GNU_STACK: return "STACK";
+ case PT_GNU_STACK: return "GNU_STACK";
+ case PT_GNU_RELRO: return "GNU_RELRO";
default:
if ((p_type >= PT_LOPROC) && (p_type <= PT_HIPROC))
{"segments", no_argument, 0, 'l'},
{"sections", no_argument, 0, 'S'},
{"section-headers", no_argument, 0, 'S'},
+ {"section-groups", no_argument, 0, 'g'},
{"symbols", no_argument, 0, 's'},
{"syms", no_argument, 0, 's'},
{"relocs", no_argument, 0, 'r'},
--segments An alias for --program-headers\n\
-S --section-headers Display the sections' header\n\
--sections An alias for --section-headers\n\
+ -g --section-groups Display the section groups\n\
-e --headers Equivalent to: -h -l -S\n\
-s --syms Display the symbol table\n\
--symbols An alias for --syms\n\
-n --notes Display the core notes (if present)\n\
-r --relocs Display the relocations (if present)\n\
-u --unwind Display the unwind info (if present)\n\
- -d --dynamic Display the dynamic segment (if present)\n\
+ -d --dynamic Display the dynamic section (if present)\n\
-V --version-info Display the version sections (if present)\n\
-A --arch-specific Display architecture specific information (if any).\n\
-D --use-dynamic Use the dynamic section info when displaying symbols\n\
usage ();
while ((c = getopt_long
- (argc, argv, "ersuahnldSDAIw::x:i:vVWH", options, NULL)) != EOF)
+ (argc, argv, "ersuahnldSDAIgw::x:i:vVWH", options, NULL)) != EOF)
{
char *cp;
int section;
do_dynamic++;
do_header++;
do_sections++;
+ do_section_groups++;
do_segments++;
do_version++;
do_histogram++;
do_arch++;
do_notes++;
break;
+ case 'g':
+ do_section_groups++;
+ break;
case 'e':
do_header++;
do_sections++;
if (!do_dynamic && !do_syms && !do_reloc && !do_unwind && !do_sections
&& !do_segments && !do_header && !do_dump && !do_version
- && !do_histogram && !do_debugging && !do_arch && !do_notes)
+ && !do_histogram && !do_debugging && !do_arch && !do_notes
+ && !do_section_groups)
usage ();
else if (argc < 3)
{
if (dynamic_addr)
error (_("more than one dynamic segment\n"));
- dynamic_addr = segment->p_offset;
- dynamic_size = segment->p_filesz;
+ /* Try to locate the .dynamic section. If there is
+ a section header table, we can easily locate it. */
+ if (section_headers != NULL)
+ {
+ Elf_Internal_Shdr *sec;
+ unsigned int j;
+
+ for (j = 0, sec = section_headers;
+ j < elf_header.e_shnum;
+ j++, sec++)
+ if (strcmp (SECTION_NAME (sec), ".dynamic") == 0)
+ break;
+
+ if (j == elf_header.e_shnum || sec->sh_size == 0)
+ {
+ error (_("no .dynamic section in the dynamic segment"));
+ break;
+ }
+
+ dynamic_addr = sec->sh_offset;
+ dynamic_size = sec->sh_size;
+
+ 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"));
+ else if (dynamic_addr > segment->p_offset)
+ warn (_("the .dynamic section is not the first section in the dynamic segment."));
+ }
+ else
+ {
+ /* Otherwise, we can only assume that the .dynamic
+ section is the first section in the DYNAMIC segment. */
+ dynamic_addr = segment->p_offset;
+ dynamic_size = segment->p_filesz;
+ }
break;
case PT_INTERP:
printf (" %3s ", get_elf_section_flags (section->sh_flags));
- printf ("%2ld %3lx %2ld\n",
+ printf ("%2ld %3lu %2ld\n",
(unsigned long) section->sh_link,
(unsigned long) section->sh_info,
(unsigned long) section->sh_addralign);
printf (" %3s ", get_elf_section_flags (section->sh_flags));
- printf ("%2ld %3lx ",
+ printf ("%2ld %3lu ",
(unsigned long) section->sh_link,
(unsigned long) section->sh_info);
printf (" %3s ", get_elf_section_flags (section->sh_flags));
- printf (" %2ld %3lx %ld\n",
+ printf (" %2ld %3lu %ld\n",
(unsigned long) section->sh_link,
(unsigned long) section->sh_info,
(unsigned long) section->sh_addralign);
return 1;
}
+static const char *
+get_group_flags (unsigned int flags)
+{
+ static char buff[32];
+ switch (flags)
+ {
+ case GRP_COMDAT:
+ return "COMDAT";
+
+ default:
+ sprintf (buff, _("[<unknown>: 0x%x]"), flags);
+ break;
+ }
+ return buff;
+}
+
+static int
+process_section_groups (FILE *file)
+{
+ Elf_Internal_Shdr *section;
+ unsigned int i;
+ struct group *group;
+
+ if (elf_header.e_shnum == 0)
+ {
+ if (do_section_groups)
+ printf (_("\nThere are no section groups in this file.\n"));
+
+ return 1;
+ }
+
+ if (section_headers == NULL)
+ {
+ error (_("Section headers are not available!\n"));
+ abort ();
+ }
+
+ section_headers_groups = calloc (elf_header.e_shnum,
+ sizeof (struct group *));
+
+ if (section_headers_groups == NULL)
+ {
+ error (_("Out of memory\n"));
+ return 0;
+ }
+
+ /* Scan the sections for the group section. */
+ for (i = 0, section = section_headers;
+ i < elf_header.e_shnum;
+ i++, section++)
+ if (section->sh_type == SHT_GROUP)
+ group_count++;
+
+ section_groups = calloc (group_count, sizeof (struct group));
+
+ if (section_groups == NULL)
+ {
+ error (_("Out of memory\n"));
+ return 0;
+ }
+
+ for (i = 0, section = section_headers, group = section_groups;
+ i < elf_header.e_shnum;
+ i++, section++)
+ {
+ if (section->sh_type == SHT_GROUP)
+ {
+ char *name = SECTION_NAME (section);
+ char *group_name, *strtab, *start, *indices;
+ unsigned int entry, j, size;
+ Elf_Internal_Sym *sym;
+ Elf_Internal_Shdr *symtab_sec, *strtab_sec, *sec;
+ Elf_Internal_Sym *symtab;
+
+ /* Get the symbol table. */
+ symtab_sec = SECTION_HEADER (section->sh_link);
+ if (symtab_sec->sh_type != SHT_SYMTAB)
+ {
+ error (_("Bad sh_link in group section `%s'\n"), name);
+ continue;
+ }
+ symtab = GET_ELF_SYMBOLS (file, symtab_sec);
+
+ sym = symtab + section->sh_info;
+
+ if (ELF_ST_TYPE (sym->st_info) == STT_SECTION)
+ {
+ bfd_vma sec_index = SECTION_HEADER_INDEX (sym->st_shndx);
+ if (sec_index == 0)
+ {
+ error (_("Bad sh_info in group section `%s'\n"), name);
+ continue;
+ }
+
+ group_name = SECTION_NAME (section_headers + sec_index);
+ strtab = NULL;
+ }
+ else
+ {
+ /* Get the string table. */
+ strtab_sec = SECTION_HEADER (symtab_sec->sh_link);
+ strtab = get_data (NULL, file, strtab_sec->sh_offset,
+ strtab_sec->sh_size,
+ _("string table"));
+
+ group_name = strtab + sym->st_name;
+ }
+
+ start = get_data (NULL, file, section->sh_offset,
+ section->sh_size, _("section data"));
+
+ indices = start;
+ size = (section->sh_size / section->sh_entsize) - 1;
+ entry = byte_get (indices, 4);
+ indices += 4;
+
+ if (do_section_groups)
+ {
+ printf ("\n%s group section `%s' [%s] contains %u sections:\n",
+ get_group_flags (entry), name, group_name, size);
+
+ printf (_(" [Index] Name\n"));
+ }
+
+ group->group_index = i;
+
+ for (j = 0; j < size; j++)
+ {
+ struct group_list *g;
+
+ entry = byte_get (indices, 4);
+ indices += 4;
+
+ if (section_headers_groups [SECTION_HEADER_INDEX (entry)]
+ != NULL)
+ {
+ error (_("section [%5u] already in group section [%5u]\n"),
+ entry, section_headers_groups [SECTION_HEADER_INDEX (entry)]->group_index);
+ continue;
+ }
+
+ section_headers_groups [SECTION_HEADER_INDEX (entry)]
+ = group;
+
+ if (do_section_groups)
+ {
+ sec = SECTION_HEADER (entry);
+ printf (" [%5u] %s\n",
+ entry, SECTION_NAME (sec));
+ }
+
+ g = xmalloc (sizeof (struct group_list));
+ g->section_index = entry;
+ g->next = group->root;
+ group->root = g;
+ }
+
+ if (strtab)
+ free (strtab);
+ if (start)
+ free (start);
+
+ group++;
+ }
+ }
+
+ return 1;
+}
+
struct
{
const char *name;
unwstart = i + 1;
len = sizeof (ELF_STRING_ia64_unwind_once) - 1;
- if (strncmp (SECTION_NAME (unwsec), ELF_STRING_ia64_unwind_once,
- len) == 0)
+ if ((unwsec->sh_flags & SHF_GROUP) != 0)
+ {
+ /* We need to find which section group it is in. */
+ struct group_list *g = section_headers_groups [i]->root;
+
+ for (; g != NULL; g = g->next)
+ {
+ sec = SECTION_HEADER (g->section_index);
+ if (strcmp (SECTION_NAME (sec),
+ ELF_STRING_ia64_unwind_info) == 0)
+ break;
+ }
+
+ if (g == NULL)
+ i = elf_header.e_shnum;
+ }
+ else if (strncmp (SECTION_NAME (unwsec),
+ ELF_STRING_ia64_unwind_once, len) == 0)
{
/* .gnu.linkonce.ia64unw.FOO -> .gnu.linkonce.ia64unwi.FOO */
len2 = sizeof (ELF_STRING_ia64_unwind_info_once) - 1;
}
static void
-dynamic_segment_mips_val (Elf_Internal_Dyn *entry)
+dynamic_section_mips_val (Elf_Internal_Dyn *entry)
{
switch (entry->d_tag)
{
static void
-dynamic_segment_parisc_val (Elf_Internal_Dyn *entry)
+dynamic_section_parisc_val (Elf_Internal_Dyn *entry)
{
switch (entry->d_tag)
{
}
static void
-dynamic_segment_ia64_val (Elf_Internal_Dyn *entry)
+dynamic_section_ia64_val (Elf_Internal_Dyn *entry)
{
switch (entry->d_tag)
{
}
static int
-get_32bit_dynamic_segment (FILE *file)
+get_32bit_dynamic_section (FILE *file)
{
- Elf32_External_Dyn *edyn;
+ Elf32_External_Dyn *edyn, *ext;
Elf_Internal_Dyn *entry;
- bfd_size_type i;
edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
- _("dynamic segment"));
+ _("dynamic section"));
if (!edyn)
return 0;
- /* SGI's ELF has more than one section in the DYNAMIC segment. Determine
- how large this .dynamic is now. We can do this even before the byte
- swapping since the DT_NULL tag is recognizable. */
- dynamic_size = 0;
- while (*(Elf32_Word *) edyn[dynamic_size++].d_tag != DT_NULL)
- ;
-
- dynamic_segment = malloc (dynamic_size * sizeof (Elf_Internal_Dyn));
+/* SGI's ELF has more than one section in the DYNAMIC segment, and we
+ might not have the luxury of section headers. Look for the DT_NULL
+ terminator to determine the number of entries. */
+ for (ext = edyn, dynamic_nent = 0;
+ (char *) ext < (char *) edyn + dynamic_size;
+ ext++)
+ {
+ dynamic_nent++;
+ if (BYTE_GET (ext->d_tag) == DT_NULL)
+ break;
+ }
- if (dynamic_segment == NULL)
+ dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+ if (dynamic_section == NULL)
{
error (_("Out of memory\n"));
free (edyn);
return 0;
}
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- i++, entry++)
+ for (ext = edyn, entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ ext++, entry++)
{
- entry->d_tag = BYTE_GET (edyn[i].d_tag);
- entry->d_un.d_val = BYTE_GET (edyn[i].d_un.d_val);
+ entry->d_tag = BYTE_GET (ext->d_tag);
+ entry->d_un.d_val = BYTE_GET (ext->d_un.d_val);
}
free (edyn);
}
static int
-get_64bit_dynamic_segment (FILE *file)
+get_64bit_dynamic_section (FILE *file)
{
- Elf64_External_Dyn *edyn;
+ Elf64_External_Dyn *edyn, *ext;
Elf_Internal_Dyn *entry;
- bfd_size_type i;
edyn = get_data (NULL, file, dynamic_addr, dynamic_size,
- _("dynamic segment"));
+ _("dynamic section"));
if (!edyn)
return 0;
- /* SGI's ELF has more than one section in the DYNAMIC segment. Determine
- how large this .dynamic is now. We can do this even before the byte
- swapping since the DT_NULL tag is recognizable. */
- dynamic_size = 0;
- while (*(bfd_vma *) edyn[dynamic_size++].d_tag != DT_NULL)
- ;
-
- dynamic_segment = malloc (dynamic_size * sizeof (Elf_Internal_Dyn));
+/* SGI's ELF has more than one section in the DYNAMIC segment, and we
+ might not have the luxury of section headers. Look for the DT_NULL
+ terminator to determine the number of entries. */
+ for (ext = edyn, dynamic_nent = 0;
+ (char *) ext < (char *) edyn + dynamic_size;
+ ext++)
+ {
+ dynamic_nent++;
+ if (BYTE_GET8 (ext->d_tag) == DT_NULL)
+ break;
+ }
- if (dynamic_segment == NULL)
+ dynamic_section = malloc (dynamic_nent * sizeof (*entry));
+ if (dynamic_section == NULL)
{
error (_("Out of memory\n"));
free (edyn);
return 0;
}
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- i++, entry++)
+ for (ext = edyn, entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ ext++, entry++)
{
- entry->d_tag = BYTE_GET8 (edyn[i].d_tag);
- entry->d_un.d_val = BYTE_GET8 (edyn[i].d_un.d_val);
+ entry->d_tag = BYTE_GET8 (ext->d_tag);
+ entry->d_un.d_val = BYTE_GET8 (ext->d_un.d_val);
}
free (edyn);
return buff;
}
-/* Parse and display the contents of the dynamic segment. */
+/* Parse and display the contents of the dynamic section. */
+
static int
-process_dynamic_segment (FILE *file)
+process_dynamic_section (FILE *file)
{
Elf_Internal_Dyn *entry;
- bfd_size_type i;
if (dynamic_size == 0)
{
if (do_dynamic)
- printf (_("\nThere is no dynamic segment in this file.\n"));
+ printf (_("\nThere is no dynamic section in this file.\n"));
return 1;
}
if (is_32bit_elf)
{
- if (! get_32bit_dynamic_segment (file))
+ if (! get_32bit_dynamic_section (file))
return 0;
}
- else if (! get_64bit_dynamic_segment (file))
+ else if (! get_64bit_dynamic_section (file))
return 0;
/* Find the appropriate symbol table. */
if (dynamic_symbols == NULL)
{
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- ++i, ++entry)
+ for (entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ ++entry)
{
Elf_Internal_Shdr section;
/* Similarly find a string table. */
if (dynamic_strings == NULL)
{
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- ++i, ++entry)
+ for (entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ ++entry)
{
unsigned long offset;
long str_tab_len;
{
unsigned long syminsz = 0;
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- ++i, ++entry)
+ for (entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ ++entry)
{
if (entry->d_tag == DT_SYMINENT)
{
if (dynamic_syminfo_offset != 0 && syminsz != 0)
{
- Elf_External_Syminfo *extsyminfo;
+ Elf_External_Syminfo *extsyminfo, *extsym;
Elf_Internal_Syminfo *syminfo;
/* There is a syminfo section. Read the data. */
}
dynamic_syminfo_nent = syminsz / sizeof (Elf_External_Syminfo);
- for (i = 0, syminfo = dynamic_syminfo; i < dynamic_syminfo_nent;
- ++i, ++syminfo)
+ for (syminfo = dynamic_syminfo, extsym = extsyminfo;
+ syminfo < dynamic_syminfo + dynamic_syminfo_nent;
+ ++syminfo, ++extsym)
{
- syminfo->si_boundto = BYTE_GET (extsyminfo[i].si_boundto);
- syminfo->si_flags = BYTE_GET (extsyminfo[i].si_flags);
+ syminfo->si_boundto = BYTE_GET (extsym->si_boundto);
+ syminfo->si_flags = BYTE_GET (extsym->si_flags);
}
free (extsyminfo);
}
if (do_dynamic && dynamic_addr)
- printf (_("\nDynamic segment at offset 0x%lx contains %ld entries:\n"),
- dynamic_addr, (long) dynamic_size);
+ printf (_("\nDynamic section at offset 0x%lx contains %u entries:\n"),
+ dynamic_addr, dynamic_nent);
if (do_dynamic)
printf (_(" Tag Type Name/Value\n"));
- for (i = 0, entry = dynamic_segment;
- i < dynamic_size;
- i++, entry++)
+ for (entry = dynamic_section;
+ entry < dynamic_section + dynamic_nent;
+ entry++)
{
if (do_dynamic)
{
{
case EM_MIPS:
case EM_MIPS_RS3_LE:
- dynamic_segment_mips_val (entry);
+ dynamic_section_mips_val (entry);
break;
case EM_PARISC:
- dynamic_segment_parisc_val (entry);
+ dynamic_section_parisc_val (entry);
break;
case EM_IA_64:
- dynamic_segment_ia64_val (entry);
+ dynamic_section_ia64_val (entry);
break;
default:
print_vma (entry->d_un.d_val, PREFIX_HEX);
break;
default:
if (dynamic_syminfo[i].si_boundto > 0
- && dynamic_syminfo[i].si_boundto < dynamic_size)
+ && dynamic_syminfo[i].si_boundto < dynamic_nent)
{
print_symbol (10,
dynamic_strings
- + (dynamic_segment
+ + (dynamic_section
[dynamic_syminfo[i].si_boundto].d_un.d_val));
putchar (' ' );
}
case DW_TAG_partial_unit: return "DW_TAG_partial_unit";
case DW_TAG_imported_unit: return "DW_TAG_imported_unit";
/* UPC values. */
- case DW_TAG_upc_shared_type: return "DW_TAG_upc_shared_type";
- case DW_TAG_upc_strict_type: return "DW_TAG_upc_strict_type";
- case DW_TAG_upc_relaxed_type: return "DW_TAG_upc_relaxed_type";
+ case DW_TAG_upc_shared_type: return "DW_TAG_upc_shared_type";
+ case DW_TAG_upc_strict_type: return "DW_TAG_upc_strict_type";
+ case DW_TAG_upc_relaxed_type: return "DW_TAG_upc_relaxed_type";
default:
{
static char buffer[100];
data += offset_size;
}
else
- {
+ {
error (_("Internal error: DWARF version is not 2 or 3.\n"));
}
break;
return data;
}
+/* Apply addends of RELA relocations. */
+
+static int
+debug_apply_rela_addends (FILE *file,
+ Elf_Internal_Shdr *section,
+ int reloc_size,
+ unsigned char *sec_data,
+ unsigned char *start,
+ unsigned char *end)
+{
+ Elf_Internal_Shdr *relsec;
+
+ if (end - start < reloc_size)
+ return 1;
+
+ for (relsec = section_headers;
+ relsec < section_headers + elf_header.e_shnum;
+ ++relsec)
+ {
+ unsigned long nrelas;
+ Elf_Internal_Rela *rela, *rp;
+ Elf_Internal_Shdr *symsec;
+ Elf_Internal_Sym *symtab;
+ Elf_Internal_Sym *sym;
+
+ if (relsec->sh_type != SHT_RELA
+ || SECTION_HEADER (relsec->sh_info) != section
+ || relsec->sh_size == 0)
+ continue;
+
+ if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
+ &rela, &nrelas))
+ return 0;
+
+ symsec = SECTION_HEADER (relsec->sh_link);
+ symtab = GET_ELF_SYMBOLS (file, symsec);
+
+ for (rp = rela; rp < rela + nrelas; ++rp)
+ {
+ unsigned char *loc;
+
+ if (rp->r_offset >= (bfd_vma) (start - sec_data)
+ && rp->r_offset < (bfd_vma) (end - sec_data) - reloc_size)
+ loc = sec_data + rp->r_offset;
+ else
+ continue;
+
+ if (is_32bit_elf)
+ {
+ sym = symtab + ELF32_R_SYM (rp->r_info);
+
+ if (ELF32_R_SYM (rp->r_info) != 0
+ && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
+ {
+ warn (_("Skipping unexpected symbol type %u\n"),
+ ELF32_ST_TYPE (sym->st_info));
+ continue;
+ }
+ }
+ else
+ {
+ sym = symtab + ELF64_R_SYM (rp->r_info);
+
+ if (ELF64_R_SYM (rp->r_info) != 0
+ && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
+ {
+ warn (_("Skipping unexpected symbol type %u\n"),
+ ELF64_ST_TYPE (sym->st_info));
+ continue;
+ }
+ }
+
+ byte_put (loc, rp->r_addend, reloc_size);
+ }
+
+ free (symtab);
+ free (rela);
+ break;
+ }
+ return 1;
+}
+
static int
display_debug_info (Elf_Internal_Shdr *section,
unsigned char *start,
while (start < end)
{
DWARF2_Internal_CompUnit compunit;
- Elf_Internal_Shdr *relsec;
unsigned char *hdrptr;
unsigned char *cu_abbrev_offset_ptr;
unsigned char *tags;
compunit.cu_version = byte_get (hdrptr, 2);
hdrptr += 2;
- /* Apply addends of RELA relocations. */
- for (relsec = section_headers;
- relsec < section_headers + elf_header.e_shnum;
- ++relsec)
- {
- unsigned long nrelas;
- Elf_Internal_Rela *rela, *rp;
- Elf_Internal_Shdr *symsec;
- Elf_Internal_Sym *symtab;
- Elf_Internal_Sym *sym;
-
- if (relsec->sh_type != SHT_RELA
- || SECTION_HEADER (relsec->sh_info) != section
- || relsec->sh_size == 0)
- continue;
-
- if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
- & rela, & nrelas))
- return 0;
-
- symsec = SECTION_HEADER (relsec->sh_link);
- symtab = GET_ELF_SYMBOLS (file, symsec);
-
- for (rp = rela; rp < rela + nrelas; ++rp)
- {
- unsigned char *loc;
-
- if (rp->r_offset >= (bfd_vma) (hdrptr - section_begin)
- && section->sh_size > (bfd_vma) offset_size
- && rp->r_offset <= section->sh_size - offset_size)
- loc = section_begin + rp->r_offset;
- else
- continue;
-
- if (is_32bit_elf)
- {
- sym = symtab + ELF32_R_SYM (rp->r_info);
-
- if (ELF32_R_SYM (rp->r_info) != 0
- && ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF32_ST_TYPE (sym->st_info));
- continue;
- }
- }
- else
- {
- sym = symtab + ELF64_R_SYM (rp->r_info);
-
- if (ELF64_R_SYM (rp->r_info) != 0
- && ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
- {
- warn (_("Skipping unexpected symbol type %u\n"),
- ELF64_ST_TYPE (sym->st_info));
- continue;
- }
- }
-
- byte_put (loc, rp->r_addend, offset_size);
- }
+ cu_offset = start - section_begin;
+ start += compunit.cu_length + initial_length_size;
- free (rela);
- break;
- }
+ if (elf_header.e_type == ET_REL
+ && !debug_apply_rela_addends (file, section, offset_size,
+ section_begin, hdrptr, start))
+ return 0;
cu_abbrev_offset_ptr = hdrptr;
compunit.cu_abbrev_offset = byte_get (hdrptr, offset_size);
hdrptr += 1;
tags = hdrptr;
- cu_offset = start - section_begin;
- start += compunit.cu_length + initial_length_size;
printf (_(" Compilation Unit @ %lx:\n"), cu_offset);
printf (_(" Length: %ld\n"), compunit.cu_length);
initial_length_size = 12;
}
else
- {
+ {
offset_size = 4;
initial_length_size = 4;
}
block_end = saved_start + length + initial_length_size;
cie_id = byte_get (start, offset_size); start += offset_size;
+ if (elf_header.e_type == ET_REL
+ && !debug_apply_rela_addends (file, section, offset_size,
+ section_start, start, block_end))
+ return 0;
+
if (is_eh ? (cie_id == 0) : (cie_id == DW_CIE_ID))
{
int version;
{
fc->code_factor = LEB ();
fc->data_factor = SLEB ();
- fc->ra = byte_get (start, 1); start += 1;
+ if (version == 1)
+ {
+ fc->ra = GET (1);
+ }
+ else
+ {
+ fc->ra = LEB ();
+ }
augmentation_data_len = LEB ();
augmentation_data = start;
start += augmentation_data_len;
start += addr_size;
fc->code_factor = LEB ();
fc->data_factor = SLEB ();
- fc->ra = byte_get (start, 1); start += 1;
+ if (version == 1)
+ {
+ fc->ra = GET (1);
+ }
+ else
+ {
+ fc->ra = LEB ();
+ }
}
else
{
fc->code_factor = LEB ();
fc->data_factor = SLEB ();
- fc->ra = byte_get (start, 1); start += 1;
+ if (version == 1)
+ {
+ fc->ra = GET (1);
+ }
+ else
+ {
+ fc->ra = LEB ();
+ }
}
cie = fc;
encoded_ptr_size = size_of_encoded_value (fc->fde_encoding);
fc->pc_begin = get_encoded_value (start, fc->fde_encoding);
- if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+ if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+ /* Don't adjust for ET_REL since there's invariably a pcrel
+ reloc here, which we haven't applied. */
+ && elf_header.e_type != ET_REL)
fc->pc_begin += section->sh_addr + (start - section_start);
start += encoded_ptr_size;
fc->pc_range = byte_get (start, encoded_ptr_size);
unsigned long i;
printf (" Augmentation data: ");
for (i = 0; i < augmentation_data_len; ++i)
- printf (" %02x", augmentation_data[i]);
+ printf (" %02x", augmentation_data[i]);
putchar ('\n');
putchar ('\n');
}
op &= 0xc0;
/* Warning: if you add any more cases to this switch, be
- sure to add them to the corresponding switch below. */
+ sure to add them to the corresponding switch below. */
switch (op)
{
case DW_CFA_advance_loc:
}
/* Now we know what registers are used, make a second pass over
- the chunk, this time actually printing out the info. */
+ the chunk, this time actually printing out the info. */
while (start < block_end)
{
case DW_CFA_set_loc:
vma = get_encoded_value (start, fc->fde_encoding);
- if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel)
+ if ((fc->fde_encoding & 0x70) == DW_EH_PE_pcrel
+ && elf_header.e_type != ET_REL)
vma += section->sh_addr + (start - section_start);
start += encoded_ptr_size;
if (do_debug_frames_interp)
size_t conflicts_offset = 0;
/* We have a lot of special sections. Thanks SGI! */
- if (dynamic_segment == NULL)
+ if (dynamic_section == NULL)
/* No information available. */
return 0;
- for (entry = dynamic_segment; entry->d_tag != DT_NULL; ++entry)
+ for (entry = dynamic_section; entry->d_tag != DT_NULL; ++entry)
switch (entry->d_tag)
{
case DT_MIPS_LIBLIST:
if (! process_file_header ())
return 1;
- if (! process_section_headers (file))
+ if (! process_section_headers (file)
+ || ! process_section_groups (file))
{
- /* Without loaded section headers we
+ /* Without loaded section headers and section groups we
cannot process lots of things. */
do_unwind = do_version = do_dump = do_arch = 0;
}
if (process_program_headers (file))
- process_dynamic_segment (file);
+ process_dynamic_section (file);
process_relocs (file);
dynamic_syminfo = NULL;
}
+ if (section_headers_groups)
+ {
+ free (section_headers_groups);
+ section_headers_groups = NULL;
+ }
+
+ if (section_groups)
+ {
+ struct group_list *g, *next;
+
+ for (i = 0; i < group_count; i++)
+ {
+ for (g = section_groups [i].root; g != NULL; g = next)
+ {
+ next = g->next;
+ free (g);
+ }
+ }
+
+ free (section_groups);
+ section_groups = NULL;
+ }
+
return 0;
}