Add -u option toi readelf to display unwind info.

Add support to display unwind info for IA64 binaries.
This commit is contained in:
Nick Clifton 2001-02-07 19:41:03 +00:00
parent a6da1910ac
commit 4d6ed7c8ce
7 changed files with 2130 additions and 489 deletions

View file

@ -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> 2001-02-04 Philip Blundell <philb@gnu.org>
* configure.in (OBJDUMP_DEFS): Match `arm*-*', not just `arm-*'. * configure.in (OBJDUMP_DEFS): Match `arm*-*', not just `arm-*'.

View file

@ -161,7 +161,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
strings_SOURCES = strings.c $(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) readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS) strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)

View file

@ -253,7 +253,7 @@ objcopy_SOURCES = objcopy.c not-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS)
strings_SOURCES = strings.c $(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) readelf_LDADD = $(INTLLIBS) $(LIBIBERTY)
strip_new_SOURCES = objcopy.c is-strip.c rename.c $(WRITE_DEBUG_SRCS) $(BULIBS) 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_LDADD = $(LDADD)
addr2line_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a addr2line_DEPENDENCIES = ../bfd/libbfd.la ../libiberty/libiberty.a
addr2line_LDFLAGS = addr2line_LDFLAGS =
readelf_OBJECTS = readelf.$(OBJEXT) version.$(OBJEXT) readelf_OBJECTS = readelf.$(OBJEXT) version.$(OBJEXT) \
unwind-ia64.$(OBJEXT)
readelf_DEPENDENCIES = ../libiberty/libiberty.a readelf_DEPENDENCIES = ../libiberty/libiberty.a
readelf_LDFLAGS = readelf_LDFLAGS =
nm_new_OBJECTS = nm.$(OBJEXT) bucomm.$(OBJEXT) version.$(OBJEXT) \ nm_new_OBJECTS = nm.$(OBJEXT) bucomm.$(OBJEXT) version.$(OBJEXT) \

File diff suppressed because it is too large Load diff

View file

@ -104,6 +104,7 @@ int do_syms;
int do_reloc; int do_reloc;
int do_sections; int do_sections;
int do_segments; int do_segments;
int do_unwind;
int do_using_dynamic; int do_using_dynamic;
int do_header; int do_header;
int do_dump; 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_sparc64_dynamic_type PARAMS ((unsigned long));
static const char * get_parisc_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 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 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_file_type PARAMS ((unsigned));
static char * get_machine_name 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 char * get_machine_flags PARAMS ((unsigned, unsigned));
static const char * get_mips_segment_type PARAMS ((unsigned long)); static const char * get_mips_segment_type PARAMS ((unsigned long));
static const char * get_parisc_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_segment_type PARAMS ((unsigned long));
static const char * get_mips_section_type_name PARAMS ((unsigned int)); 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_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_section_type_name PARAMS ((unsigned int));
static const char * get_symbol_binding PARAMS ((unsigned int)); static const char * get_symbol_binding PARAMS ((unsigned int));
static const char * get_symbol_type 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_file_header PARAMS ((void));
static int process_program_headers PARAMS ((FILE *)); static int process_program_headers PARAMS ((FILE *));
static int process_section_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_mips_val PARAMS ((Elf_Internal_Dyn *));
static void dynamic_segment_parisc_val PARAMS ((Elf_Internal_Dyn *)); static void dynamic_segment_parisc_val PARAMS ((Elf_Internal_Dyn *));
static int process_dynamic_segment PARAMS ((FILE *)); 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 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_32bit_elf_symbols PARAMS ((FILE *, unsigned long, unsigned long));
static Elf_Internal_Sym * get_64bit_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_dynamic_data PARAMS ((FILE *, unsigned int));
static int get_32bit_dynamic_segment PARAMS ((FILE *)); static int get_32bit_dynamic_segment PARAMS ((FILE *));
static int get_64bit_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 /* 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 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 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 If, however, BFD64 is not defined, then we must assume that the
internal data structure only has 4 byte wide fields that are 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 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. */ /* Display the contents of the relocation data found at the specified offset. */
static int static int
dump_relocations (file, rel_offset, rel_size, symtab, nsyms, strtab, is_rela) 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_rela)
{ {
if (is_32bit_elf) if (!slurp_rela_relocs (file, rel_offset, rel_size, &relas, &rel_size))
{ return 0;
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;
}
} }
else else
{ {
if (is_32bit_elf) if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size))
{ return 0;
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 (is_rela) if (is_rela)
@ -1565,6 +1600,21 @@ get_machine_flags (e_flags, e_machine)
if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS) if ((e_flags & EF_PICOJAVA_GNUCALLS) == EF_PICOJAVA_GNUCALLS)
strcat (buf, ", gnu calling convention"); strcat (buf, ", gnu calling convention");
break; 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; 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 * static const char *
get_segment_type (p_type) get_segment_type (p_type)
unsigned long p_type; unsigned long p_type;
@ -1647,6 +1712,9 @@ get_segment_type (p_type)
case EM_PARISC: case EM_PARISC:
result = get_parisc_segment_type (p_type); result = get_parisc_segment_type (p_type);
break; break;
case EM_IA_64:
result = get_ia64_segment_type (p_type);
break;
default: default:
result = NULL; result = NULL;
break; break;
@ -1749,6 +1817,20 @@ get_parisc_section_type_name (sh_type)
return NULL; 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 * static const char *
get_section_type_name (sh_type) get_section_type_name (sh_type)
unsigned int sh_type; unsigned int sh_type;
@ -1796,6 +1878,9 @@ get_section_type_name (sh_type)
case EM_PARISC: case EM_PARISC:
result = get_parisc_section_type_name (sh_type); result = get_parisc_section_type_name (sh_type);
break; break;
case EM_IA_64:
result = get_ia64_section_type_name (sh_type);
break;
default: default:
result = NULL; result = NULL;
break; break;
@ -1837,6 +1922,7 @@ struct option options [] =
{"use-dynamic", no_argument, 0, 'D'}, {"use-dynamic", no_argument, 0, 'D'},
{"hex-dump", required_argument, 0, 'x'}, {"hex-dump", required_argument, 0, 'x'},
{"debug-dump", optional_argument, 0, 'w'}, {"debug-dump", optional_argument, 0, 'w'},
{"unwind", no_argument, 0, 'u'},
#ifdef SUPPORT_DISASSEMBLY #ifdef SUPPORT_DISASSEMBLY
{"instruction-dump", required_argument, 0, 'i'}, {"instruction-dump", required_argument, 0, 'i'},
#endif #endif
@ -1861,6 +1947,7 @@ usage ()
fprintf (stdout, _(" -s or --syms or --symbols Display the symbol table\n")); 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, _(" -n or --notes Display the core notes (if present)\n"));
fprintf (stdout, _(" -r or --relocs Display the relocations (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, _(" -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, _(" -V or --version-info Display the version sections (if present)\n"));
fprintf (stdout, _(" -A or --arch-specific Display architecture specific information (if any).\n")); fprintf (stdout, _(" -A or --arch-specific Display architecture specific information (if any).\n"));
@ -1923,7 +2010,7 @@ parse_args (argc, argv)
usage (); usage ();
while ((c = getopt_long while ((c = getopt_long
(argc, argv, "ersahnldSDAIw::x:i:vV", options, NULL)) != EOF) (argc, argv, "ersuahnldSDAIw::x:i:vV", options, NULL)) != EOF)
{ {
char * cp; char * cp;
int section; int section;
@ -1940,6 +2027,7 @@ parse_args (argc, argv)
case 'a': case 'a':
do_syms ++; do_syms ++;
do_reloc ++; do_reloc ++;
do_unwind ++;
do_dynamic ++; do_dynamic ++;
do_header ++; do_header ++;
do_sections ++; do_sections ++;
@ -1963,6 +2051,9 @@ parse_args (argc, argv)
case 'r': case 'r':
do_reloc ++; do_reloc ++;
break; break;
case 'u':
do_unwind ++;
break;
case 'h': case 'h':
do_header ++; do_header ++;
break; 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_segments && !do_header && !do_dump && !do_version
&& !do_histogram && !do_debugging && !do_arch && !do_notes) && !do_histogram && !do_debugging && !do_arch && !do_notes)
usage (); usage ();
@ -2976,6 +3067,366 @@ process_relocs (file)
return 1; 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 static void
dynamic_segment_mips_val (entry) dynamic_segment_mips_val (entry)
@ -7896,6 +8347,8 @@ process_file (file_name)
process_relocs (file); process_relocs (file);
process_unwind (file);
process_symbol_table (file); process_symbol_table (file);
process_syminfo (file); process_syminfo (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
View 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 *));