This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[patch] ARM mapping symbols and disassembly
- From: Paul Brook <paul at codesourcery dot com>
- To: binutils at sourceware dot org
- Date: Fri, 20 Oct 2006 16:45:01 +0100
- Subject: [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);
+ }
}
}