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