Add -u option toi readelf to display unwind info.
Add support to display unwind info for IA64 binaries.
This commit is contained in:
parent
a6da1910ac
commit
4d6ed7c8ce
7 changed files with 2130 additions and 489 deletions
|
@ -1,3 +1,18 @@
|
|||
2001-02-07 David Mosberger <davidm@hpl.hp.com>
|
||||
|
||||
* readelf.c (process_unwind): New function.
|
||||
(slurp_ia64_unwind_table): Ditto.
|
||||
(dump_ia64_unwind): Ditto.
|
||||
(find_symbol_for_address): Ditto.
|
||||
(slurp_rela_relocs): New function (split off from dump_relocations()).
|
||||
(slurp_rel_relocs): Ditto.
|
||||
(parse_args): Handle '-u' option.
|
||||
|
||||
* unwind-ia64.c: New file.
|
||||
* unwind-ia64.h: New file.
|
||||
* Makefile.am: Include unwind-ia64.c in readelf build.
|
||||
* Makefile.in: Regenerate.
|
||||
|
||||
2001-02-04 Philip Blundell <philb@gnu.org>
|
||||
|
||||
* configure.in (OBJDUMP_DEFS): Match `arm*-*', not just `arm-*'.
|
||||
|
|
|
@ -161,7 +161,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
|
|||
|
||||
strings_SOURCES = strings.c $(BULIBS)
|
||||
|
||||
readelf_SOURCES = readelf.c version.c
|
||||
readelf_SOURCES = readelf.c version.c unwind-ia64.c
|
||||
readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
|
||||
|
||||
strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
|
||||
|
|
|
@ -253,7 +253,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
|
|||
|
||||
strings_SOURCES = strings.c $(BULIBS)
|
||||
|
||||
readelf_SOURCES = readelf.c version.c
|
||||
readelf_SOURCES = readelf.c version.c unwind-ia64.c
|
||||
readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
|
||||
|
||||
strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
|
||||
|
@ -394,7 +394,8 @@ version.$(OBJEXT) filemode.$(OBJEXT)
|
|||
addr2line_LDADD = $(LDADD)
|
||||
addr2line_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a
|
||||
addr2line_LDFLAGS =
|
||||
readelf_OBJECTS = readelf.$(OBJEXT) version.$(OBJEXT)
|
||||
readelf_OBJECTS = readelf.$(OBJEXT) version.$(OBJEXT) \
|
||||
unwind-ia64.$(OBJEXT)
|
||||
readelf_DEPENDENCIES = ../libiberty/libiberty.a
|
||||
readelf_LDFLAGS =
|
||||
nm_new_OBJECTS = nm.$(OBJEXT) bucomm.$(OBJEXT) version.$(OBJEXT) \
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -104,6 +104,7 @@ int do_syms;
|
|||
int do_reloc;
|
||||
int do_sections;
|
||||
int do_segments;
|
||||
int do_unwind;
|
||||
int do_using_dynamic;
|
||||
int do_header;
|
||||
int do_dump;
|
||||
|
@ -150,6 +151,8 @@ static const char * get_mips_dynamic_type PARAMS ((unsigned long));
|
|||
static const char * get_sparc64_dynamic_type PARAMS ((unsigned long));
|
||||
static const char * get_parisc_dynamic_type PARAMS ((unsigned long));
|
||||
static const char * get_dynamic_type PARAMS ((unsigned long));
|
||||
static int slurp_rela_relocs PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rela **, unsigned long *));
|
||||
static int slurp_rel_relocs PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Rel **, unsigned long *));
|
||||
static int dump_relocations PARAMS ((FILE *, unsigned long, unsigned long, Elf_Internal_Sym *, unsigned long, char *, int));
|
||||
static char * get_file_type PARAMS ((unsigned));
|
||||
static char * get_machine_name PARAMS ((unsigned));
|
||||
|
@ -157,9 +160,11 @@ static void decode_ARM_machine_flags PARAMS ((unsigned, char []));
|
|||
static char * get_machine_flags PARAMS ((unsigned, unsigned));
|
||||
static const char * get_mips_segment_type PARAMS ((unsigned long));
|
||||
static const char * get_parisc_segment_type PARAMS ((unsigned long));
|
||||
static const char * get_ia64_segment_type PARAMS ((unsigned long));
|
||||
static const char * get_segment_type PARAMS ((unsigned long));
|
||||
static const char * get_mips_section_type_name PARAMS ((unsigned int));
|
||||
static const char * get_parisc_section_type_name PARAMS ((unsigned int));
|
||||
static const char * get_ia64_section_type_name PARAMS ((unsigned int));
|
||||
static const char * get_section_type_name PARAMS ((unsigned int));
|
||||
static const char * get_symbol_binding PARAMS ((unsigned int));
|
||||
static const char * get_symbol_type PARAMS ((unsigned int));
|
||||
|
@ -171,6 +176,7 @@ static void parse_args PARAMS ((int, char **));
|
|||
static int process_file_header PARAMS ((void));
|
||||
static int process_program_headers PARAMS ((FILE *));
|
||||
static int process_section_headers PARAMS ((FILE *));
|
||||
static int process_unwind PARAMS ((FILE *));
|
||||
static void dynamic_segment_mips_val PARAMS ((Elf_Internal_Dyn *));
|
||||
static void dynamic_segment_parisc_val PARAMS ((Elf_Internal_Dyn *));
|
||||
static int process_dynamic_segment PARAMS ((FILE *));
|
||||
|
@ -187,6 +193,7 @@ static int get_64bit_program_headers PARAMS ((FILE *, Elf_Internal_Phdr *))
|
|||
static int get_file_header PARAMS ((FILE *));
|
||||
static Elf_Internal_Sym * get_32bit_elf_symbols PARAMS ((FILE *, unsigned long, unsigned long));
|
||||
static Elf_Internal_Sym * get_64bit_elf_symbols PARAMS ((FILE *, unsigned long, unsigned long));
|
||||
static const char * get_elf_section_flags PARAMS ((bfd_vma));
|
||||
static int * get_dynamic_data PARAMS ((FILE *, unsigned int));
|
||||
static int get_32bit_dynamic_segment PARAMS ((FILE *));
|
||||
static int get_64bit_dynamic_segment PARAMS ((FILE *));
|
||||
|
@ -244,7 +251,7 @@ typedef int Elf32_Word;
|
|||
/* If we can support a 64 bit data type then BFD64 should be defined
|
||||
and sizeof (bfd_vma) == 8. In this case when translating from an
|
||||
external 8 byte field to an internal field, we can assume that the
|
||||
internal field is also 8 bytes wide and so we can extact all the data.
|
||||
internal field is also 8 bytes wide and so we can extract all the data.
|
||||
If, however, BFD64 is not defined, then we must assume that the
|
||||
internal data structure only has 4 byte wide fields that are the
|
||||
equivalent of the 8 byte wide external counterparts, and so we must
|
||||
|
@ -602,6 +609,144 @@ guess_is_rela (e_machine)
|
|||
}
|
||||
}
|
||||
|
||||
static int
|
||||
slurp_rela_relocs (file, rel_offset, rel_size, relasp, nrelasp)
|
||||
FILE *file;
|
||||
unsigned long rel_offset;
|
||||
unsigned long rel_size;
|
||||
Elf_Internal_Rela **relasp;
|
||||
unsigned long *nrelasp;
|
||||
{
|
||||
Elf_Internal_Rela *relas;
|
||||
unsigned long nrelas;
|
||||
unsigned int i;
|
||||
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
Elf32_External_Rela * erelas;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erelas,
|
||||
Elf32_External_Rela *, "relocs");
|
||||
|
||||
nrelas = rel_size / sizeof (Elf32_External_Rela);
|
||||
|
||||
relas = (Elf_Internal_Rela *)
|
||||
malloc (nrelas * sizeof (Elf_Internal_Rela));
|
||||
|
||||
if (relas == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nrelas; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
free (erelas);
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf64_External_Rela * erelas;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erelas,
|
||||
Elf64_External_Rela *, "relocs");
|
||||
|
||||
nrelas = rel_size / sizeof (Elf64_External_Rela);
|
||||
|
||||
relas = (Elf_Internal_Rela *)
|
||||
malloc (nrelas * sizeof (Elf_Internal_Rela));
|
||||
|
||||
if (relas == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nrelas; i++)
|
||||
{
|
||||
relas[i].r_offset = BYTE_GET8 (erelas[i].r_offset);
|
||||
relas[i].r_info = BYTE_GET8 (erelas[i].r_info);
|
||||
relas[i].r_addend = BYTE_GET8 (erelas[i].r_addend);
|
||||
}
|
||||
|
||||
free (erelas);
|
||||
}
|
||||
*relasp = relas;
|
||||
*nrelasp = nrelas;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
slurp_rel_relocs (file, rel_offset, rel_size, relsp, nrelsp)
|
||||
FILE *file;
|
||||
unsigned long rel_offset;
|
||||
unsigned long rel_size;
|
||||
Elf_Internal_Rel **relsp;
|
||||
unsigned long *nrelsp;
|
||||
{
|
||||
Elf_Internal_Rel *rels;
|
||||
unsigned long nrels;
|
||||
unsigned int i;
|
||||
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
Elf32_External_Rel * erels;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erels,
|
||||
Elf32_External_Rel *, "relocs");
|
||||
|
||||
nrels = rel_size / sizeof (Elf32_External_Rel);
|
||||
|
||||
rels = (Elf_Internal_Rel *) malloc (nrels * sizeof (Elf_Internal_Rel));
|
||||
|
||||
if (rels == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nrels; i++)
|
||||
{
|
||||
rels[i].r_offset = BYTE_GET (erels[i].r_offset);
|
||||
rels[i].r_info = BYTE_GET (erels[i].r_info);
|
||||
}
|
||||
|
||||
free (erels);
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf64_External_Rel * erels;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erels,
|
||||
Elf64_External_Rel *, "relocs");
|
||||
|
||||
nrels = rel_size / sizeof (Elf64_External_Rel);
|
||||
|
||||
rels = (Elf_Internal_Rel *) malloc (nrels * sizeof (Elf_Internal_Rel));
|
||||
|
||||
if (rels == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < nrels; i++)
|
||||
{
|
||||
rels[i].r_offset = BYTE_GET8 (erels[i].r_offset);
|
||||
rels[i].r_info = BYTE_GET8 (erels[i].r_info);
|
||||
}
|
||||
|
||||
free (erels);
|
||||
}
|
||||
*relsp = rels;
|
||||
*nrelsp = nrels;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Display the contents of the relocation data found at the specified offset. */
|
||||
static int
|
||||
dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
|
||||
|
@ -623,123 +768,13 @@ dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela)
|
|||
|
||||
if (is_rela)
|
||||
{
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
Elf32_External_Rela * erelas;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erelas,
|
||||
Elf32_External_Rela *, "relocs");
|
||||
|
||||
rel_size = rel_size / sizeof (Elf32_External_Rela);
|
||||
|
||||
relas = (Elf_Internal_Rela *)
|
||||
malloc (rel_size * sizeof (Elf_Internal_Rela));
|
||||
|
||||
if (relas == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rel_size; i++)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
free (erelas);
|
||||
|
||||
rels = (Elf_Internal_Rel *) relas;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf64_External_Rela * erelas;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erelas,
|
||||
Elf64_External_Rela *, "relocs");
|
||||
|
||||
rel_size = rel_size / sizeof (Elf64_External_Rela);
|
||||
|
||||
relas = (Elf_Internal_Rela *)
|
||||
malloc (rel_size * sizeof (Elf_Internal_Rela));
|
||||
|
||||
if (relas == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rel_size; i++)
|
||||
{
|
||||
relas[i].r_offset = BYTE_GET8 (erelas[i].r_offset);
|
||||
relas[i].r_info = BYTE_GET8 (erelas[i].r_info);
|
||||
relas[i].r_addend = BYTE_GET8 (erelas[i].r_addend);
|
||||
}
|
||||
|
||||
free (erelas);
|
||||
|
||||
rels = (Elf_Internal_Rel *) relas;
|
||||
}
|
||||
if (!slurp_rela_relocs (file, rel_offset, rel_size, &relas, &rel_size))
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
Elf32_External_Rel * erels;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erels,
|
||||
Elf32_External_Rel *, "relocs");
|
||||
|
||||
rel_size = rel_size / sizeof (Elf32_External_Rel);
|
||||
|
||||
rels = (Elf_Internal_Rel *)
|
||||
malloc (rel_size * sizeof (Elf_Internal_Rel));
|
||||
|
||||
if (rels == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rel_size; i++)
|
||||
{
|
||||
rels[i].r_offset = BYTE_GET (erels[i].r_offset);
|
||||
rels[i].r_info = BYTE_GET (erels[i].r_info);
|
||||
}
|
||||
|
||||
free (erels);
|
||||
|
||||
relas = (Elf_Internal_Rela *) rels;
|
||||
}
|
||||
else
|
||||
{
|
||||
Elf64_External_Rel * erels;
|
||||
|
||||
GET_DATA_ALLOC (rel_offset, rel_size, erels,
|
||||
Elf64_External_Rel *, "relocs");
|
||||
|
||||
rel_size = rel_size / sizeof (Elf64_External_Rel);
|
||||
|
||||
rels = (Elf_Internal_Rel *)
|
||||
malloc (rel_size * sizeof (Elf_Internal_Rel));
|
||||
|
||||
if (rels == NULL)
|
||||
{
|
||||
error(_("out of memory parsing relocs"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 0; i < rel_size; i++)
|
||||
{
|
||||
rels[i].r_offset = BYTE_GET8 (erels[i].r_offset);
|
||||
rels[i].r_info = BYTE_GET8 (erels[i].r_info);
|
||||
}
|
||||
|
||||
free (erels);
|
||||
|
||||
relas = (Elf_Internal_Rela *) rels;
|
||||
}
|
||||
if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size))
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_rela)
|
||||
|
@ -1565,6 +1600,21 @@ get_machine_flags (e_flags, e_machine)
|
|||
if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS)
|
||||
strcat (buf, ", gnu calling convention");
|
||||
break;
|
||||
|
||||
case EM_IA_64:
|
||||
if ((e_flags & EF_IA_64_ABI64))
|
||||
strcat (buf, ", 64-bit");
|
||||
else
|
||||
strcat (buf, ", 32-bit");
|
||||
if ((e_flags & EF_IA_64_REDUCEDFP))
|
||||
strcat (buf, ", reduced fp model");
|
||||
if ((e_flags & EF_IA_64_NOFUNCDESC_CONS_GP))
|
||||
strcat (buf, ", no function descriptors, constant gp");
|
||||
else if ((e_flags & EF_IA_64_CONS_GP))
|
||||
strcat (buf, ", constant gp");
|
||||
if ((e_flags & EF_IA_64_ABSOLUTE))
|
||||
strcat (buf, ", absolute");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1617,6 +1667,21 @@ get_parisc_segment_type (type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_ia64_segment_type (type)
|
||||
unsigned long type;
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case PT_IA_64_ARCHEXT: return "IA_64_ARCHEXT";
|
||||
case PT_IA_64_UNWIND: return "IA_64_UNWIND";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_segment_type (p_type)
|
||||
unsigned long p_type;
|
||||
|
@ -1647,6 +1712,9 @@ get_segment_type (p_type)
|
|||
case EM_PARISC:
|
||||
result = get_parisc_segment_type (p_type);
|
||||
break;
|
||||
case EM_IA_64:
|
||||
result = get_ia64_segment_type (p_type);
|
||||
break;
|
||||
default:
|
||||
result = NULL;
|
||||
break;
|
||||
|
@ -1749,6 +1817,20 @@ get_parisc_section_type_name (sh_type)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_ia64_section_type_name (sh_type)
|
||||
unsigned int sh_type;
|
||||
{
|
||||
switch (sh_type)
|
||||
{
|
||||
case SHT_IA_64_EXT: return "IA_64_EXT";
|
||||
case SHT_IA_64_UNWIND: return "IA_64_UNWIND";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const char *
|
||||
get_section_type_name (sh_type)
|
||||
unsigned int sh_type;
|
||||
|
@ -1796,6 +1878,9 @@ get_section_type_name (sh_type)
|
|||
case EM_PARISC:
|
||||
result = get_parisc_section_type_name (sh_type);
|
||||
break;
|
||||
case EM_IA_64:
|
||||
result = get_ia64_section_type_name (sh_type);
|
||||
break;
|
||||
default:
|
||||
result = NULL;
|
||||
break;
|
||||
|
@ -1837,6 +1922,7 @@ struct option options [] =
|
|||
{"use-dynamic", no_argument, 0, 'D'},
|
||||
{"hex-dump", required_argument, 0, 'x'},
|
||||
{"debug-dump", optional_argument, 0, 'w'},
|
||||
{"unwind", no_argument, 0, 'u'},
|
||||
#ifdef SUPPORT_DISASSEMBLY
|
||||
{"instruction-dump", required_argument, 0, 'i'},
|
||||
#endif
|
||||
|
@ -1861,6 +1947,7 @@ usage ()
|
|||
fprintf (stdout, _(" -s or --syms or --symbols Display the symbol table\n"));
|
||||
fprintf (stdout, _(" -n or --notes Display the core notes (if present)\n"));
|
||||
fprintf (stdout, _(" -r or --relocs Display the relocations (if present)\n"));
|
||||
fprintf (stdout, _(" -u or --unwind Display the unwind info (if present)\n"));
|
||||
fprintf (stdout, _(" -d or --dynamic Display the dynamic segment (if present)\n"));
|
||||
fprintf (stdout, _(" -V or --version-info Display the version sections (if present)\n"));
|
||||
fprintf (stdout, _(" -A or --arch-specific Display architecture specific information (if any).\n"));
|
||||
|
@ -1923,7 +2010,7 @@ parse_args (argc, argv)
|
|||
usage ();
|
||||
|
||||
while ((c = getopt_long
|
||||
(argc, argv, "ersahnldSDAIw::x:i:vV", options, NULL)) != EOF)
|
||||
(argc, argv, "ersuahnldSDAIw::x:i:vV", options, NULL)) != EOF)
|
||||
{
|
||||
char * cp;
|
||||
int section;
|
||||
|
@ -1940,6 +2027,7 @@ parse_args (argc, argv)
|
|||
case 'a':
|
||||
do_syms ++;
|
||||
do_reloc ++;
|
||||
do_unwind ++;
|
||||
do_dynamic ++;
|
||||
do_header ++;
|
||||
do_sections ++;
|
||||
|
@ -1963,6 +2051,9 @@ parse_args (argc, argv)
|
|||
case 'r':
|
||||
do_reloc ++;
|
||||
break;
|
||||
case 'u':
|
||||
do_unwind ++;
|
||||
break;
|
||||
case 'h':
|
||||
do_header ++;
|
||||
break;
|
||||
|
@ -2065,7 +2156,7 @@ parse_args (argc, argv)
|
|||
}
|
||||
}
|
||||
|
||||
if (!do_dynamic && !do_syms && !do_reloc && !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)
|
||||
usage ();
|
||||
|
@ -2976,6 +3067,366 @@ process_relocs (file)
|
|||
return 1;
|
||||
}
|
||||
|
||||
#include "unwind-ia64.h"
|
||||
|
||||
/* An absolute address consists of a section and an offset. If the
|
||||
section is NULL, the offset itself is the address, otherwise, the
|
||||
address equals to LOAD_ADDRESS(section) + offset. */
|
||||
|
||||
struct absaddr
|
||||
{
|
||||
unsigned short section;
|
||||
bfd_vma offset;
|
||||
};
|
||||
|
||||
struct unw_aux_info
|
||||
{
|
||||
struct unw_table_entry
|
||||
{
|
||||
struct absaddr start;
|
||||
struct absaddr end;
|
||||
struct absaddr info;
|
||||
}
|
||||
*table; /* Unwind table. */
|
||||
unsigned long table_len; /* Length of unwind table. */
|
||||
const unsigned char * info; /* Unwind info. */
|
||||
unsigned long info_size; /* Size of unwind info. */
|
||||
bfd_vma info_addr; /* starting address of unwind info. */
|
||||
bfd_vma seg_base; /* Starting address of segment. */
|
||||
Elf_Internal_Sym * symtab; /* The symbol table. */
|
||||
unsigned long nsyms; /* Number of symbols. */
|
||||
const char * strtab; /* The string table. */
|
||||
unsigned long strtab_size; /* Size of string table. */
|
||||
};
|
||||
|
||||
static void find_symbol_for_address PARAMS ((struct unw_aux_info *,
|
||||
struct absaddr, const char **,
|
||||
bfd_vma *));
|
||||
static void dump_ia64_unwind PARAMS ((struct unw_aux_info *));
|
||||
static int slurp_ia64_unwind_table PARAMS ((FILE *file, struct unw_aux_info *,
|
||||
Elf32_Internal_Shdr *));
|
||||
|
||||
static void
|
||||
find_symbol_for_address (aux, addr, symname, offset)
|
||||
struct unw_aux_info *aux;
|
||||
struct absaddr addr;
|
||||
const char **symname;
|
||||
bfd_vma *offset;
|
||||
{
|
||||
bfd_vma dist = (bfd_vma) 0x100000;
|
||||
Elf_Internal_Sym *sym, *best = NULL;
|
||||
unsigned long i;
|
||||
|
||||
for (i = 0, sym = aux->symtab; i < aux->nsyms; ++i, ++sym)
|
||||
{
|
||||
if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
|
||||
&& sym->st_name != 0
|
||||
&& (addr.section == SHN_UNDEF || addr.section == sym->st_shndx)
|
||||
&& addr.offset >= sym->st_value
|
||||
&& addr.offset - sym->st_value < dist)
|
||||
{
|
||||
best = sym;
|
||||
dist = addr.offset - sym->st_value;
|
||||
if (!dist)
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (best)
|
||||
{
|
||||
*symname = (best->st_name >= aux->strtab_size
|
||||
? "<corrupt>" : aux->strtab + best->st_name);
|
||||
*offset = dist;
|
||||
return;
|
||||
}
|
||||
*symname = NULL;
|
||||
*offset = addr.offset;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_ia64_unwind (aux)
|
||||
struct unw_aux_info *aux;
|
||||
{
|
||||
bfd_vma addr_size;
|
||||
struct unw_table_entry * tp;
|
||||
int in_body;
|
||||
|
||||
addr_size = is_32bit_elf ? 4 : 8;
|
||||
|
||||
for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
|
||||
{
|
||||
bfd_vma stamp;
|
||||
bfd_vma offset;
|
||||
const unsigned char * dp;
|
||||
const unsigned char * head;
|
||||
const char * procname;
|
||||
|
||||
find_symbol_for_address (aux, tp->start, &procname, &offset);
|
||||
|
||||
fputs ("\n<", stdout);
|
||||
|
||||
if (procname)
|
||||
{
|
||||
fputs (procname, stdout);
|
||||
|
||||
if (offset)
|
||||
printf ("+%lx", (unsigned long) offset);
|
||||
}
|
||||
|
||||
fputs (">: [", stdout);
|
||||
print_vma (tp->start.offset, PREFIX_HEX);
|
||||
fputc ('-', stdout);
|
||||
print_vma (tp->end.offset, PREFIX_HEX);
|
||||
printf ("), info at +0x%lx\n",
|
||||
(unsigned long) (tp->info.offset - aux->seg_base));
|
||||
|
||||
head = aux->info + (tp->info.offset - aux->info_addr);
|
||||
stamp = BYTE_GET8 ((unsigned char *) head);
|
||||
|
||||
printf (" v%u, flags=0x%lx (%s%s ), len=%lu bytes\n",
|
||||
(unsigned) UNW_VER (stamp),
|
||||
(unsigned long) ((stamp & UNW_FLAG_MASK) >> 32),
|
||||
UNW_FLAG_EHANDLER (stamp) ? " ehandler" : "",
|
||||
UNW_FLAG_UHANDLER (stamp) ? " uhandler" : "",
|
||||
(unsigned long) (addr_size * UNW_LENGTH (stamp)));
|
||||
|
||||
if (UNW_VER (stamp) != 1)
|
||||
{
|
||||
printf ("\tUnknown version.\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
in_body = 0;
|
||||
for (dp = head + 8; dp < head + 8 + addr_size * UNW_LENGTH (stamp);)
|
||||
dp = unw_decode (dp, in_body, & in_body);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
slurp_ia64_unwind_table (file, aux, sec)
|
||||
FILE *file;
|
||||
struct unw_aux_info *aux;
|
||||
Elf32_Internal_Shdr *sec;
|
||||
{
|
||||
unsigned long size, addr_size, nrelas, i;
|
||||
Elf_Internal_Phdr *prog_hdrs, *seg;
|
||||
struct unw_table_entry *tep;
|
||||
Elf32_Internal_Shdr *relsec;
|
||||
Elf_Internal_Rela *rela, *rp;
|
||||
unsigned char *table, *tp;
|
||||
Elf_Internal_Sym *sym;
|
||||
const char *relname;
|
||||
int result;
|
||||
|
||||
addr_size = is_32bit_elf ? 4 : 8;
|
||||
|
||||
/* First, find the starting address of the segment that includes
|
||||
this section: */
|
||||
|
||||
if (elf_header.e_phnum)
|
||||
{
|
||||
prog_hdrs = (Elf_Internal_Phdr *)
|
||||
xmalloc (elf_header.e_phnum * sizeof (Elf_Internal_Phdr));
|
||||
|
||||
if (is_32bit_elf)
|
||||
result = get_32bit_program_headers (file, prog_hdrs);
|
||||
else
|
||||
result = get_64bit_program_headers (file, prog_hdrs);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
free (prog_hdrs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (seg = prog_hdrs; seg < prog_hdrs + elf_header.e_phnum; ++seg)
|
||||
{
|
||||
if (seg->p_type != PT_LOAD)
|
||||
continue;
|
||||
|
||||
if (sec->sh_addr >= seg->p_vaddr
|
||||
&& (sec->sh_addr + sec->sh_size <= seg->p_vaddr + seg->p_memsz))
|
||||
{
|
||||
aux->seg_base = seg->p_vaddr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (prog_hdrs);
|
||||
}
|
||||
|
||||
/* Second, build the unwind table from the contents of the unwind section: */
|
||||
size = sec->sh_size;
|
||||
GET_DATA_ALLOC (sec->sh_offset, size, table, char *, "unwind table");
|
||||
|
||||
tep = aux->table = xmalloc (size / (3 * addr_size) * sizeof (aux->table[0]));
|
||||
for (tp = table; tp < table + size; tp += 3 * addr_size, ++ tep)
|
||||
{
|
||||
tep->start.section = SHN_UNDEF;
|
||||
tep->end.section = SHN_UNDEF;
|
||||
tep->info.section = SHN_UNDEF;
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
tep->start.offset = byte_get ((unsigned char *) tp + 0, 4);
|
||||
tep->end.offset = byte_get ((unsigned char *) tp + 4, 4);
|
||||
tep->info.offset = byte_get ((unsigned char *) tp + 8, 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
tep->start.offset = BYTE_GET8 ((unsigned char *) tp + 0);
|
||||
tep->end.offset = BYTE_GET8 ((unsigned char *) tp + 8);
|
||||
tep->info.offset = BYTE_GET8 ((unsigned char *) tp + 16);
|
||||
}
|
||||
tep->start.offset += aux->seg_base;
|
||||
tep->end.offset += aux->seg_base;
|
||||
tep->info.offset += aux->seg_base;
|
||||
}
|
||||
free (table);
|
||||
|
||||
/* Third, apply any relocations to the unwind table: */
|
||||
|
||||
for (relsec = section_headers;
|
||||
relsec < section_headers + elf_header.e_shnum;
|
||||
++relsec)
|
||||
{
|
||||
if (relsec->sh_type != SHT_RELA
|
||||
|| section_headers + relsec->sh_info != sec)
|
||||
continue;
|
||||
|
||||
if (!slurp_rela_relocs (file, relsec->sh_offset, relsec->sh_size,
|
||||
& rela, & nrelas))
|
||||
return 0;
|
||||
|
||||
for (rp = rela; rp < rela + nrelas; ++rp)
|
||||
{
|
||||
if (is_32bit_elf)
|
||||
{
|
||||
relname = elf_ia64_reloc_type (ELF32_R_TYPE (rp->r_info));
|
||||
sym = aux->symtab + ELF32_R_SYM (rp->r_info);
|
||||
|
||||
if (ELF32_ST_TYPE (sym->st_info) != STT_SECTION)
|
||||
{
|
||||
warn (_("Skipping unexpected symbol type %u"),
|
||||
ELF32_ST_TYPE (sym->st_info));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
relname = elf_ia64_reloc_type (ELF64_R_TYPE (rp->r_info));
|
||||
sym = aux->symtab + ELF64_R_SYM (rp->r_info);
|
||||
|
||||
if (ELF64_ST_TYPE (sym->st_info) != STT_SECTION)
|
||||
{
|
||||
warn (_("Skipping unexpected symbol type %u"),
|
||||
ELF64_ST_TYPE (sym->st_info));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (strncmp (relname, "R_IA64_SEGREL", 13) != 0)
|
||||
{
|
||||
warn (_("Skipping unexpected relocation type %s"), relname);
|
||||
continue;
|
||||
}
|
||||
|
||||
i = rp->r_offset / (3 * addr_size);
|
||||
|
||||
switch (rp->r_offset/addr_size % 3)
|
||||
{
|
||||
case 0:
|
||||
aux->table[i].start.section = sym->st_shndx;
|
||||
aux->table[i].start.offset += rp->r_addend;
|
||||
break;
|
||||
case 1:
|
||||
aux->table[i].end.section = sym->st_shndx;
|
||||
aux->table[i].end.offset += rp->r_addend;
|
||||
break;
|
||||
case 2:
|
||||
aux->table[i].info.section = sym->st_shndx;
|
||||
aux->table[i].info.offset += rp->r_addend;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free (rela);
|
||||
}
|
||||
|
||||
aux->table_len = size / (3 * addr_size);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
process_unwind (file)
|
||||
FILE * file;
|
||||
{
|
||||
Elf32_Internal_Shdr *sec, *unwsec = NULL, *strsec;
|
||||
unsigned long i, addr_size;
|
||||
struct unw_aux_info aux;
|
||||
|
||||
memset (& aux, 0, sizeof (aux));
|
||||
|
||||
addr_size = is_32bit_elf ? 4 : 8;
|
||||
|
||||
if (!do_unwind)
|
||||
return 1;
|
||||
|
||||
for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
|
||||
{
|
||||
if (sec->sh_type == SHT_SYMTAB)
|
||||
{
|
||||
aux.nsyms = sec->sh_size / sec->sh_entsize;
|
||||
aux.symtab = GET_ELF_SYMBOLS (file, sec->sh_offset, aux.nsyms);
|
||||
|
||||
strsec = section_headers + sec->sh_link;
|
||||
aux.strtab_size = strsec->sh_size;
|
||||
GET_DATA_ALLOC (strsec->sh_offset, aux.strtab_size,
|
||||
(char *) aux.strtab, char *, "string table");
|
||||
}
|
||||
else if (sec->sh_type == SHT_IA_64_UNWIND)
|
||||
unwsec = sec;
|
||||
else if (strcmp (SECTION_NAME (sec), ELF_STRING_ia64_unwind_info) == 0)
|
||||
{
|
||||
aux.info_size = sec->sh_size;
|
||||
aux.info_addr = sec->sh_addr;
|
||||
GET_DATA_ALLOC (sec->sh_offset, aux.info_size, (char *) aux.info,
|
||||
char *, "unwind info");
|
||||
}
|
||||
}
|
||||
|
||||
if (unwsec)
|
||||
{
|
||||
printf (_("\nUnwind section "));
|
||||
|
||||
if (string_table == NULL)
|
||||
printf ("%d", unwsec->sh_name);
|
||||
else
|
||||
printf ("'%s'", SECTION_NAME (unwsec));
|
||||
|
||||
printf (_(" at offset 0x%lx contains %lu entries:\n"),
|
||||
unwsec->sh_offset, unwsec->sh_size / (3 * addr_size));
|
||||
|
||||
(void) slurp_ia64_unwind_table (file, & aux, unwsec);
|
||||
|
||||
if (aux.table_len > 0)
|
||||
dump_ia64_unwind (& aux);
|
||||
}
|
||||
else
|
||||
printf (_("\nThere are no unwind sections in this file.\n"));
|
||||
|
||||
if (aux.table)
|
||||
free ((char *) aux.table);
|
||||
if (aux.info)
|
||||
free ((char *) aux.info);
|
||||
if (aux.symtab)
|
||||
free (aux.symtab);
|
||||
if (aux.strtab)
|
||||
free ((char *) aux.strtab);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dynamic_segment_mips_val (entry)
|
||||
|
@ -7896,6 +8347,8 @@ process_file (file_name)
|
|||
|
||||
process_relocs (file);
|
||||
|
||||
process_unwind (file);
|
||||
|
||||
process_symbol_table (file);
|
||||
|
||||
process_syminfo (file);
|
||||
|
|
1111
binutils/unwind-ia64.c
Normal file
1111
binutils/unwind-ia64.c
Normal file
File diff suppressed because it is too large
Load diff
31
binutils/unwind-ia64.h
Normal file
31
binutils/unwind-ia64.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
/* unwind-ia64.h -- dump IA-64 unwind info.
|
||||
Copyright (c) 2000, 2001 Free Software Foundation, Inc.
|
||||
Contributed by David Mosberger-Tang <davidm@hpl.hp.com>
|
||||
|
||||
This file is part of GNU Binutils.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#include <elf/ia64.h>
|
||||
#include <ansidecl.h>
|
||||
|
||||
#define UNW_VER(x) ((x) >> 48)
|
||||
#define UNW_FLAG_MASK 0x0000ffff00000000
|
||||
#define UNW_FLAG_OSMASK 0x0000f00000000000
|
||||
#define UNW_FLAG_EHANDLER(x) ((x) & 0x0000000100000000L)
|
||||
#define UNW_FLAG_UHANDLER(x) ((x) & 0x0000000200000000L)
|
||||
#define UNW_LENGTH(x) ((x) & 0x00000000ffffffffL)
|
||||
|
||||
extern const unsigned char * unw_decode PARAMS ((const unsigned char *, int, void *));
|
Loading…
Reference in a new issue