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]

Commit: Improve readelf's decoding or ARM unwind tables.


Hi Guys,

  Whilst working on PR 13449, I found some problems with readelf's
  decoding of ARM unwind tables.  So I am applying this patch to make
  things better.

Cheers
  Nick

binutils/ChangeLog
2011-12-02  Nick Clifton  <nickc@redhat.com>

	* readelf.c (ia64_process_unwind): Turn into a void funtion.
	(hppa_process_unwind): Likewise.
	(arm_process_unwind): Likewise.
	(process_unwind): Likewise.
	(arm_get_section_word): Rename to get_unwind_section_word.
	Add sym_name parameter to return the offset into the string table
	of the symbol associated with the reloc applied to the word.
	(decode_tic6x_unwind_regmask): Add NULL argument to invocation of
	get_unwind_section_word.
	(dump_arm_unwind): Likewise.
	(decode_arm_unwind_bytecode): Prepend a comma when *not* the first
	register in a list.
	(decode_arm_unwind): If the returned function address is 0 and a
	valid symname offset is provided use that to compute the name
	associated with the entry.
	Add extra checks of the compact model index entry.

Index: binutils/readelf.c
===================================================================
RCS file: /cvs/src/src/binutils/readelf.c,v
retrieving revision 1.562
diff -u -3 -p -r1.562 readelf.c
--- binutils/readelf.c	28 Nov 2011 16:51:09 -0000	1.562
+++ binutils/readelf.c	2 Dec 2011 16:52:50 -0000
@@ -5779,7 +5781,7 @@ slurp_ia64_unwind_table (FILE * file,
   return 1;
 }
 
-static int
+static void
 ia64_process_unwind (FILE * file)
 {
   Elf_Internal_Shdr * sec;
@@ -5916,8 +5918,6 @@ ia64_process_unwind (FILE * file)
     free (aux.symtab);
   if (aux.strtab)
     free ((char *) aux.strtab);
-
-  return 1;
 }
 
 struct hppa_unw_table_entry
@@ -6189,7 +6189,7 @@ slurp_hppa_unwind_table (FILE * file,
   return 1;
 }
 
-static int
+static void
 hppa_process_unwind (FILE * file)
 {
   struct hppa_unw_aux_info aux;
@@ -6198,10 +6198,10 @@ hppa_process_unwind (FILE * file)
   Elf_Internal_Shdr * sec;
   unsigned long i;
 
-  memset (& aux, 0, sizeof (aux));
-
   if (string_table == NULL)
-    return 1;
+    return;
+
+  memset (& aux, 0, sizeof (aux));
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
@@ -6249,8 +6249,6 @@ hppa_process_unwind (FILE * file)
     free (aux.symtab);
   if (aux.strtab)
     free ((char *) aux.strtab);
-
-  return 1;
 }
 
 struct arm_section
@@ -6315,17 +6313,21 @@ arm_free_section (struct arm_section *ar
       cached section and install SEC instead.
    2) Locate the 32-bit word at WORD_OFFSET in unwind section SEC
       and return its valued in * WORDP, relocating if necessary.
-   3) Update the NEXT_RELA field in ARM_SEC and stores the section index and
+   3) Update the NEXT_RELA field in ARM_SEC and store the section index and
       relocation's offset in ADDR.
-   4) Return TRUE upon success, FALSE otherwise.  */
+   4) If SYM_NAME is non-NULL and a relocation was applied, record the offset
+      into the string table of the symbol associated with the reloc.  If no
+      reloc was applied store -1 there.
+   5) Return TRUE upon success, FALSE otherwise.  */
 
 static bfd_boolean
-arm_section_get_word (struct arm_unw_aux_info *  aux,
-		      struct arm_section *       arm_sec,
-		      Elf_Internal_Shdr *        sec,
-		      bfd_vma 			 word_offset,
-		      unsigned int *             wordp,
-		      struct absaddr *           addr)
+get_unwind_section_word (struct arm_unw_aux_info *  aux,
+			 struct arm_section *       arm_sec,
+			 Elf_Internal_Shdr *        sec,
+			 bfd_vma 		    word_offset,
+			 unsigned int *             wordp,
+			 struct absaddr *           addr,
+			 bfd_vma *		    sym_name)
 {
   Elf_Internal_Rela *rp;
   Elf_Internal_Sym *sym;
@@ -6336,6 +6338,9 @@ arm_section_get_word (struct arm_unw_aux
   addr->section = SHN_UNDEF;
   addr->offset = 0;
 
+  if (sym_name != NULL)
+    *sym_name = (bfd_vma) -1;
+
   /* If necessary, update the section cache.  */
   if (sec != arm_sec->sec)
     {
@@ -6465,6 +6470,8 @@ arm_section_get_word (struct arm_unw_aux
       word = (word & ~ (bfd_vma) 0x7fffffff) | (prelval & 0x7fffffff);
       addr->section = sym->st_shndx;
       addr->offset = offset;
+      if (sym_name)
+	* sym_name = sym->st_name;
       break;
     }
 
@@ -6501,8 +6508,8 @@ decode_tic6x_unwind_regmask (unsigned in
   if (remaining == 0 && more_words)				\
     {								\
       data_offset += 4;						\
-      if (!arm_section_get_word (aux, data_arm_sec, data_sec,	\
-				 data_offset, &word, &addr))	\
+      if (! get_unwind_section_word (aux, data_arm_sec, data_sec,	\
+				     data_offset, & word, & addr, NULL))	\
 	return;							\
       remaining = 4;						\
       more_words--;						\
@@ -6606,7 +6613,7 @@ decode_arm_unwind_bytecode (struct arm_u
 	    }
 	  if (op & 0x08)
 	    {
-	      if (first)
+	      if (!first)
 		printf (", ");
 	      printf ("r14");
 	    }
@@ -6883,21 +6890,29 @@ arm_expand_prel31 (bfd_vma word, bfd_vma
 }
 
 static void
-decode_arm_unwind (struct arm_unw_aux_info *aux,
-		   unsigned int word, unsigned int remaining,
-		   bfd_vma data_offset, Elf_Internal_Shdr *data_sec,
-		   struct arm_section *data_arm_sec)
+decode_arm_unwind (struct arm_unw_aux_info *  aux,
+		   unsigned int               word,
+		   unsigned int               remaining,
+		   bfd_vma                    data_offset,
+		   Elf_Internal_Shdr *        data_sec,
+		   struct arm_section *       data_arm_sec)
 {
   int per_index;
   unsigned int more_words = 0;
   struct absaddr addr;
+  bfd_vma sym_name = (bfd_vma) -1;
 
   if (remaining == 0)
     {
-      /* Fetch the first word.  */
-      if (!arm_section_get_word (aux, data_arm_sec, data_sec, data_offset,
-				 &word, &addr))
+      /* Fetch the first word.
+	 Note - when decoding an object file the address extracted
+	 here will always be 0.  So we also pass in the sym_name
+	 parameter so that we can find the symbol associated with
+	 the personality routine.  */
+      if (! get_unwind_section_word (aux, data_arm_sec, data_sec, data_offset,
+				     & word, & addr, & sym_name))
 	return;
+
       remaining = 4;
     }
 
@@ -6909,7 +6924,21 @@ decode_arm_unwind (struct arm_unw_aux_in
 
       fn = arm_expand_prel31 (word, data_sec->sh_addr + data_offset);
       printf (_("  Personality routine: "));
-      procname = arm_print_vma_and_name (aux, fn, addr);
+      if (fn == 0
+	  && addr.section == SHN_UNDEF && addr.offset == 0
+	  && sym_name != (bfd_vma) -1 && sym_name < aux->strtab_size)
+	{
+	  procname = aux->strtab + sym_name;
+	  print_vma (fn, PREFIX_HEX);
+	  if (procname)
+	    {
+	      fputs (" <", stdout);
+	      fputs (procname, stdout);
+	      fputc ('>', stdout);
+	    }
+	}
+      else
+	procname = arm_print_vma_and_name (aux, fn, addr);
       fputc ('\n', stdout);
 
       /* The GCC personality routines use the standard compact
@@ -6939,9 +6968,20 @@ decode_arm_unwind (struct arm_unw_aux_in
     }
   else
     {
-      
+      /* ARM EHABI Section 6.3:
+	 
+	 An exception-handling table entry for the compact model looks like:
+	 
+           31 30-28 27-24 23-0
+	   -- ----- ----- ----
+            1   0   index Data for personalityRoutine[index]    */
+
+      if (elf_header.e_machine == EM_ARM
+	  && (word & 0x70000000))
+	warn (_("Corrupt ARM compact model table entry (%08x)\n"), word);
+
       per_index = (word >> 24) & 0x7f;
-      printf (_("  Compact model %d\n"), per_index);
+      printf (_("  Compact model index: %d\n"), per_index);
       if (per_index == 0)
 	{
 	  more_words = 0;
@@ -6965,14 +7005,17 @@ decode_arm_unwind (struct arm_unw_aux_in
 				      data_offset, data_sec, data_arm_sec);
 	}
       else
-	printf ("  [reserved]\n");
+	{
+	  warn (_("Unknown ARM compact model index encountered\n"));
+	  printf (_("  [reserved]\n"));
+	}
       break;
 
     case EM_TI_C6000:
       if (per_index < 3)
 	{
 	  decode_tic6x_unwind_bytecode (aux, word, remaining, more_words,
-				      data_offset, data_sec, data_arm_sec);
+					data_offset, data_sec, data_arm_sec);
 	}
       else if (per_index < 5)
 	{
@@ -6989,11 +7032,12 @@ decode_arm_unwind (struct arm_unw_aux_in
 		  tic6x_unwind_regnames[word & 0xf]);
 	}
       else
-	printf ("  [reserved]\n");
+	printf (_("  [reserved (%d)]\n"), per_index);
       break;
 
     default:
-      abort ();
+      error (_("Unsupported architecture type %d encountered when decoding unwind table"),
+	     elf_header.e_machine);
     }
 
   /* Decode the descriptors.  Not implemented.  */
@@ -7017,13 +7061,13 @@ dump_arm_unwind (struct arm_unw_aux_info
 
       fputc ('\n', stdout);
 
-      if (!arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
-				 8 * i, &exidx_fn, &fn_addr)
-	  || !arm_section_get_word (aux, &exidx_arm_sec, exidx_sec,
-				    8 * i + 4, &exidx_entry, &entry_addr))
+      if (! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
+				     8 * i, & exidx_fn, & fn_addr, NULL)
+	  || ! get_unwind_section_word (aux, & exidx_arm_sec, exidx_sec,
+					8 * i + 4, & exidx_entry, & entry_addr, NULL))
 	{
-	  arm_free_section (&exidx_arm_sec);
-	  arm_free_section (&extab_arm_sec);
+	  arm_free_section (& exidx_arm_sec);
+	  arm_free_section (& extab_arm_sec);
 	  return;
 	}
 
@@ -7084,7 +7128,8 @@ dump_arm_unwind (struct arm_unw_aux_info
 }
 
 /* Used for both ARM and C6X unwinding tables.  */
-static int
+
+static void
 arm_process_unwind (FILE *file)
 {
   struct arm_unw_aux_info aux;
@@ -7094,9 +7139,6 @@ arm_process_unwind (FILE *file)
   unsigned long i;
   unsigned int sec_type;
 
-  memset (& aux, 0, sizeof (aux));
-  aux.file = file;
-
   switch (elf_header.e_machine)
     {
     case EM_ARM:
@@ -7107,12 +7149,17 @@ arm_process_unwind (FILE *file)
       sec_type = SHT_C6000_UNWIND;
       break;
 
-    default:
-	abort();
+    default: 
+      error (_("Unsupported architecture type %d encountered when processing unwind table"),
+	     elf_header.e_machine);
+      return;
     }
 
   if (string_table == NULL)
-    return 1;
+    return;
+
+  memset (& aux, 0, sizeof (aux));
+  aux.file = file;
 
   for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
     {
@@ -7130,37 +7177,35 @@ arm_process_unwind (FILE *file)
 	unwsec = sec;
     }
 
-  if (!unwsec)
+  if (unwsec == NULL)
     printf (_("\nThere are no unwind sections in this file.\n"));
+  else
+    for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
+      {
+	if (sec->sh_type == sec_type)
+	  {
+	    printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
+		    SECTION_NAME (sec),
+		    (unsigned long) sec->sh_offset,
+		    (unsigned long) (sec->sh_size / (2 * eh_addr_size)));
 
-  for (i = 0, sec = section_headers; i < elf_header.e_shnum; ++i, ++sec)
-    {
-      if (sec->sh_type == sec_type)
-	{
-	  printf (_("\nUnwind table index '%s' at offset 0x%lx contains %lu entries:\n"),
-		  SECTION_NAME (sec),
-		  (unsigned long) sec->sh_offset,
-		  (unsigned long) (sec->sh_size / (2 * eh_addr_size)));
-
-	  dump_arm_unwind (&aux, sec);
-	}
-    }
+	    dump_arm_unwind (&aux, sec);
+	  }
+      }
 
   if (aux.symtab)
     free (aux.symtab);
   if (aux.strtab)
     free ((char *) aux.strtab);
-
-  return 1;
 }
 
-static int
+static void
 process_unwind (FILE * file)
 {
   struct unwind_handler
   {
     int machtype;
-    int (* handler)(FILE *);
+    void (* handler)(FILE *);
   } handlers[] =
   {
     { EM_ARM, arm_process_unwind },
@@ -7172,14 +7217,14 @@ process_unwind (FILE * file)
   int i;
 
   if (!do_unwind)
-    return 1;
+    return;
 
   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;
+  printf (_("\nThe decoding of unwind sections for machine type %s is not currently supported.\n"),
+	  get_machine_name (elf_header.e_machine));
 }
 
 static void


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