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

Patch to force disassemble of Thumb instructions


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

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