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]

[patch] ARM mapping symbols and disassembly


objdump currently uses the type of the preceding symbol to determine whether 
it should disassemble code as Arm or Thumb. This has various failure modes, 
including functions that contain both Arm and Thumb code, and cases where the 
preceding symbol is not a function symbol. The latter is common in the 
binutils/gas testsuites. It currently works because gas gives these symbols 
the nonstandard STT_ARM_16BIT type. I have a followup patch to suppress this 
behavior.

The attached patch makes the disassembler look for mapping symbols to 
determine disassembly mode. Having the disassembler root through the symbol 
table like this is ugly, but I couldn't find a better solution.

Tested with cross to arm-none-eabi.
Ok?

Paul

2006-10-20  Paul Brook  <paul@codesourcery.com>

	binutils/
	* objdump.c (disassemble_section): Set info->symtab{,_size,_pos}.

	include/
	* dis-asm.h (disassemble_info): Add symtab, symtab_pos and
	symtab_size.

	opcodes/
	* arm-dis.c (last_is_thumb, last_mapping_sym, last_mapping_addr): New.
	(get_sym_code_type): New function.
	(print_insn): Search for mapping symbols.
Index: binutils/objdump.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/binutils/objdump.c,v
retrieving revision 1.117.2.1
diff -u -p -r1.117.2.1 objdump.c
--- binutils/objdump.c	22 Aug 2006 15:08:29 -0000	1.117.2.1
+++ binutils/objdump.c	19 Oct 2006 21:26:51 -0000
@@ -1748,11 +1748,13 @@ disassemble_section (bfd *abfd, asection
 
 	  pinfo->symbols = sorted_syms + place;
 	  pinfo->num_symbols = x - place;
+	  pinfo->symtab_pos = place;
 	}
       else
 	{
 	  pinfo->symbols = NULL;
 	  pinfo->num_symbols = 0;
+	  pinfo->symtab_pos = -1;
 	}
 
       if (! prefix_addresses)
@@ -1945,6 +1947,8 @@ disassemble_data (bfd *abfd)
 		 compare_relocs);
 	}
     }
+  disasm_info.symtab = sorted_syms;
+  disasm_info.symtab_size = sorted_symcount;
 
   bfd_map_over_sections (abfd, disassemble_section, & disasm_info);
 
Index: include/dis-asm.h
===================================================================
RCS file: /var/cvsroot/src-cvs/src/include/dis-asm.h,v
retrieving revision 1.62
diff -u -p -r1.62 dis-asm.h
--- include/dis-asm.h	17 Feb 2006 14:36:26 -0000	1.62
+++ include/dis-asm.h	19 Oct 2006 18:29:10 -0000
@@ -94,6 +94,12 @@ typedef struct disassemble_info {
   /* Number of symbols in array.  */
   int num_symbols;
 
+  /* Symbol table provided for targets that want to look at it.  This is
+     used on Arm to find mapping symbols and determine Arm/Thumb code.  */
+  asymbol **symtab;
+  int symtab_pos;
+  int symtab_size;
+
   /* For use by the disassembler.
      The top 16 bits are reserved for public use (and are documented here).
      The bottom 16 bits are for the internal use of the disassembler.  */
Index: opcodes/arm-dis.c
===================================================================
RCS file: /var/cvsroot/src-cvs/src/opcodes/arm-dis.c,v
retrieving revision 1.62.2.9
diff -u -p -r1.62.2.9 arm-dis.c
--- opcodes/arm-dis.c	19 Sep 2006 18:44:37 -0000	1.62.2.9
+++ opcodes/arm-dis.c	20 Oct 2006 14:19:27 -0000
@@ -1480,6 +1480,11 @@ static unsigned int ifthen_next_state;
 static bfd_vma ifthen_address;
 #define IFTHEN_COND ((ifthen_state >> 4) & 0xf)
 
+/* Cached Thumb state.  */
+int last_is_thumb;
+int last_mapping_sym = -1;
+bfd_vma last_mapping_addr = 0;
+
 
 /* Functions.  */
 int
@@ -3859,6 +3864,39 @@ find_ifthen_state (bfd_vma pc, struct di
     ifthen_state = 0;
 }
 
+/* Try to infer the code type (Arm or Thumb) from a symbol.
+   Returns nonzero if is_thumb was set.  */
+
+static int
+get_sym_code_type (struct disassemble_info *info, int n, int *is_thumb)
+{
+  elf_symbol_type *es;
+  unsigned int type;
+  const char *name;
+
+  es = *(elf_symbol_type **)(info->symbols);
+  type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
+
+//printf("Scan %d %s\n", n, bfd_asymbol_name(info->symtab[n]));
+  /* If the symbol has function type then use that.  */
+  if (type == STT_FUNC || type == STT_ARM_TFUNC)
+    {
+      *is_thumb = (type == STT_ARM_TFUNC);
+      return TRUE;
+    }
+
+  /* Check for mapping symbols.  */
+  name = bfd_asymbol_name(info->symtab[n]);
+  if (name[0] == '$' && (name[1] == 'a' || name[1] == 't')
+      && (name[2] == 0 || name[2] == '.'))
+    {
+      *is_thumb = (name[1] == 't');
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
 /* NOTE: There are no checks in these routines that
    the relevant number of data bytes exist.  */
 
@@ -3897,13 +3935,72 @@ print_insn (bfd_vma pc, struct disassemb
 	}
       else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
 	{
-	  elf_symbol_type *  es;
-	  unsigned int       type;
+	  bfd_vma addr;
+	  int n;
+	  int last_sym;
+	  bfd_boolean found;
 
-	  es = *(elf_symbol_type **)(info->symbols);
-	  type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
+	  if (info->symtab)
+	    {
+	      if (pc <= last_mapping_addr)
+		last_mapping_sym = -1;
+//printf("Mapping %d %d %d\n", last_mapping_sym, info->symtab_pos, info->symtab_size);
+	      is_thumb = last_is_thumb;
+	      found = FALSE;
+	      /* Start scanning at the start of the function, or wherever
+		 we finished last time.  */
+	      n = info->symtab_pos + 1;
+	      if (n < last_mapping_sym)
+		n = last_mapping_sym;
+
+	      /* Scan up to the location being disassembled.  */
+	      for (; n < info->symtab_size; n++)
+		{
+		  addr = bfd_asymbol_value (info->symtab[n]);
+		  if (addr > pc)
+		    break;
+		  if (get_sym_code_type (info, n, &is_thumb))
+		    found = TRUE;
+		}
 
-	  is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
+	      last_sym = n;
+	      if (!found)
+		{
+		  if (last_mapping_sym == -1)
+		    last_mapping_sym = 0;
+		  else
+		    found = TRUE;
+
+		  /* No mapping symbol found at this address.  Look backwards
+		     for a preceeding one.  */
+		  for (n = info->symtab_pos; n >= last_mapping_sym; n--)
+		    {
+		      if (get_sym_code_type (info, n, &is_thumb))
+			{
+			  found = TRUE;
+			  break;
+			}
+		    }
+		}
+
+	      last_mapping_sym = last_sym;
+	      last_is_thumb = is_thumb;
+	    }
+	  else
+	    found = FALSE;
+
+	  /* If no mapping symbol has been found then fall back to the type
+	     of the function symbol.  */
+	  if (!found)
+	    {
+	      elf_symbol_type *  es;
+	      unsigned int       type;
+
+	      es = *(elf_symbol_type **)(info->symbols);
+	      type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
+
+	      is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
+	    }
 	}
     }
 

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