This is the mail archive of the binutils@sourceware.org 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]

Crude .ARM.exidx dumping


I can not do prel31 relocations in my head.  So this patch adds just
enough smarts to readelf -u to dump .ARM.exidx, and look up the names
of associated functions.

This isn't ready to committed because (A) relocations aren't applied
so it won't work on object files, and (B) it really ought to decode
unwind instructions, too.  It was just enough to fix the bug I was
working on.  But I'm posting it as a basis for anyone who wants to
extend it (maybe me someday).

-- 
Daniel Jacobowitz
CodeSourcery

2007-03-13  Daniel Jacobowitz  <dan@codesourcery.com>

	* readelf.c (find_symbol_for_address): Handle Thumb symbols.
	(struct arm_unw_aux_info, struct arm_exidx_entry, dump_arm_unwind)
	(slurp_arm_unwind_table, arm_process-unwind): New.
	(process_unwind): Add arm_process_unwind.

---
 binutils/readelf.c |  263 ++++++++++++++++++++++++++++++++++++++++++++++++++++-
 1 files changed, 260 insertions(+), 3 deletions(-)

Index: binutils-2.17.50/binutils/readelf.c
===================================================================
--- binutils-2.17.50.orig/binutils/readelf.c	2007-03-12 11:11:20.000000000 -0700
+++ binutils-2.17.50/binutils/readelf.c	2007-03-13 06:00:30.000000000 -0700
@@ -4815,16 +4815,24 @@ find_symbol_for_address (Elf_Internal_Sy
   Elf_Internal_Sym *sym, *best = NULL;
   unsigned long i;
 
+  if (elf_header.e_machine == EM_ARM)
+    addr.offset &= ~1;
+
   for (i = 0, sym = symtab; i < nsyms; ++i, ++sym)
     {
+      bfd_vma value = sym->st_value;
+
+      if (elf_header.e_machine == EM_ARM)
+	value &= ~1;
+
       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)
+	  && addr.offset >= value
+	  && addr.offset - value < dist)
 	{
 	  best = sym;
-	  dist = addr.offset - sym->st_value;
+	  dist = addr.offset - value;
 	  if (!dist)
 	    break;
 	}
@@ -5500,6 +5508,254 @@ hppa_process_unwind (FILE *file)
   return 1;
 }
 
+struct arm_unw_aux_info
+{
+  struct arm_exidx_entry
+  {
+    unsigned int fn;
+    unsigned int entry;
+  }
+  *exidx_table;
+
+  unsigned long exidx_len;	/* Length of .ARM.exidx.  */
+  bfd_vma exidx_base;		/* Start of .ARM.exidx, for prel31 relocs.  */
+
+  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_arm_unwind (struct arm_unw_aux_info *aux)
+{
+  struct arm_exidx_entry *ex;
+
+  for (ex = aux->exidx_table; ex < aux->exidx_table + aux->exidx_len; ex++)
+    {
+      bfd_vma fn, offset;
+      struct absaddr start;
+      const char *procname;
+
+      fn = ex->fn & 0x7fffffff;
+      if (fn & 0x40000000)
+	fn |= ~ (bfd_vma) 0x7fffffff;
+      fn = fn + aux->exidx_base + 8 * (ex - aux->exidx_table);
+      start.section = SHN_UNDEF;
+      start.offset = fn;
+
+      find_symbol_for_address (aux->symtab, aux->nsyms, aux->strtab,
+			       aux->strtab_size, start, &procname,
+			       &offset);
+
+      fputc ('\n', stdout);
+      print_vma (fn, PREFIX_HEX);
+      fputs (" <", stdout);
+
+      if (procname)
+	{
+	  fputs (procname, stdout);
+
+	  /* Shouldn't happen.  */
+	  if (ex->fn & 0x80000000)
+	    offset |= 0x80000000;
+
+	  if (offset)
+	    printf ("+0x%lx", (unsigned long) offset);
+	}
+
+      fputs (">: ", stdout);
+
+      if (ex->entry == 1)
+	{
+	  print_vma (ex->entry, PREFIX_HEX);
+	  fputs (" [cantunwind]", stdout);
+	}
+      else if (ex->entry & 0x80000000)
+	{
+	  print_vma (ex->entry, PREFIX_HEX);
+	  fputs (" [...]", stdout);
+	}
+      else
+	{
+	  bfd_vma table;
+
+	  fputs ("@", stdout);
+	  table = ex->entry;
+	  if (table & 0x40000000)
+	    table |= ~ (bfd_vma) 0x7fffffff;
+	  table = table + aux->exidx_base + 8 * (ex - aux->exidx_table) + 4;
+	  print_vma (table, PREFIX_HEX);
+	  fputs (" [...]", stdout);
+	}
+    }
+
+  printf ("\n");
+}
+
+static int
+slurp_arm_unwind_table (FILE *file,
+			struct arm_unw_aux_info *aux,
+			Elf_Internal_Shdr *sec)
+{
+  unsigned long size, unw_ent_size, nentries, nrelas, i;
+  Elf_Internal_Phdr *seg;
+  struct arm_exidx_entry *texidx;
+  Elf_Internal_Shdr *relsec;
+  Elf_Internal_Rela *rela, *rp;
+  unsigned char *table, *tp;
+  Elf_Internal_Sym *sym;
+  const char *relname;
+
+  /* Load the unwind table index (.ARM.exidx).  */
+  size = sec->sh_size;
+  table = get_data (NULL, file, sec->sh_offset, 1, size,
+		    _("unwind table index"));
+  if (!table)
+    return 0;
+
+  unw_ent_size = 8;
+  nentries = size / unw_ent_size;
+  size = nentries * unw_ent_size;
+
+  aux->exidx_base = sec->sh_addr;
+  aux->exidx_table = xcmalloc (nentries, sizeof (aux->exidx_table[0]));
+  texidx = aux->exidx_table;
+
+  for (tp = table; tp < table + size; tp += unw_ent_size, ++texidx)
+    {
+      texidx->fn = byte_get ((unsigned char *) tp + 0, 4);
+      texidx->entry = byte_get ((unsigned char *) tp + 4, 4);
+    }
+  free (table);
+
+
+  /* Third, apply any relocations to the unwind table.  */
+
+  if (0)
+  for (relsec = section_headers;
+       relsec < section_headers + elf_header.e_shnum;
+       ++relsec)
+    {
+      if (relsec->sh_type != SHT_RELA
+	  || SECTION_HEADER_INDEX (relsec->sh_info) >= elf_header.e_shnum
+	  || 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 (! const_strneq (relname, "R_PARISC_SEGREL"))
+	    {
+	      warn (_("Skipping unexpected relocation type %s\n"), relname);
+	      continue;
+	    }
+
+	  i = rp->r_offset / unw_ent_size;
+
+#if 0
+	  switch ((rp->r_offset % unw_ent_size) / eh_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;
+	    }
+#endif
+	}
+
+      free (rela);
+    }
+
+  aux->exidx_len = nentries;
+
+  return 1;
+}
+
+static int
+arm_process_unwind (FILE *file)
+{
+  struct arm_unw_aux_info aux;
+  Elf_Internal_Shdr *unwsec = NULL;
+  Elf_Internal_Shdr *strsec;
+  Elf_Internal_Shdr *sec;
+  unsigned long i;
+
+  memset (& aux, 0, sizeof (aux));
+
+  if (string_table == NULL)
+    return 1;
+
+  for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+    {
+      if (sec->sh_type == SHT_SYMTAB
+	  && SECTION_HEADER_INDEX (sec->sh_link) < elf_header.e_shnum)
+	{
+	  aux.nsyms = sec->sh_size / sec->sh_entsize;
+	  aux.symtab = GET_ELF_SYMBOLS (file, sec);
+
+	  strsec = SECTION_HEADER (sec->sh_link);
+	  aux.strtab = get_data (NULL, file, strsec->sh_offset,
+				 1, strsec->sh_size, _("string table"));
+	  aux.strtab_size = aux.strtab != NULL ? strsec->sh_size : 0;
+	}
+      else if (streq (SECTION_NAME (sec), ".ARM.exidx"))
+	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 (streq (SECTION_NAME (sec), ".ARM.exidx"))
+	{
+	  printf (_("\nUnwind table index "));
+	  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 * eh_addr_size + 8)));
+
+          slurp_arm_unwind_table (file, &aux, sec);
+	  if (aux.exidx_len > 0)
+	    dump_arm_unwind (&aux);
+
+	  if (aux.exidx_table)
+	    free ((char *) aux.exidx_table);
+	  aux.exidx_table = NULL;
+	}
+    }
+
+  if (aux.symtab)
+    free (aux.symtab);
+  if (aux.strtab)
+    free ((char *) aux.strtab);
+
+  return 1;
+}
+
 static int
 process_unwind (FILE *file)
 {
@@ -5507,6 +5763,7 @@ process_unwind (FILE *file)
     int machtype;
     int (*handler)(FILE *file);
   } handlers[] = {
+    { EM_ARM, arm_process_unwind },
     { EM_IA_64, ia64_process_unwind },
     { EM_PARISC, hppa_process_unwind },
     { 0, 0 }


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