This is the mail archive of the
binutils@sourceware.cygnus.com
mailing list for the binutils project.
Patch to force disassemble of Thumb instructions
- To: binutils at sourceware dot cygnus dot com
- Subject: Patch to force disassemble of Thumb instructions
- From: Nick Clifton <nickc at cygnus dot com>
- Date: Mon, 3 Jan 2000 12:51:02 -0800
Hi Guys,
I am about to check in the patch below. It adds a new, ARM
specific command line switch to the disassembler;
--disassembler-options=force-thumb which can be used to force the
disassembler to interpret all instructions as Thumb instructions,
even if it believes them to be ARM instructions. This can be
useful when attempting to disassemble COFF format thumb binaries
produced by non-GNU toolchains.
Cheers
Nick
2000-01-03 Nick Clifton <nickc@cygnus.com>
* arm-dis.c (streq): New macro.
(strneq): New macro.
(force_thumb): ew local variable.
(parse_disassembler_option): New function: Parse a single, ARM
specific disassembler command line switch.
(parse_disassembler_option): Call parse_disassembler_option to
parse individual command line switches.
(print_insn_big_arm): Check force_thumb.
(print_insn_little_arm): Check force_thumb.
Index: opcodes/arm-dis.c
===================================================================
RCS file: /cvs/binutils/binutils/opcodes/arm-dis.c,v
retrieving revision 1.8
diff -p -r1.8 arm-dis.c
*** arm-dis.c 1999/11/16 03:37:02 1.8
--- arm-dis.c 2000/01/03 20:43:55
*************** Foundation, Inc., 59 Temple Place - Suit
*** 32,37 ****
--- 32,44 ----
#include "elf/internal.h"
#include "elf/arm.h"
+ #ifndef streq
+ #define streq(a,b) (strcmp ((a), (b)) == 0)
+ #endif
+ #ifndef strneq
+ #define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0)
+ #endif
+
static char * arm_conditional[] =
{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
"hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
*************** static char * arm_regnames_apcs[] =
*** 51,65 ****
/* Choose which register name set to use. */
static char ** arm_regnames = arm_regnames_standard;
static char * arm_fp_const[] =
{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
static char * arm_shift[] =
{"lsl", "lsr", "asr", "ror"};
!
! static int print_insn_arm
! PARAMS ((bfd_vma, struct disassemble_info *, long));
!
static void
arm_decode_shift (given, func, stream)
long given;
--- 58,79 ----
/* Choose which register name set to use. */
static char ** arm_regnames = arm_regnames_standard;
+ static boolean force_thumb = false;
+
static char * arm_fp_const[] =
{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
static char * arm_shift[] =
{"lsl", "lsr", "asr", "ror"};
!
! /* Forward declarations. */
! static void arm_decode_shift PARAMS ((long, fprintf_ftype, void *));
! static int print_insn_arm PARAMS ((bfd_vma, struct disassemble_info *, long));
! static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
! static void parse_disassembler_option PARAMS ((char *));
! static void parse_disassembler_options PARAMS ((char *));
!
! /* Functions. */
static void
arm_decode_shift (given, func, stream)
long given;
*************** arm_toggle_regnames ()
*** 792,823 ****
}
static void
! parse_disassembler_options (options)
! char * options;
{
! if (options == NULL)
return;
! if (strncmp (options, "reg-names-", 10) == 0)
{
! options += 10;
! if (strcmp (options, "std") == 0)
arm_regnames = arm_regnames_standard;
! else if (strcmp (options, "apcs") == 0)
arm_regnames = arm_regnames_apcs;
! else if (strcmp (options, "raw") == 0)
arm_regnames = arm_regnames_raw;
else
! fprintf (stderr, "Unrecognised register name set: %s\n", options);
}
else
! fprintf (stderr, "Unrecognised disassembler option: %s\n", options);
return;
}
! /* NOTE: There are no checks in these routines that the relevant number of data bytes exist */
int
print_insn_big_arm (pc, info)
--- 806,868 ----
}
static void
! parse_disassembler_option (option)
! char * option;
{
! if (option == NULL)
return;
! if (strneq (option, "reg-names-", 10))
{
! option += 10;
! if (streq (option, "std"))
arm_regnames = arm_regnames_standard;
! else if (streq (option, "apcs"))
arm_regnames = arm_regnames_apcs;
! else if (streq (option, "raw"))
arm_regnames = arm_regnames_raw;
else
! fprintf (stderr, "Unrecognised register name set: %s\n", option);
}
+ else if (streq (option, "force-thumb"))
+ force_thumb = 1;
+ else if (streq (option, "no-force-thumb"))
+ force_thumb = 0;
else
! fprintf (stderr, "Unrecognised disassembler option: %s\n", option);
return;
}
+
+ static void
+ parse_disassembler_options (options)
+ char * options;
+ {
+ char * space;
+
+ if (options == NULL)
+ return;
+
+ do
+ {
+ space = strchr (options, ' ');
+
+ if (space)
+ {
+ * space = '\0';
+ parse_disassembler_option (options);
+ * space = ' ';
+ options = space + 1;
+ }
+ else
+ parse_disassembler_option (options);
+ }
+ while (space);
+ }
! /* NOTE: There are no checks in these routines that the relevant number of
! data bytes exist. */
int
print_insn_big_arm (pc, info)
*************** print_insn_big_arm (pc, info)
*** 839,846 ****
info->disassembler_options = NULL;
}
! is_thumb = false;
! if (info->symbols != NULL)
{
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
{
--- 884,892 ----
info->disassembler_options = NULL;
}
! is_thumb = force_thumb;
!
! if (!is_thumb && info->symbols != NULL)
{
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
{
*************** print_insn_little_arm (pc, info)
*** 919,928 ****
/* To avoid repeated parsing of this option, we remove it here. */
info->disassembler_options = NULL;
}
!
! is_thumb = false;
! if (info->symbols != NULL)
{
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
{
--- 965,974 ----
/* To avoid repeated parsing of this option, we remove it here. */
info->disassembler_options = NULL;
}
!
! is_thumb = force_thumb;
! if (!is_thumb && info->symbols != NULL)
{
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
{
*************** print_insn_little_arm (pc, info)
*** 952,960 ****
status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
b[3] = b[2] = 0;
}
if (status != 0)
{
! (*info->memory_error_func) (status, pc, info);
return -1;
}
--- 998,1007 ----
status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
b[3] = b[2] = 0;
}
+
if (status != 0)
{
! info->memory_error_func (status, pc, info);
return -1;
}
2000-01-03 Nick Clifton <nickc@cygnus.com>
* binutils.texi: Document new, ARM specific disassembler
command line switch "-M force-thumb".
Index: binutils/binutils.texi
===================================================================
RCS file: /cvs/binutils/binutils/binutils/binutils.texi,v
retrieving revision 1.14
diff -p -r1.14 binutils.texi
*** binutils.texi 1999/11/21 11:37:21 1.14
--- binutils.texi 2000/01/03 20:43:55
*************** register 13 called 'sp', register 14 cal
*** 1353,1358 ****
--- 1353,1364 ----
select the name set used by the ARM Procedure Call Standard, whilst
specifying @samp{--disassembler-options=reg-names-raw} will just use
@samp{r} followed by the register number.
+
+ This option can also be used for ARM architectures to force the
+ disassembler to interpret all instructions as THUMB instructions by
+ using the switch @samp{--disassembler-options=force-thumb}. This can be
+ useful when attempting to disassemble thumb code produced by other
+ compilers.
@item -p
@itemx --private-headers