IA-64 unwind dump support for "readelf"
David Mosberger
davidm@hpl.hp.com
Wed Feb 7 00:22:00 GMT 2001
Please consider the attached patch for inclusion in binutils. The
patch is relative to the Jan 31st version of the binutils CVS tree and
adds IA-64 unwind info dump support to the "readelf" program. Being
able to easily read the unwind information often proves valuable when
working with IA-64, particularly when learning the unwind format and
when debugging unwind-related problems. Here is a sample output:
$ readelf -u init/main.o
Unwind section '.IA_64.unwind' at offset 0x20a00 contains 16 entries:
:
<profile_setup>: [0x0-0xa0), info at +0x18
v1, flags=0x0 ( ), len=16 bytes
R2:prologue_gr(mask=[rp,ar.pfs],grsave=r34,rlen=5)
P7:pfs_when(t=0)
P7:mem_stack_f(t=1,size=16)
P7:rp_when(t=4)
R1:body(rlen=25)
B2:epilogue(t=2,ecount=0)
:
More features:
- the dump works even when there are relocation present in the
unwind section; this makes it possible to do dump the unwind
info of an object file (not just an executable)
- support both 64-bit and 32-bit ELF files
The only limitation that I know of is that "readelf -u" is currently
unable to process programs with more than one segment containing text
sections, but no normal UNIX/Linux program does that, so this
shouldn't be much of a real issue.
I should say that I would have preferred to put the entire IA-64
specific unwind dump support in separate object files, but that would
have required restructuring "readelf", so I refrained from doing so.
The FSF should have my copyright assignments on file, so I hope this
can be merged without too much trouble.
Thanks!
--david
diff -urN binutils-cvs-010131/binutils/ChangeLog binutils-cvs-010131-lia/binutils/ChangeLog
--- binutils-cvs-010131/binutils/ChangeLog Wed Jan 31 14:50:53 2001
+++ binutils-cvs-010131-lia/binutils/ChangeLog Sat Feb 3 00:52:25 2001
@@ -1,3 +1,16 @@
+2001-02-03 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-reader.c: New file.
+ * unwind-ia64.c: Ditto.
+
2001-01-31 Steve deRosier <sderosier@vari-lite.com>
* ieee.c (ieee_add_bb11): Don't check for backslashes
diff -urN binutils-cvs-010131/binutils/readelf.c binutils-cvs-010131-lia/binutils/readelf.c
--- binutils-cvs-010131/binutils/readelf.c Tue Jan 23 05:49:37 2001
+++ binutils-cvs-010131-lia/binutils/readelf.c Sat Feb 3 00:46:03 2001
@@ -104,6 +104,7 @@
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_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 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 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_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 @@
/* 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,144 +609,172 @@
}
}
-/* 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)
- FILE * file;
- unsigned long rel_offset;
- unsigned long rel_size;
- Elf_Internal_Sym * symtab;
- unsigned long nsyms;
- char * strtab;
- int is_rela;
+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;
{
- unsigned int i;
- Elf_Internal_Rel * rels;
- Elf_Internal_Rela * relas;
+ Elf_Internal_Rela *relas;
+ unsigned long nrelas;
+ unsigned int i;
+ if (is_32bit_elf)
+ {
+ Elf32_External_Rela * erelas;
- if (is_rela == UNKNOWN)
- is_rela = guess_is_rela (elf_header.e_machine);
+ GET_DATA_ALLOC (rel_offset, rel_size, erelas,
+ Elf32_External_Rela *, "relocs");
- if (is_rela)
- {
- if (is_32bit_elf)
- {
- Elf32_External_Rela * erelas;
+ nrelas = rel_size / sizeof (Elf32_External_Rela);
- GET_DATA_ALLOC (rel_offset, rel_size, erelas,
- Elf32_External_Rela *, "relocs");
+ relas = (Elf_Internal_Rela *)
+ malloc (nrelas * sizeof (Elf_Internal_Rela));
- rel_size = rel_size / sizeof (Elf32_External_Rela);
+ if (relas == NULL)
+ {
+ error(_("out of memory parsing relocs"));
+ return 0;
+ }
- relas = (Elf_Internal_Rela *)
- malloc (rel_size * sizeof (Elf_Internal_Rela));
+ 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);
+ }
- if (relas == NULL)
- {
- error(_("out of memory parsing relocs"));
- return 0;
- }
+ free (erelas);
+ }
+ else
+ {
+ Elf64_External_Rela * erelas;
- 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);
- }
+ GET_DATA_ALLOC (rel_offset, rel_size, erelas,
+ Elf64_External_Rela *, "relocs");
+
+ nrelas = rel_size / sizeof (Elf64_External_Rela);
- free (erelas);
+ relas = (Elf_Internal_Rela *)
+ malloc (nrelas * sizeof (Elf_Internal_Rela));
- rels = (Elf_Internal_Rel *) relas;
+ if (relas == NULL)
+ {
+ error(_("out of memory parsing relocs"));
+ return 0;
}
- else
+
+ for (i = 0; i < nrelas; i++)
{
- Elf64_External_Rela * erelas;
+ 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);
+ }
- GET_DATA_ALLOC (rel_offset, rel_size, erelas,
- Elf64_External_Rela *, "relocs");
+ free (erelas);
+ }
+ *relasp = relas;
+ *nrelasp = nrelas;
+ return 1;
+}
- rel_size = rel_size / sizeof (Elf64_External_Rela);
+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;
- relas = (Elf_Internal_Rela *)
- malloc (rel_size * sizeof (Elf_Internal_Rela));
+ if (is_32bit_elf)
+ {
+ Elf32_External_Rel * erels;
- if (relas == NULL)
- {
- error(_("out of memory parsing relocs"));
- return 0;
- }
+ GET_DATA_ALLOC (rel_offset, rel_size, erels,
+ Elf32_External_Rel *, "relocs");
- 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);
- }
+ nrels = rel_size / sizeof (Elf32_External_Rel);
- free (erelas);
+ rels = (Elf_Internal_Rel *) malloc (nrels * sizeof (Elf_Internal_Rel));
+
+ if (rels == NULL)
+ {
+ error(_("out of memory parsing relocs"));
+ return 0;
+ }
- rels = (Elf_Internal_Rel *) relas;
+ 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
{
- if (is_32bit_elf)
- {
- Elf32_External_Rel * erels;
+ Elf64_External_Rel * erels;
- GET_DATA_ALLOC (rel_offset, rel_size, erels,
- Elf32_External_Rel *, "relocs");
+ GET_DATA_ALLOC (rel_offset, rel_size, erels,
+ Elf64_External_Rel *, "relocs");
- rel_size = rel_size / sizeof (Elf32_External_Rel);
+ nrels = 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;
- }
+ rels = (Elf_Internal_Rel *) malloc (nrels * sizeof (Elf_Internal_Rel));
- 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
+ if (rels == NULL)
{
- Elf64_External_Rel * erels;
-
- GET_DATA_ALLOC (rel_offset, rel_size, erels,
- Elf64_External_Rel *, "relocs");
+ error(_("out of memory parsing relocs"));
+ return 0;
+ }
- rel_size = rel_size / sizeof (Elf64_External_Rel);
+ 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);
+ }
- rels = (Elf_Internal_Rel *)
- malloc (rel_size * sizeof (Elf_Internal_Rel));
+ free (erels);
+ }
+ *relsp = rels;
+ *nrelsp = nrels;
+ return 1;
+}
- if (rels == NULL)
- {
- error(_("out of memory parsing relocs"));
- return 0;
- }
+/* 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)
+ FILE * file;
+ unsigned long rel_offset;
+ unsigned long rel_size;
+ Elf_Internal_Sym * symtab;
+ unsigned long nsyms;
+ char * strtab;
+ int is_rela;
+{
+ unsigned int i;
+ Elf_Internal_Rel * rels;
+ Elf_Internal_Rela * relas;
- 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);
+ if (is_rela == UNKNOWN)
+ is_rela = guess_is_rela (elf_header.e_machine);
- relas = (Elf_Internal_Rela *) rels;
- }
+ if (is_rela)
+ {
+ if (!slurp_rela_relocs (file, rel_offset, rel_size, &relas, &rel_size))
+ return 0;
+ }
+ else
+ {
+ if (!slurp_rel_relocs (file, rel_offset, rel_size, &rels, &rel_size))
+ return 0;
}
if (is_rela)
@@ -1565,6 +1600,21 @@
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;
}
}
@@ -1618,6 +1668,21 @@
}
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 @@
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;
@@ -1750,6 +1818,20 @@
}
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 @@
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 @@
{"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 @@
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 @@
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 @@
case 'a':
do_syms ++;
do_reloc ++;
+ do_unwind ++;
do_dynamic ++;
do_header ++;
do_sections ++;
@@ -1963,6 +2051,9 @@
case 'r':
do_reloc ++;
break;
+ case 'u':
+ do_unwind ++;
+ break;
case 'h':
do_header ++;
break;
@@ -2065,7 +2156,7 @@
}
}
- 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,349 @@
return 1;
}
+#include "unwind-ia64.c"
+
+/* 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 stamp, addr_size, offset;
+ const unsigned char *dp, *head;
+ struct unw_table_entry *tp;
+ const char *procname;
+ int in_body;
+
+ addr_size = is_32bit_elf ? 4 : 8;
+
+ for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
+ {
+ 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" : "",
+ addr_size*(unsigned long)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;
+ }
+ }
+
+ 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));
+
+ 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)
@@ -7895,6 +8329,8 @@
process_dynamic_segment (file);
process_relocs (file);
+
+ process_unwind (file);
process_symbol_table (file);
diff -urN binutils-cvs-010131/binutils/unwind-ia64-reader.c binutils-cvs-010131-lia/binutils/unwind-ia64-reader.c
--- binutils-cvs-010131/binutils/unwind-ia64-reader.c Wed Dec 31 16:00:00 1969
+++ binutils-cvs-010131-lia/binutils/unwind-ia64-reader.c Sat Feb 3 00:44:06 2001
@@ -0,0 +1,665 @@
+/* unwind_decoder.c -- decoder for 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. */
+
+/*
+ * Generic IA-64 unwind info decoder.
+ *
+ * This file is used both by the Linux kernel and objdump. Please
+ * keep the two copies of this file in sync (modulo differences in the
+ * prototypes...).
+ *
+ * You need to customize the decoder by defining the following
+ * macros/constants before including this file:
+ *
+ * Types:
+ * unw_word Unsigned integer type with at least 64 bits
+ *
+ * Register names:
+ * UNW_REG_BSP
+ * UNW_REG_BSPSTORE
+ * UNW_REG_FPSR
+ * UNW_REG_LC
+ * UNW_REG_PFS
+ * UNW_REG_PR
+ * UNW_REG_RNAT
+ * UNW_REG_PSP
+ * UNW_REG_RP
+ * UNW_REG_UNAT
+ *
+ * Decoder action macros:
+ * UNW_DEC_BAD_CODE(code)
+ * UNW_DEC_ABI(fmt,abi,context,arg)
+ * UNW_DEC_BR_GR(fmt,brmask,gr,arg)
+ * UNW_DEC_BR_MEM(fmt,brmask,arg)
+ * UNW_DEC_COPY_STATE(fmt,label,arg)
+ * UNW_DEC_EPILOGUE(fmt,t,ecount,arg)
+ * UNW_DEC_FRGR_MEM(fmt,grmask,frmask,arg)
+ * UNW_DEC_FR_MEM(fmt,frmask,arg)
+ * UNW_DEC_GR_GR(fmt,grmask,gr,arg)
+ * UNW_DEC_GR_MEM(fmt,grmask,arg)
+ * UNW_DEC_LABEL_STATE(fmt,label,arg)
+ * UNW_DEC_MEM_STACK_F(fmt,t,size,arg)
+ * UNW_DEC_MEM_STACK_V(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_GR(fmt,r,arg)
+ * UNW_DEC_PRIUNAT_WHEN_GR(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_MEM(fmt,t,arg)
+ * UNW_DEC_PRIUNAT_WHEN_PSPREL(fmt,pspoff,arg)
+ * UNW_DEC_PRIUNAT_WHEN_SPREL(fmt,spoff,arg)
+ * UNW_DEC_PROLOGUE(fmt,body,rlen,arg)
+ * UNW_DEC_PROLOGUE_GR(fmt,rlen,mask,grsave,arg)
+ * UNW_DEC_REG_PSPREL(fmt,reg,pspoff,arg)
+ * UNW_DEC_REG_REG(fmt,src,dst,arg)
+ * UNW_DEC_REG_SPREL(fmt,reg,spoff,arg)
+ * UNW_DEC_REG_WHEN(fmt,reg,t,arg)
+ * UNW_DEC_RESTORE(fmt,t,abreg,arg)
+ * UNW_DEC_RESTORE_P(fmt,qp,t,abreg,arg)
+ * UNW_DEC_SPILL_BASE(fmt,pspoff,arg)
+ * UNW_DEC_SPILL_MASK(fmt,imaskp,arg)
+ * UNW_DEC_SPILL_PSPREL(fmt,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_PSPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ * UNW_DEC_SPILL_REG(fmt,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_REG_P(fmt,qp,t,abreg,x,ytreg,arg)
+ * UNW_DEC_SPILL_SPREL(fmt,t,abreg,spoff,arg)
+ * UNW_DEC_SPILL_SPREL_P(fmt,qp,t,abreg,pspoff,arg)
+ */
+
+static unw_word unw_decode_uleb128 PARAMS ((const unsigned char **));
+static const unsigned char *unw_decode_x1 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_x2 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_x3 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_x4 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_r1 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_r2 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_r3 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_p1 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_p2_p5 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_p6 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_p7_p10 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_b1 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_b2 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode_b3_x4 PARAMS ((const unsigned char *,
+ unsigned char, void *));
+static const unsigned char *unw_decode PARAMS ((const unsigned char *, int,
+ void *));
+
+static unw_word
+unw_decode_uleb128 (dpp)
+ const unsigned char **dpp;
+{
+ unsigned shift = 0;
+ unw_word byte, result = 0;
+ const unsigned char *bp = *dpp;
+
+ while (1)
+ {
+ byte = *bp++;
+ result |= (byte & 0x7f) << shift;
+ if ((byte & 0x80) == 0)
+ break;
+ shift += 7;
+ }
+ *dpp = bp;
+ return result;
+}
+
+static const unsigned char *
+unw_decode_x1 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code __attribute__((unused));
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char byte1, abreg;
+ unw_word t, off;
+
+ byte1 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL (X1, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL (X1, t, abreg, off, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_x2 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char byte1, byte2, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++;
+ byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ abreg = (byte1 & 0x7f);
+ ytreg = byte2;
+ x = (byte1 >> 7) & 1;
+ if ((byte1 & 0x80) == 0 && ytreg == 0)
+ UNW_DEC_RESTORE (X2, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG (X2, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_x3 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char byte1, byte2, abreg, qp;
+ unw_word t, off;
+
+ byte1 = *dp++;
+ byte2 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ off = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+
+ if (byte1 & 0x80)
+ UNW_DEC_SPILL_SPREL_P (X3, qp, t, abreg, off, arg);
+ else
+ UNW_DEC_SPILL_PSPREL_P (X3, qp, t, abreg, off, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_x4 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char byte1, byte2, byte3, qp, abreg, x, ytreg;
+ unw_word t;
+
+ byte1 = *dp++;
+ byte2 = *dp++;
+ byte3 = *dp++;
+ t = unw_decode_uleb128 (&dp);
+
+ qp = (byte1 & 0x3f);
+ abreg = (byte2 & 0x7f);
+ x = (byte2 >> 7) & 1;
+ ytreg = byte3;
+
+ if ((byte2 & 0x80) == 0 && byte3 == 0)
+ UNW_DEC_RESTORE_P (X4, qp, t, abreg, arg);
+ else
+ UNW_DEC_SPILL_REG_P (X4, qp, t, abreg, x, ytreg, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_r1 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ int body = (code & 0x20) != 0;
+ unw_word rlen;
+
+ rlen = (code & 0x1f);
+ UNW_DEC_PROLOGUE (R1, body, rlen, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_r2 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char byte1, mask, grsave;
+ unw_word rlen;
+
+ byte1 = *dp++;
+
+ mask = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ grsave = (byte1 & 0x7f);
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE_GR (R2, rlen, mask, grsave, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_r3 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unw_word rlen;
+
+ rlen = unw_decode_uleb128 (&dp);
+ UNW_DEC_PROLOGUE (R3, ((code & 0x3) == 1), rlen, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_p1 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char brmask = (code & 0x1f);
+
+ UNW_DEC_BR_MEM (P1, brmask, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_p2_p5 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ if ((code & 0x10) == 0)
+ {
+ unsigned char byte1 = *dp++;
+
+ UNW_DEC_BR_GR (P2, ((code & 0xf) << 1) | ((byte1 >> 7) & 1),
+ (byte1 & 0x7f), arg);
+ }
+ else if ((code & 0x08) == 0)
+ {
+ unsigned char byte1 = *dp++, r, dst;
+
+ r = ((code & 0x7) << 1) | ((byte1 >> 7) & 1);
+ dst = (byte1 & 0x7f);
+ switch (r)
+ {
+ case 0:
+ UNW_DEC_REG_GR (P3, UNW_REG_PSP, dst, arg);
+ break;
+ case 1:
+ UNW_DEC_REG_GR (P3, UNW_REG_RP, dst, arg);
+ break;
+ case 2:
+ UNW_DEC_REG_GR (P3, UNW_REG_PFS, dst, arg);
+ break;
+ case 3:
+ UNW_DEC_REG_GR (P3, UNW_REG_PR, dst, arg);
+ break;
+ case 4:
+ UNW_DEC_REG_GR (P3, UNW_REG_UNAT, dst, arg);
+ break;
+ case 5:
+ UNW_DEC_REG_GR (P3, UNW_REG_LC, dst, arg);
+ break;
+ case 6:
+ UNW_DEC_RP_BR (P3, dst, arg);
+ break;
+ case 7:
+ UNW_DEC_REG_GR (P3, UNW_REG_RNAT, dst, arg);
+ break;
+ case 8:
+ UNW_DEC_REG_GR (P3, UNW_REG_BSP, dst, arg);
+ break;
+ case 9:
+ UNW_DEC_REG_GR (P3, UNW_REG_BSPSTORE, dst, arg);
+ break;
+ case 10:
+ UNW_DEC_REG_GR (P3, UNW_REG_FPSR, dst, arg);
+ break;
+ case 11:
+ UNW_DEC_PRIUNAT_GR (P3, dst, arg);
+ break;
+ default:
+ UNW_DEC_BAD_CODE (r);
+ break;
+ }
+ }
+ else if ((code & 0x7) == 0)
+ UNW_DEC_SPILL_MASK (P4, dp, arg);
+ else if ((code & 0x7) == 1)
+ {
+ unw_word grmask, frmask, byte1, byte2, byte3;
+
+ byte1 = *dp++;
+ byte2 = *dp++;
+ byte3 = *dp++;
+ grmask = ((byte1 >> 4) & 0xf);
+ frmask = ((byte1 & 0xf) << 16) | (byte2 << 8) | byte3;
+ UNW_DEC_FRGR_MEM (P5, grmask, frmask, arg);
+ }
+ else
+ UNW_DEC_BAD_CODE (code);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_p6 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ int gregs = (code & 0x10) != 0;
+ unsigned char mask = (code & 0x0f);
+
+ if (gregs)
+ UNW_DEC_GR_MEM (P6, mask, arg);
+ else
+ UNW_DEC_FR_MEM (P6, mask, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_p7_p10 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unsigned char r, byte1, byte2;
+ unw_word t, size;
+
+ if ((code & 0x10) == 0)
+ {
+ r = (code & 0xf);
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 0:
+ size = unw_decode_uleb128 (&dp);
+ UNW_DEC_MEM_STACK_F (P7, t, size, arg);
+ break;
+
+ case 1:
+ UNW_DEC_MEM_STACK_V (P7, t, arg);
+ break;
+ case 2:
+ UNW_DEC_SPILL_BASE (P7, t, arg);
+ break;
+ case 3:
+ UNW_DEC_REG_SPREL (P7, UNW_REG_PSP, t, arg);
+ break;
+ case 4:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_RP, t, arg);
+ break;
+ case 5:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_RP, t, arg);
+ break;
+ case 6:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_PFS, t, arg);
+ break;
+ case 7:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_PFS, t, arg);
+ break;
+ case 8:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_PR, t, arg);
+ break;
+ case 9:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_PR, t, arg);
+ break;
+ case 10:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_LC, t, arg);
+ break;
+ case 11:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_LC, t, arg);
+ break;
+ case 12:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_UNAT, t, arg);
+ break;
+ case 13:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_UNAT, t, arg);
+ break;
+ case 14:
+ UNW_DEC_REG_WHEN (P7, UNW_REG_FPSR, t, arg);
+ break;
+ case 15:
+ UNW_DEC_REG_PSPREL (P7, UNW_REG_FPSR, t, arg);
+ break;
+ default:
+ UNW_DEC_BAD_CODE (r);
+ break;
+ }
+ }
+ else
+ {
+ switch (code & 0xf)
+ {
+ case 0x0: /* p8 */
+ {
+ r = *dp++;
+ t = unw_decode_uleb128 (&dp);
+ switch (r)
+ {
+ case 1:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_RP, t, arg);
+ break;
+ case 2:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_PFS, t, arg);
+ break;
+ case 3:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_PR, t, arg);
+ break;
+ case 4:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_LC, t, arg);
+ break;
+ case 5:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_UNAT, t, arg);
+ break;
+ case 6:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_FPSR, t, arg);
+ break;
+ case 7:
+ UNW_DEC_REG_WHEN (P8, UNW_REG_BSP, t, arg);
+ break;
+ case 8:
+ UNW_DEC_REG_PSPREL (P8, UNW_REG_BSP, t, arg);
+ break;
+ case 9:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_BSP, t, arg);
+ break;
+ case 10:
+ UNW_DEC_REG_WHEN (P8, UNW_REG_BSPSTORE, t, arg);
+ break;
+ case 11:
+ UNW_DEC_REG_PSPREL (P8, UNW_REG_BSPSTORE, t, arg);
+ break;
+ case 12:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_BSPSTORE, t, arg);
+ break;
+ case 13:
+ UNW_DEC_REG_WHEN (P8, UNW_REG_RNAT, t, arg);
+ break;
+ case 14:
+ UNW_DEC_REG_PSPREL (P8, UNW_REG_RNAT, t, arg);
+ break;
+ case 15:
+ UNW_DEC_REG_SPREL (P8, UNW_REG_RNAT, t, arg);
+ break;
+ case 16:
+ UNW_DEC_PRIUNAT_WHEN_GR (P8, t, arg);
+ break;
+ case 17:
+ UNW_DEC_PRIUNAT_PSPREL (P8, t, arg);
+ break;
+ case 18:
+ UNW_DEC_PRIUNAT_SPREL (P8, t, arg);
+ break;
+ case 19:
+ UNW_DEC_PRIUNAT_WHEN_MEM (P8, t, arg);
+ break;
+ default:
+ UNW_DEC_BAD_CODE (r);
+ break;
+ }
+ }
+ break;
+
+ case 0x1:
+ byte1 = *dp++;
+ byte2 = *dp++;
+ UNW_DEC_GR_GR (P9, (byte1 & 0xf), (byte2 & 0x7f), arg);
+ break;
+
+ case 0xf: /* p10 */
+ byte1 = *dp++;
+ byte2 = *dp++;
+ UNW_DEC_ABI (P10, byte1, byte2, arg);
+ break;
+
+ case 0x9:
+ return unw_decode_x1 (dp, code, arg);
+
+ case 0xa:
+ return unw_decode_x2 (dp, code, arg);
+
+ case 0xb:
+ return unw_decode_x3 (dp, code, arg);
+
+ case 0xc:
+ return unw_decode_x4 (dp, code, arg);
+
+ default:
+ UNW_DEC_BAD_CODE (code);
+ break;
+ }
+ }
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_b1 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unw_word label = (code & 0x1f);
+
+ if ((code & 0x20) != 0)
+ UNW_DEC_COPY_STATE (B1, label, arg);
+ else
+ UNW_DEC_LABEL_STATE (B1, label, arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_b2 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unw_word t;
+
+ t = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE (B2, t, (code & 0x1f), arg);
+ return dp;
+}
+
+static const unsigned char *
+unw_decode_b3_x4 (dp, code, arg)
+ const unsigned char *dp;
+ unsigned char code ATTRIBUTE_UNUSED;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unw_word t, ecount, label;
+
+ if ((code & 0x10) == 0)
+ {
+ t = unw_decode_uleb128 (&dp);
+ ecount = unw_decode_uleb128 (&dp);
+ UNW_DEC_EPILOGUE (B3, t, ecount, arg);
+ }
+ else if ((code & 0x07) == 0)
+ {
+ label = unw_decode_uleb128 (&dp);
+ if ((code & 0x08) != 0)
+ UNW_DEC_COPY_STATE (B4, label, arg);
+ else
+ UNW_DEC_LABEL_STATE (B4, label, arg);
+ }
+ else
+ switch (code & 0x7)
+ {
+ case 1:
+ return unw_decode_x1 (dp, code, arg);
+ case 2:
+ return unw_decode_x2 (dp, code, arg);
+ case 3:
+ return unw_decode_x3 (dp, code, arg);
+ case 4:
+ return unw_decode_x4 (dp, code, arg);
+ default:
+ UNW_DEC_BAD_CODE (code);
+ break;
+ }
+ return dp;
+}
+
+typedef const unsigned char *(*unw_decoder) PARAMS((const unsigned char *, unsigned char,
+ void *));
+
+static unw_decoder unw_decode_table[2][8] = {
+ /* prologue table: */
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_p1, /* 4 */
+ unw_decode_p2_p5,
+ unw_decode_p6,
+ unw_decode_p7_p10},
+ {
+ unw_decode_r1, /* 0 */
+ unw_decode_r1,
+ unw_decode_r2,
+ unw_decode_r3,
+ unw_decode_b1, /* 4 */
+ unw_decode_b1,
+ unw_decode_b2,
+ unw_decode_b3_x4}
+};
+
+/*
+ * Decode one descriptor and return address of next descriptor.
+ */
+static inline const unsigned char *
+unw_decode (dp, inside_body, arg)
+ const unsigned char *dp;
+ int inside_body;
+ void *arg ATTRIBUTE_UNUSED;
+{
+ unw_decoder decoder;
+ unsigned char code;
+
+ code = *dp++;
+ decoder = unw_decode_table[inside_body][code >> 5];
+ dp = (*decoder) (dp, code, arg);
+ return dp;
+}
diff -urN binutils-cvs-010131/binutils/unwind-ia64.c binutils-cvs-010131-lia/binutils/unwind-ia64.c
--- binutils-cvs-010131/binutils/unwind-ia64.c Wed Dec 31 16:00:00 1969
+++ binutils-cvs-010131-lia/binutils/unwind-ia64.c Sat Feb 3 00:41:52 2001
@@ -0,0 +1,413 @@
+/* readelf-unwind-ia64.c -- 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>
+
+#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)
+
+static bfd_vma unw_rlen = 0;
+
+static void
+unw_print_brmask (char *cp, unsigned char mask)
+{
+ char *sep = "";
+ int i;
+
+ for (i = 0; mask && (i < 5); ++i)
+ {
+ if (mask & 1)
+ {
+ cp += sprintf (cp, "%sb%u", sep, i + 1);
+ sep = ",";
+ }
+ mask >>= 1;
+ }
+ *cp = '\0';
+}
+
+static void
+unw_print_grmask (char *cp, unsigned char mask)
+{
+ char *sep = "";
+ int i;
+
+ *cp = '\0';
+ for (i = 0; i < 4; ++i)
+ {
+ if (mask & 1)
+ {
+ cp += sprintf (cp, "%sr%u", sep, i + 4);
+ sep = ",";
+ }
+ mask >>= 1;
+ }
+}
+
+static void
+unw_print_frmask (char *cp, unsigned long mask)
+{
+ char *sep = "";
+ int i;
+
+ *cp = '\0';
+ for (i = 0; i < 20; ++i)
+ {
+ if (mask & 1)
+ {
+ cp += sprintf (cp, "%sf%u", sep, (i < 4) ? (i + 2) : (i + 12));
+ sep = ",";
+ }
+ mask >>= 1;
+ }
+}
+
+static void
+unw_print_abreg (char *cp, unsigned char abreg)
+{
+ static const char *special_reg[16] =
+ {
+ "pr", "psp", "@priunat", "rp", "ar.bsp", "ar.bspstore", "ar.rnat",
+ "ar.unat", "ar.fpsr", "ar.pfs", "ar.lc",
+ "Unknown11", "Unknown12", "Unknown13", "Unknown14", "Unknown15"
+ };
+
+ switch ((abreg >> 5) & 0x3)
+ {
+ case 0: /* gr */
+ sprintf (cp, "r%u", (abreg & 0x1f));
+ break;
+
+ case 1: /* fr */
+ sprintf (cp, "f%u", (abreg & 0x1f));
+ break;
+
+ case 2: /* br */
+ sprintf (cp, "b%u", (abreg & 0x1f));
+ break;
+
+ case 3: /* special */
+ strcpy (cp, special_reg[abreg & 0xf]);
+ break;
+ }
+}
+
+static void
+unw_print_xyreg (char *cp, unsigned char x, unsigned char ytreg)
+{
+ switch ((x << 1) | ((ytreg >> 7) & 1))
+ {
+ case 0: /* gr */
+ sprintf (cp, "r%u", (ytreg & 0x1f));
+ break;
+
+ case 1: /* fr */
+ sprintf (cp, "f%u", (ytreg & 0x1f));
+ break;
+
+ case 2: /* br */
+ sprintf (cp, "b%u", (ytreg & 0x1f));
+ break;
+ }
+}
+
+#define UNW_REG_BSP "bsp"
+#define UNW_REG_BSPSTORE "bspstore"
+#define UNW_REG_FPSR "fpsr"
+#define UNW_REG_LC "lc"
+#define UNW_REG_PFS "pfs"
+#define UNW_REG_PR "pr"
+#define UNW_REG_PSP "psp"
+#define UNW_REG_RNAT "rnat"
+#define UNW_REG_RP "rp"
+#define UNW_REG_UNAT "unat"
+
+typedef bfd_vma unw_word;
+
+#define STR(x) #x
+
+#define UNW_DEC_BAD_CODE(code) \
+ printf ("Unknown code 0x%02x\n", code)
+
+#define UNW_DEC_PROLOGUE(fmt, body, rlen, arg) \
+do { \
+ unw_rlen = rlen; \
+ *(int *)arg = body; \
+ printf (" "STR(fmt)":%s(rlen=%lu)\n", \
+ body ? "body" : "prologue", (unsigned long) rlen); \
+} while (0)
+
+#define UNW_DEC_PROLOGUE_GR(fmt, rlen, mask, grsave, arg) \
+do { \
+ char regname[16], maskstr[64], *sep; \
+ \
+ unw_rlen = rlen; \
+ *(int *)arg = 0; \
+ \
+ maskstr[0] = '\0'; \
+ sep = ""; \
+ if (mask & 0x8) \
+ { \
+ strcat (maskstr, "rp"); \
+ sep = ","; \
+ } \
+ if (mask & 0x4) \
+ { \
+ strcat (maskstr, sep); \
+ strcat (maskstr, "ar.pfs"); \
+ sep = ","; \
+ } \
+ if (mask & 0x2) \
+ { \
+ strcat (maskstr, sep); \
+ strcat (maskstr, "psp"); \
+ sep = ","; \
+ } \
+ if (mask & 0x1) \
+ { \
+ strcat (maskstr, sep); \
+ strcat (maskstr, "pr"); \
+ } \
+ sprintf (regname, "r%u", grsave); \
+ printf (" "STR(fmt)":prologue_gr(mask=[%s],grsave=%s,rlen=%lu)\n", \
+ maskstr, regname, (unsigned long) rlen); \
+} while (0)
+
+#define UNW_DEC_FR_MEM(fmt, frmask, arg) \
+do { \
+ char frstr[200]; \
+ \
+ unw_print_frmask (frstr, frmask); \
+ printf ("\t"STR(fmt)":fr_mem(frmask=[%s])\n", frstr); \
+} while (0)
+
+#define UNW_DEC_GR_MEM(fmt, grmask, arg) \
+do { \
+ char grstr[200]; \
+ \
+ unw_print_grmask (grstr, grmask); \
+ printf ("\t"STR(fmt)":gr_mem(grmask=[%s])\n", grstr); \
+} while (0)
+
+#define UNW_DEC_FRGR_MEM(fmt, grmask, frmask, arg) \
+do { \
+ char frstr[200], grstr[20]; \
+ \
+ unw_print_grmask (grstr, grmask); \
+ unw_print_frmask (frstr, frmask); \
+ printf ("\t"STR(fmt)":frgr_mem(grmask=[%s],frmask=[%s])\n", grstr, frstr); \
+} while (0)
+
+#define UNW_DEC_BR_MEM(fmt, brmask, arg) \
+do { \
+ char brstr[20]; \
+ \
+ unw_print_brmask (brstr, brmask); \
+ printf ("\t"STR(fmt)":br_mem(brmask=[%s])\n", brstr); \
+} while (0)
+
+#define UNW_DEC_BR_GR(fmt, brmask, gr, arg) \
+do { \
+ char brstr[20]; \
+ \
+ unw_print_brmask (brstr, brmask); \
+ printf ("\t"STR(fmt)":br_gr(brmask=[%s],gr=r%u)\n", brstr, gr); \
+} while (0)
+
+#define UNW_DEC_REG_GR(fmt, src, dst, arg) \
+ printf ("\t"STR(fmt)":%s_gr(reg=r%u)\n", src, dst)
+
+#define UNW_DEC_RP_BR(fmt, dst, arg) \
+ printf ("\t"STR(fmt)":rp_br(reg=b%u)\n", dst)
+
+#define UNW_DEC_REG_WHEN(fmt, reg, t, arg) \
+ printf ("\t"STR(fmt)":%s_when(t=%lu)\n", reg, (unsigned long) t)
+
+#define UNW_DEC_REG_SPREL(fmt, reg, spoff, arg) \
+ printf ("\t"STR(fmt)":%s_sprel(spoff=0x%lx)\n", \
+ reg, 4*(unsigned long)spoff)
+
+#define UNW_DEC_REG_PSPREL(fmt, reg, pspoff, arg) \
+ printf ("\t"STR(fmt)":%s_psprel(pspoff=0x10-0x%lx)\n", \
+ reg, 4*(unsigned long)pspoff)
+
+#define UNW_DEC_GR_GR(fmt, grmask, gr, arg) \
+do { \
+ char grstr[20]; \
+ \
+ unw_print_grmask (grstr, grmask); \
+ printf ("\t"STR(fmt)":gr_gr(grmask=[%s],r%u)\n", grstr, gr); \
+} while (0)
+
+#define UNW_DEC_ABI(fmt, abi, context, arg) \
+do { \
+ static const char *abiname[] = \
+ { \
+ "@svr4", "@hpux", "@nt" \
+ }; \
+ char buf[20]; \
+ const char *abistr = buf; \
+ \
+ if (abi < 3) \
+ abistr = abiname[abi]; \
+ else \
+ sprintf (buf, "0x%x", abi); \
+ printf ("\t"STR(fmt)":unwabi(abi=%s,context=0x%02x)\n", \
+ abistr, context); \
+} while (0)
+
+#define UNW_DEC_PRIUNAT_GR(fmt, r, arg) \
+ printf ("\t"STR(fmt)":priunat_gr(reg=r%u)\n", r)
+
+#define UNW_DEC_PRIUNAT_WHEN_GR(fmt, t, arg) \
+ printf ("\t"STR(fmt)":priunat_when_gr(t=%lu)\n", (unsigned long) t)
+
+#define UNW_DEC_PRIUNAT_WHEN_MEM(fmt, t, arg) \
+ printf ("\t"STR(fmt)":priunat_when_mem(t=%lu)\n", (unsigned long) t)
+
+#define UNW_DEC_PRIUNAT_PSPREL(fmt, pspoff, arg) \
+ printf ("\t"STR(fmt)":priunat_psprel(pspoff=0x10-0x%lx)\n", \
+ 4*(unsigned long)pspoff)
+
+#define UNW_DEC_PRIUNAT_SPREL(fmt, spoff, arg) \
+ printf ("\t"STR(fmt)":priunat_sprel(spoff=0x%lx)\n", \
+ 4*(unsigned long)spoff)
+
+#define UNW_DEC_MEM_STACK_F(fmt, t, size, arg) \
+ printf ("\t"STR(fmt)":mem_stack_f(t=%lu,size=%lu)\n", \
+ (unsigned long) t, 16*(unsigned long)size)
+
+#define UNW_DEC_MEM_STACK_V(fmt, t, arg) \
+ printf ("\t"STR(fmt)":mem_stack_v(t=%lu)\n", (unsigned long) t)
+
+#define UNW_DEC_SPILL_BASE(fmt, pspoff, arg) \
+ printf ("\t"STR(fmt)":spill_base(pspoff=0x10-0x%lx)\n", \
+ 4*(unsigned long)pspoff)
+
+#define UNW_DEC_SPILL_MASK(fmt, dp, arg) \
+do { \
+ static const char *spill_type = "-frb"; \
+ unsigned const char *imaskp = dp; \
+ unsigned char mask = 0; \
+ bfd_vma insn = 0; \
+ \
+ printf ("\t"STR(fmt)":spill_mask(imask=["); \
+ for (insn = 0; insn < unw_rlen; ++insn) \
+ { \
+ if ((insn % 4) == 0) \
+ mask = *imaskp++; \
+ if (insn > 0 && (insn % 3) == 0) \
+ putchar (','); \
+ putchar (spill_type[(mask >> (2*(3-(insn & 0x3)))) & 0x3]); \
+ } \
+ printf ("])\n"); \
+ dp = imaskp; \
+} while (0)
+
+#define UNW_DEC_SPILL_SPREL(fmt, t, abreg, spoff, arg) \
+do { \
+ char regname[10]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt)":spill_sprel(reg=%s,t=%lu,spoff=0x%lx)\n", \
+ regname, (unsigned long) t, 4*(unsigned long)off); \
+} while (0)
+
+#define UNW_DEC_SPILL_PSPREL(fmt, t, abreg, pspoff, arg) \
+do { \
+ char regname[10]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt)":spill_psprel(reg=%s,t=%lu,pspoff=0x10-0x%lx)\n", \
+ regname, (unsigned long) t, 4*(unsigned long)pspoff); \
+} while (0)
+
+#define UNW_DEC_RESTORE(fmt, t, abreg, arg) \
+do { \
+ char regname[10]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt)":restore(t=%lu,reg=%s)\n", \
+ (unsigned long) t, regname); \
+} while (0)
+
+#define UNW_DEC_SPILL_REG(fmt, t, abreg, x, ytreg, arg) \
+do { \
+ char abregname[10], tregname[10]; \
+ \
+ unw_print_abreg (abregname, abreg); \
+ unw_print_xyreg (tregname, x, ytreg); \
+ printf ("\t"STR(fmt)":spill_reg(t=%lu,reg=%s,treg=%s)\n", \
+ (unsigned long) t, abregname, tregname); \
+} while (0)
+
+#define UNW_DEC_SPILL_SPREL_P(fmt, qp, t, abreg, spoff, arg) \
+do { \
+ char regname[20]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt)":spill_sprel_p(qp=p%u,t=%lu,reg=%s,spoff=0x%lx)\n", \
+ qp, (unsigned long) t, regname, 4*(unsigned long)spoff); \
+} while (0)
+
+#define UNW_DEC_SPILL_PSPREL_P(fmt, qp, t, abreg, pspoff, arg) \
+do { \
+ char regname[20]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt) \
+ ":spill_psprel_p(qp=p%u,t=%lu,reg=%s,pspoff=0x10-0x%lx)\n", \
+ qp, (unsigned long) t, regname, 4*(unsigned long)pspoff); \
+} while (0)
+
+#define UNW_DEC_RESTORE_P(fmt, qp, t, abreg, arg) \
+do { \
+ char regname[20]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ printf ("\t"STR(fmt)":restore_p(qp=p%u,t=%lu,reg=%s)\n", \
+ qp, (unsigned long) t, regname); \
+} while (0)
+
+#define UNW_DEC_SPILL_REG_P(fmt, qp, t, abreg, x, ytreg, arg) \
+do { \
+ char regname[20], tregname[20]; \
+ \
+ unw_print_abreg (regname, abreg); \
+ unw_print_xyreg (tregname, x, ytreg); \
+ printf ("\t"STR(fmt)":spill_reg_p(qp=p%u,t=%lu,reg=%s,treg=%s)\n", \
+ qp, (unsigned long) t, regname, tregname); \
+} while (0)
+
+#define UNW_DEC_LABEL_STATE(fmt, label, arg) \
+ printf ("\t"STR(fmt)":label_state(label=%lu)\n", (unsigned long) label)
+
+#define UNW_DEC_COPY_STATE(fmt, label, arg) \
+ printf ("\t"STR(fmt)":copy_state(label=%lu)\n", (unsigned long) label)
+
+#define UNW_DEC_EPILOGUE(fmt, t, ecount, arg) \
+ printf ("\t"STR(fmt)":epilogue(t=%lu,ecount=%lu)\n", \
+ (unsigned long) t, (unsigned long) ecount)
+
+#include "unwind-ia64-reader.c"
More information about the Binutils
mailing list