This is the mail archive of the binutils@sources.redhat.com mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[patch] Add support for PA-RISC unwind sections to readelf


This patch adds support to readelf for interpreting PA-RISC unwind
sections. Please apply if ok. :)

randolph

2004-11-02  Randolph Chung  <tausq@debian.org>

	* readelf.c (ia64_unw_aux_info, ia64_unw_table_entry): Rename from
	unw_aux_info and unw_table_entry.
	(find_symbol_for_address): Pass symtab and strtab info explicitly.
	(dump_ia64_unwind): Rename unw_{aux_info,table_entry} with ia64_ prefix.
	(slurp_ia64_unwind_table): Likewise.
	(ia64_process_unwind): Rename from old process_unwind.
	(hppa_unw_aux_info): New.
	(dump_hppa_unwind): New.
	(slurp_hppa_unwind_table): New.
	(hppa_process_unwind): New.
	(process_unwind): Factor out common unwinding checks; dispatch to 
	unwind handler based on machine type.

Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.230.4.1
diff -u -p -r1.230.4.1 readelf.c
--- binutils/readelf.c	9 Apr 2004 18:28:06 -0000	1.230.4.1
+++ binutils/readelf.c	2 Nov 2004 22:00:03 -0000
@@ -3824,6 +3824,8 @@ process_relocs (FILE *file)
   return 1;
 }
 
+/* Process the unwind section.  */
+
 #include "unwind-ia64.h"
 
 /* An absolute address consists of a section and an offset.  If the
@@ -3836,9 +3838,9 @@ struct absaddr
     bfd_vma offset;
   };
 
-struct unw_aux_info
+struct ia64_unw_aux_info
   {
-    struct unw_table_entry
+    struct ia64_unw_table_entry
       {
 	struct absaddr start;
 	struct absaddr end;
@@ -3857,7 +3859,10 @@ struct unw_aux_info
   };
 
 static void
-find_symbol_for_address (struct unw_aux_info *aux,
+find_symbol_for_address (Elf_Internal_Sym *symtab,
+		         unsigned long nsyms,
+			 const char *strtab,
+			 unsigned long strtab_size,
 			 struct absaddr addr,
 			 const char **symname,
 			 bfd_vma *offset)
@@ -3866,7 +3871,7 @@ find_symbol_for_address (struct unw_aux_
   Elf_Internal_Sym *sym, *best = NULL;
   unsigned long i;
 
-  for (i = 0, sym = aux->symtab; i < aux->nsyms; ++i, ++sym)
+  for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
     {
       if (ELF_ST_TYPE (sym->st_info) == STT_FUNC
 	  && sym->st_name != 0
@@ -3882,8 +3887,8 @@ find_symbol_for_address (struct unw_aux_
     }
   if (best)
     {
-      *symname = (best->st_name >= aux->strtab_size
-		  ? "<corrupt>" : aux->strtab + best->st_name);
+      *symname = (best->st_name >= strtab_size
+		  ? "<corrupt>" : strtab + best->st_name);
       *offset = dist;
       return;
     }
@@ -3892,10 +3897,10 @@ find_symbol_for_address (struct unw_aux_
 }
 
 static void
-dump_ia64_unwind (struct unw_aux_info *aux)
+dump_ia64_unwind (struct ia64_unw_aux_info *aux)
 {
   bfd_vma addr_size;
-  struct unw_table_entry *tp;
+  struct ia64_unw_table_entry *tp;
   int in_body;
 
   addr_size = is_32bit_elf ? 4 : 8;
@@ -3908,7 +3913,8 @@ dump_ia64_unwind (struct unw_aux_info *a
       const unsigned char *head;
       const char *procname;
 
-      find_symbol_for_address (aux, tp->start, &procname, &offset);
+      find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab, 
+			       aux->strtab_size, tp->start, &procname, &offset);
 
       fputs ("\n<", stdout);
 
@@ -3951,12 +3957,12 @@ dump_ia64_unwind (struct unw_aux_info *a
 
 static int
 slurp_ia64_unwind_table (FILE *file,
-			 struct unw_aux_info *aux,
+			 struct ia64_unw_aux_info *aux,
 			 Elf_Internal_Shdr *sec)
 {
   unsigned long size, addr_size, nrelas, i;
   Elf_Internal_Phdr *seg;
-  struct unw_table_entry *tep;
+  struct ia64_unw_table_entry *tep;
   Elf_Internal_Shdr *relsec;
   Elf_Internal_Rela *rela, *rp;
   unsigned char *table, *tp;
@@ -4095,20 +4101,11 @@ slurp_ia64_unwind_table (FILE *file,
 }
 
 static int
-process_unwind (FILE *file)
+ia64_process_unwind (FILE *file)
 {
   Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
   unsigned long i, addr_size, unwcount = 0, unwstart = 0;
-  struct unw_aux_info aux;
-
-  if (!do_unwind)
-    return 1;
-
-  if (elf_header.e_machine != EM_IA_64)
-    {
-      printf (_("\nThere are no unwind sections in this file.\n"));
-      return 1;
-    }
+  struct ia64_unw_aux_info aux;
 
   memset (& aux, 0, sizeof (aux));
 
@@ -4229,6 +4226,376 @@ process_unwind (FILE *file)
   return 1;
 }
 
+struct hppa_unw_aux_info
+  {
+    struct hppa_unw_table_entry
+      {
+	struct absaddr start;
+	struct absaddr end;
+        unsigned int Cannot_unwind:1;	/* 0 */
+        unsigned int Millicode:1;	/* 1 */
+        unsigned int Millicode_save_sr0:1;	/* 2 */
+        unsigned int Region_description:2;	/* 3..4 */
+        unsigned int reserved1:1;	/* 5 */
+        unsigned int Entry_SR:1;	/* 6 */
+        unsigned int Entry_FR:4;	/* number saved *//* 7..10 */
+        unsigned int Entry_GR:5;	/* number saved *//* 11..15 */
+        unsigned int Args_stored:1;	/* 16 */
+        unsigned int Variable_Frame:1;	/* 17 */
+        unsigned int Separate_Package_Body:1;	/* 18 */
+        unsigned int Frame_Extension_Millicode:1;	/* 19 */
+        unsigned int Stack_Overflow_Check:1;	/* 20 */
+        unsigned int Two_Instruction_SP_Increment:1;	/* 21 */
+        unsigned int Ada_Region:1;	/* 22 */
+        unsigned int cxx_info:1;	/* 23 */
+        unsigned int cxx_try_catch:1;	/* 24 */
+        unsigned int sched_entry_seq:1;	/* 25 */
+        unsigned int reserved2:1;	/* 26 */
+        unsigned int Save_SP:1;	/* 27 */
+        unsigned int Save_RP:1;	/* 28 */
+        unsigned int Save_MRP_in_frame:1;	/* 29 */
+        unsigned int extn_ptr_defined:1;	/* 30 */
+        unsigned int Cleanup_defined:1;	/* 31 */
+
+        unsigned int MPE_XL_interrupt_marker:1;	/* 0 */
+        unsigned int HP_UX_interrupt_marker:1;	/* 1 */
+        unsigned int Large_frame:1;	/* 2 */
+        unsigned int Pseudo_SP_Set:1;	/* 3 */
+        unsigned int reserved4:1;	/* 4 */
+        unsigned int Total_frame_size:27;	/* 5..31 */
+      }
+    *table;			/* Unwind table.  */
+    unsigned long table_len;	/* Length of unwind table.  */
+    bfd_vma seg_base;		/* Starting address of segment.  */
+    Elf_Internal_Sym *symtab;	/* The symbol table.  */
+    unsigned long nsyms;	/* Number of symbols.  */
+    char *strtab;		/* The string table.  */
+    unsigned long strtab_size;	/* Size of string table.  */
+  };
+
+static void
+dump_hppa_unwind (struct hppa_unw_aux_info *aux)
+{
+  bfd_vma addr_size;
+  struct hppa_unw_table_entry *tp;
+
+  addr_size = is_32bit_elf ? 4 : 8;
+  for (tp = aux->table; tp < aux->table + aux->table_len; ++tp)
+    {
+      bfd_vma offset;
+      const char *procname;
+
+      find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+			       aux->strtab_size, 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 ("]\n\t");
+
+#define PF(_m) if (tp->_m) printf(#_m " ");
+#define PV(_m) if (tp->_m) printf(#_m "=%d ", tp->_m);
+      PF(Cannot_unwind);
+      PF(Millicode);
+      PF(Millicode_save_sr0);
+      /* PV(Region_description); */
+      PF(Entry_SR);
+      PV(Entry_FR);
+      PV(Entry_GR);
+      PF(Args_stored);
+      PF(Variable_Frame);
+      PF(Separate_Package_Body);
+      PF(Frame_Extension_Millicode);
+      PF(Stack_Overflow_Check);
+      PF(Two_Instruction_SP_Increment);
+      PF(Ada_Region);
+      PF(cxx_info);
+      PF(cxx_try_catch);
+      PF(sched_entry_seq);
+      PF(Save_SP);
+      PF(Save_RP);
+      PF(Save_MRP_in_frame);
+      PF(extn_ptr_defined);
+      PF(Cleanup_defined);
+      PF(MPE_XL_interrupt_marker);
+      PF(HP_UX_interrupt_marker);
+      PF(Large_frame);
+      PF(Pseudo_SP_Set);
+      PV(Total_frame_size);
+#undef PF
+#undef PV
+    }
+
+  printf("\n");
+}
+
+static int
+slurp_hppa_unwind_table (FILE *file, 
+			 struct hppa_unw_aux_info *aux,
+			 Elf_Internal_Shdr *sec)
+{
+  unsigned long size, unw_ent_size, addr_size, nrelas, i;
+  Elf_Internal_Phdr *seg;
+  struct hppa_unw_table_entry *tep;
+  Elf_Internal_Shdr *relsec;
+  Elf_Internal_Rela *rela, *rp;
+  unsigned char *table, *tp;
+  Elf_Internal_Sym *sym;
+  const char *relname;
+
+  addr_size = is_32bit_elf ? 4 : 8;
+
+  /* First, find the starting address of the segment that includes
+     this section: */
+
+  if (elf_header.e_phnum)
+    {
+      if (! get_program_headers (file))
+	  return 0;
+
+      for (seg = program_headers;
+	   seg < program_headers + 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;
+	    }
+	}
+    }
+
+  /* Second, build the unwind table from the contents of the unwind section:  */
+  size = sec->sh_size;
+  table = get_data (NULL, file, sec->sh_offset, size, _("unwind table"));
+  if (!table)
+    return 0;
+
+  unw_ent_size = 2 * addr_size + 8;
+
+  tep = aux->table = xmalloc (size / unw_ent_size * sizeof (aux->table[0]));
+
+  for (tp = table; tp < table + size; tp += (2 * addr_size + 8), ++tep)
+    {
+      unsigned int tmp1, tmp2;
+
+      tep->start.section = SHN_UNDEF;
+      tep->end.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);
+	  tmp1 = byte_get ((unsigned char *) tp + 8, 4);
+	  tmp2 = byte_get ((unsigned char *) tp + 12, 4);
+	}
+      else
+	{
+	  tep->start.offset = BYTE_GET8 ((unsigned char *) tp + 0);
+	  tep->end.offset = BYTE_GET8 ((unsigned char *) tp + 8);
+	  tmp1 = byte_get ((unsigned char *) tp + 16, 4);
+	  tmp2 = byte_get ((unsigned char *) tp + 20, 4);
+	}
+
+      tep->Cannot_unwind = (tmp1 >> 31) & 0x1;
+      tep->Millicode = (tmp1 >> 30) & 0x1;
+      tep->Millicode_save_sr0 = (tmp1 >> 29) & 0x1;
+      tep->Region_description = (tmp1 >> 27) & 0x3;
+      tep->reserved1 = (tmp1 >> 26) & 0x1;
+      tep->Entry_SR = (tmp1 >> 25) & 0x1;
+      tep->Entry_FR = (tmp1 >> 21) & 0xf;
+      tep->Entry_GR = (tmp1 >> 16) & 0x1f;
+      tep->Args_stored = (tmp1 >> 15) & 0x1;
+      tep->Variable_Frame = (tmp1 >> 14) & 0x1;
+      tep->Separate_Package_Body = (tmp1 >> 13) & 0x1;
+      tep->Frame_Extension_Millicode = (tmp1 >> 12) & 0x1;
+      tep->Stack_Overflow_Check = (tmp1 >> 11) & 0x1;
+      tep->Two_Instruction_SP_Increment = (tmp1 >> 10) & 0x1;
+      tep->Ada_Region = (tmp1 >> 9) & 0x1;
+      tep->cxx_info = (tmp1 >> 8) & 0x1;
+      tep->cxx_try_catch = (tmp1 >> 7) & 0x1;
+      tep->sched_entry_seq = (tmp1 >> 6) & 0x1;
+      tep->reserved2 = (tmp1 >> 5) & 0x1;
+      tep->Save_SP = (tmp1 >> 4) & 0x1;
+      tep->Save_RP = (tmp1 >> 3) & 0x1;
+      tep->Save_MRP_in_frame = (tmp1 >> 2) & 0x1;
+      tep->extn_ptr_defined = (tmp1 >> 1) & 0x1;
+      tep->Cleanup_defined = tmp1 & 0x1;
+
+      tep->MPE_XL_interrupt_marker = (tmp2 >> 31) & 0x1;
+      tep->HP_UX_interrupt_marker = (tmp2 >> 30) & 0x1;
+      tep->Large_frame = (tmp2 >> 29) & 0x1;
+      tep->Pseudo_SP_Set = (tmp2 >> 28) & 0x1;
+      tep->reserved4 = (tmp2 >> 27) & 0x1;
+      tep->Total_frame_size = tmp2 & 0x7ffffff;
+
+      tep->start.offset += aux->seg_base;
+      tep->end.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_HEADER (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_hppa_reloc_type (ELF32_R_TYPE (rp->r_info));
+	      sym = aux->symtab + ELF32_R_SYM (rp->r_info);
+	    }
+	  else
+	    {
+	      relname = elf_hppa_reloc_type (ELF64_R_TYPE (rp->r_info));
+	      sym = aux->symtab + ELF64_R_SYM (rp->r_info);
+	    }
+
+	  /* R_PARISC_SEGREL32 or R_PARISC_SEGREL64 */
+	  if (strncmp (relname, "R_PARISC_SEGREL", 15) != 0)
+	    {
+	      warn (_("Skipping unexpected relocation type %s\n"), relname);
+	      continue;
+	    }
+
+	  i = rp->r_offset / unw_ent_size;
+
+	  switch ((rp->r_offset % unw_ent_size) / addr_size)
+	    {
+	    case 0:
+	      aux->table[i].start.section = sym->st_shndx;
+	      aux->table[i].start.offset += sym->st_value + rp->r_addend;
+	      break;
+	    case 1:
+	      aux->table[i].end.section   = sym->st_shndx;
+	      aux->table[i].end.offset   += sym->st_value + rp->r_addend;
+	      break;
+	    default:
+	      break;
+	    }
+	}
+
+      free (rela);
+    }
+
+  aux->table_len = size / unw_ent_size;
+
+  return 1;
+}
+
+static int 
+hppa_process_unwind (FILE *file)
+{
+  Elf_Internal_Shdr *sec, *unwsec = NULL, *strsec;
+  unsigned long i, addr_size;
+  struct hppa_unw_aux_info aux;
+
+  memset (& aux, 0, sizeof (aux));
+
+  assert (string_table != NULL);
+  addr_size = is_32bit_elf ? 4 : 8;
+
+  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);
+
+	  strsec = SECTION_HEADER (sec->sh_link);
+	  aux.strtab_size = strsec->sh_size;
+	  aux.strtab = get_data (NULL, file, strsec->sh_offset,
+				 aux.strtab_size, _("string table"));
+	}
+      else if (strcmp (SECTION_NAME(sec), ".PARISC.unwind") == 0)
+	unwsec = sec;
+    }
+
+  if (!unwsec)
+    printf (_("\nThere are no unwind sections in this file.\n"));
+
+  for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+    {
+      if (strcmp (SECTION_NAME(sec), ".PARISC.unwind") == 0)
+	{
+		
+	  printf (_("\nUnwind section "));
+	  printf (_("'%s'"), SECTION_NAME (sec));
+
+	  printf (_(" at offset 0x%lx contains %lu entries:\n"),
+		  (unsigned long) sec->sh_offset,
+		  (unsigned long) (sec->sh_size / (2 * addr_size + 8)));
+	  
+          slurp_hppa_unwind_table (file, &aux, sec);
+	  if (aux.table_len > 0)
+	    dump_hppa_unwind (&aux);
+
+	  if (aux.table)
+	    free ((char *) aux.table);
+	  aux.table = NULL;
+	}
+    }
+
+  if (aux.symtab)
+    free (aux.symtab);
+  if (aux.strtab)
+    free ((char *) aux.strtab);
+
+  return 1;
+}
+
+static int
+process_unwind (FILE *file)
+{
+  struct unwind_handler {
+    int machtype;
+    int (*handler)(FILE *file);
+  } handlers[] = {
+    { EM_IA_64, ia64_process_unwind },
+    { EM_PARISC, hppa_process_unwind },
+    { 0, 0 }
+  };
+  int i;
+
+  if (!do_unwind)
+    return 1;
+
+
+  for (i = 0; handlers[i].handler != NULL; i++)
+    {
+      if (elf_header.e_machine == handlers[i].machtype)
+      return handlers[i].handler(file);
+    }
+
+  printf (_("\nThere are no unwind sections in this file.\n"));
+  return 1;
+}
+
 static void
 dynamic_segment_mips_val (Elf_Internal_Dyn *entry)
 {
-- 
Randolph Chung
Debian GNU/Linux Developer, hppa/ia64 ports
http://www.tausq.org/


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]