arm-dis.c revision 60484
160484Sobrien/* Instruction printing code for the ARM
260484Sobrien   Copyright (C) 1994, 95, 96, 97, 98, 99, 2000 Free Software Foundation, Inc.
360484Sobrien   Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
460484Sobrien   Modification by James G. Smith (jsmith@cygnus.co.uk)
560484Sobrien
660484SobrienThis file is part of libopcodes.
760484Sobrien
860484SobrienThis program is free software; you can redistribute it and/or modify it under
960484Sobrienthe terms of the GNU General Public License as published by the Free
1060484SobrienSoftware Foundation; either version 2 of the License, or (at your option)
1160484Sobrienany later version.
1260484Sobrien
1360484SobrienThis program is distributed in the hope that it will be useful, but WITHOUT
1460484SobrienANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
1560484SobrienFITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
1660484Sobrienmore details.
1760484Sobrien
1860484SobrienYou should have received a copy of the GNU General Public License
1960484Sobrienalong with this program; if not, write to the Free Software
2060484SobrienFoundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
2160484Sobrien
2260484Sobrien#include "sysdep.h"
2360484Sobrien#include "dis-asm.h"
2460484Sobrien#define DEFINE_TABLE
2560484Sobrien#include "arm-opc.h"
2660484Sobrien#include "coff/internal.h"
2760484Sobrien#include "libcoff.h"
2860484Sobrien#include "opintl.h"
2960484Sobrien
3060484Sobrien/* FIXME: This shouldn't be done here */
3160484Sobrien#include "elf-bfd.h"
3260484Sobrien#include "elf/internal.h"
3360484Sobrien#include "elf/arm.h"
3460484Sobrien
3560484Sobrien#ifndef streq
3660484Sobrien#define streq(a,b)	(strcmp ((a), (b)) == 0)
3760484Sobrien#endif
3860484Sobrien
3960484Sobrien#ifndef strneq
4060484Sobrien#define strneq(a,b,n)	(strncmp ((a), (b), (n)) == 0)
4160484Sobrien#endif
4260484Sobrien
4360484Sobrien#ifndef NUM_ELEM
4460484Sobrien#define NUM_ELEM(a)     (sizeof (a) / sizeof (a)[0])
4560484Sobrien#endif
4660484Sobrien
4760484Sobrienstatic char * arm_conditional[] =
4860484Sobrien{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
4960484Sobrien "hi", "ls", "ge", "lt", "gt", "le", "", "nv"};
5060484Sobrien
5160484Sobrientypedef struct
5260484Sobrien{
5360484Sobrien  const char * name;
5460484Sobrien  const char * description;
5560484Sobrien  const char * reg_names[16];
5660484Sobrien}
5760484Sobrienarm_regname;
5860484Sobrien
5960484Sobrienstatic arm_regname regnames[] =
6060484Sobrien{
6160484Sobrien  { "raw" , "Select raw register names",
6260484Sobrien    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}},
6360484Sobrien  { "std",  "Select register names used in ARM's ISA documentation",
6460484Sobrien    { "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp",  "lr",  "pc" }},
6560484Sobrien  { "apcs", "Select register names used in the APCS",
6660484Sobrien    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl",  "fp",  "ip",  "sp",  "lr",  "pc" }},
6760484Sobrien  { "atpcs", "Select register names used in the ATPCS",
6860484Sobrien    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7",  "v8",  "IP",  "SP",  "LR",  "PC" }},
6960484Sobrien  { "special-atpcs", "Select special register names used in the ATPCS",
7060484Sobrien    { "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL",  "FP",  "IP",  "SP",  "LR",  "PC" }}
7160484Sobrien};
7260484Sobrien
7360484Sobrien/* Default to standard register name set.  */
7460484Sobrienstatic unsigned int regname_selected = 1;
7560484Sobrien
7660484Sobrien#define NUM_ARM_REGNAMES  NUM_ELEM (regnames)
7760484Sobrien#define arm_regnames      regnames[regname_selected].reg_names
7860484Sobrien
7960484Sobrienstatic boolean force_thumb = false;
8060484Sobrien
8160484Sobrienstatic char * arm_fp_const[] =
8260484Sobrien{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"};
8360484Sobrien
8460484Sobrienstatic char * arm_shift[] =
8560484Sobrien{"lsl", "lsr", "asr", "ror"};
8660484Sobrien
8760484Sobrien/* Forward declarations.  */
8860484Sobrienstatic void arm_decode_shift PARAMS ((long, fprintf_ftype, void *));
8960484Sobrienstatic int  print_insn_arm   PARAMS ((bfd_vma, struct disassemble_info *, long));
9060484Sobrienstatic int  print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long));
9160484Sobrienstatic void parse_disassembler_options PARAMS ((char *));
9260484Sobrienstatic int  print_insn       PARAMS ((bfd_vma, struct disassemble_info *, boolean));
9360484Sobrienint get_arm_regname_num_options (void);
9460484Sobrienint set_arm_regname_option (int option);
9560484Sobrienint get_arm_regnames (int option, const char **setname,
9660484Sobrien		      const char **setdescription,
9760484Sobrien		      const char ***register_names);
9860484Sobrien
9960484Sobrien/* Functions. */
10060484Sobrienint
10160484Sobrienget_arm_regname_num_options (void)
10260484Sobrien{
10360484Sobrien  return NUM_ARM_REGNAMES;
10460484Sobrien}
10560484Sobrien
10660484Sobrienint
10760484Sobrienset_arm_regname_option (int option)
10860484Sobrien{
10960484Sobrien  int old = regname_selected;
11060484Sobrien  regname_selected = option;
11160484Sobrien  return old;
11260484Sobrien}
11360484Sobrien
11460484Sobrienint
11560484Sobrienget_arm_regnames (int option, const char **setname,
11660484Sobrien		  const char **setdescription,
11760484Sobrien                  const char ***register_names)
11860484Sobrien{
11960484Sobrien  *setname = regnames[option].name;
12060484Sobrien  *setdescription = regnames[option].description;
12160484Sobrien  *register_names = regnames[option].reg_names;
12260484Sobrien  return 16;
12360484Sobrien}
12460484Sobrien
12560484Sobrienstatic void
12660484Sobrienarm_decode_shift (given, func, stream)
12760484Sobrien     long given;
12860484Sobrien     fprintf_ftype func;
12960484Sobrien     void * stream;
13060484Sobrien{
13160484Sobrien  func (stream, "%s", arm_regnames[given & 0xf]);
13260484Sobrien
13360484Sobrien  if ((given & 0xff0) != 0)
13460484Sobrien    {
13560484Sobrien      if ((given & 0x10) == 0)
13660484Sobrien	{
13760484Sobrien	  int amount = (given & 0xf80) >> 7;
13860484Sobrien	  int shift = (given & 0x60) >> 5;
13960484Sobrien
14060484Sobrien	  if (amount == 0)
14160484Sobrien	    {
14260484Sobrien	      if (shift == 3)
14360484Sobrien		{
14460484Sobrien		  func (stream, ", rrx");
14560484Sobrien		  return;
14660484Sobrien		}
14760484Sobrien
14860484Sobrien	      amount = 32;
14960484Sobrien	    }
15060484Sobrien
15160484Sobrien	  func (stream, ", %s #%d", arm_shift[shift], amount);
15260484Sobrien	}
15360484Sobrien      else
15460484Sobrien	func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5],
15560484Sobrien	      arm_regnames[(given & 0xf00) >> 8]);
15660484Sobrien    }
15760484Sobrien}
15860484Sobrien
15960484Sobrien/* Print one instruction from PC on INFO->STREAM.
16060484Sobrien   Return the size of the instruction (always 4 on ARM). */
16160484Sobrienstatic int
16260484Sobrienprint_insn_arm (pc, info, given)
16360484Sobrien     bfd_vma                   pc;
16460484Sobrien     struct disassemble_info * info;
16560484Sobrien     long                      given;
16660484Sobrien{
16760484Sobrien  struct arm_opcode *  insn;
16860484Sobrien  void *               stream = info->stream;
16960484Sobrien  fprintf_ftype        func   = info->fprintf_func;
17060484Sobrien
17160484Sobrien  for (insn = arm_opcodes; insn->assembler; insn++)
17260484Sobrien    {
17360484Sobrien      if ((given & insn->mask) == insn->value)
17460484Sobrien	{
17560484Sobrien	  char * c;
17660484Sobrien
17760484Sobrien	  for (c = insn->assembler; *c; c++)
17860484Sobrien	    {
17960484Sobrien	      if (*c == '%')
18060484Sobrien		{
18160484Sobrien		  switch (*++c)
18260484Sobrien		    {
18360484Sobrien		    case '%':
18460484Sobrien		      func (stream, "%%");
18560484Sobrien		      break;
18660484Sobrien
18760484Sobrien		    case 'a':
18860484Sobrien		      if (((given & 0x000f0000) == 0x000f0000)
18960484Sobrien			  && ((given & 0x02000000) == 0))
19060484Sobrien			{
19160484Sobrien			  int offset = given & 0xfff;
19260484Sobrien
19360484Sobrien			  func (stream, "[pc");
19460484Sobrien
19560484Sobrien			  if (given & 0x01000000)
19660484Sobrien			    {
19760484Sobrien			      if ((given & 0x00800000) == 0)
19860484Sobrien				offset = - offset;
19960484Sobrien
20060484Sobrien			      /* pre-indexed */
20160484Sobrien			      func (stream, ", #%x]", offset);
20260484Sobrien
20360484Sobrien			      offset += pc + 8;
20460484Sobrien
20560484Sobrien			      /* Cope with the possibility of write-back
20660484Sobrien				 being used.  Probably a very dangerous thing
20760484Sobrien				 for the programmer to do, but who are we to
20860484Sobrien				 argue ?  */
20960484Sobrien			      if (given & 0x00200000)
21060484Sobrien				func (stream, "!");
21160484Sobrien			    }
21260484Sobrien			  else
21360484Sobrien			    {
21460484Sobrien			      /* Post indexed.  */
21560484Sobrien			      func (stream, "], #%x", offset);
21660484Sobrien
21760484Sobrien			      offset = pc + 8;  /* ie ignore the offset.  */
21860484Sobrien			    }
21960484Sobrien
22060484Sobrien			  func (stream, "\t; ");
22160484Sobrien			  info->print_address_func (offset, info);
22260484Sobrien			}
22360484Sobrien		      else
22460484Sobrien			{
22560484Sobrien			  func (stream, "[%s",
22660484Sobrien				arm_regnames[(given >> 16) & 0xf]);
22760484Sobrien			  if ((given & 0x01000000) != 0)
22860484Sobrien			    {
22960484Sobrien			      if ((given & 0x02000000) == 0)
23060484Sobrien				{
23160484Sobrien				  int offset = given & 0xfff;
23260484Sobrien				  if (offset)
23360484Sobrien				    func (stream, ", %s#%d",
23460484Sobrien					  (((given & 0x00800000) == 0)
23560484Sobrien					   ? "-" : ""), offset);
23660484Sobrien				}
23760484Sobrien			      else
23860484Sobrien				{
23960484Sobrien				  func (stream, ", %s",
24060484Sobrien					(((given & 0x00800000) == 0)
24160484Sobrien					 ? "-" : ""));
24260484Sobrien				  arm_decode_shift (given, func, stream);
24360484Sobrien				}
24460484Sobrien
24560484Sobrien			      func (stream, "]%s",
24660484Sobrien				    ((given & 0x00200000) != 0) ? "!" : "");
24760484Sobrien			    }
24860484Sobrien			  else
24960484Sobrien			    {
25060484Sobrien			      if ((given & 0x02000000) == 0)
25160484Sobrien				{
25260484Sobrien				  int offset = given & 0xfff;
25360484Sobrien				  if (offset)
25460484Sobrien				    func (stream, "], %s#%d",
25560484Sobrien					  (((given & 0x00800000) == 0)
25660484Sobrien					   ? "-" : ""), offset);
25760484Sobrien				  else
25860484Sobrien				    func (stream, "]");
25960484Sobrien				}
26060484Sobrien			      else
26160484Sobrien				{
26260484Sobrien				  func (stream, "], %s",
26360484Sobrien					(((given & 0x00800000) == 0)
26460484Sobrien					 ? "-" : ""));
26560484Sobrien				  arm_decode_shift (given, func, stream);
26660484Sobrien				}
26760484Sobrien			    }
26860484Sobrien			}
26960484Sobrien		      break;
27060484Sobrien
27160484Sobrien		    case 's':
27260484Sobrien                      if ((given & 0x004f0000) == 0x004f0000)
27360484Sobrien			{
27460484Sobrien                          /* PC relative with immediate offset.  */
27560484Sobrien			  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
27660484Sobrien
27760484Sobrien			  if ((given & 0x00800000) == 0)
27860484Sobrien			    offset = -offset;
27960484Sobrien
28060484Sobrien			  func (stream, "[pc, #%x]\t; ", offset);
28160484Sobrien
28260484Sobrien			  (*info->print_address_func)
28360484Sobrien			    (offset + pc + 8, info);
28460484Sobrien			}
28560484Sobrien		      else
28660484Sobrien			{
28760484Sobrien			  func (stream, "[%s",
28860484Sobrien				arm_regnames[(given >> 16) & 0xf]);
28960484Sobrien			  if ((given & 0x01000000) != 0)
29060484Sobrien			    {
29160484Sobrien                              /* Pre-indexed.  */
29260484Sobrien			      if ((given & 0x00400000) == 0x00400000)
29360484Sobrien				{
29460484Sobrien                                  /* Immediate.  */
29560484Sobrien                                  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
29660484Sobrien				  if (offset)
29760484Sobrien				    func (stream, ", %s#%d",
29860484Sobrien					  (((given & 0x00800000) == 0)
29960484Sobrien					   ? "-" : ""), offset);
30060484Sobrien				}
30160484Sobrien			      else
30260484Sobrien				{
30360484Sobrien                                  /* Register.  */
30460484Sobrien				  func (stream, ", %s%s",
30560484Sobrien					(((given & 0x00800000) == 0)
30660484Sobrien					 ? "-" : ""),
30760484Sobrien                                        arm_regnames[given & 0xf]);
30860484Sobrien				}
30960484Sobrien
31060484Sobrien			      func (stream, "]%s",
31160484Sobrien				    ((given & 0x00200000) != 0) ? "!" : "");
31260484Sobrien			    }
31360484Sobrien			  else
31460484Sobrien			    {
31560484Sobrien                              /* Post-indexed.  */
31660484Sobrien			      if ((given & 0x00400000) == 0x00400000)
31760484Sobrien				{
31860484Sobrien                                  /* Immediate.  */
31960484Sobrien                                  int offset = ((given & 0xf00) >> 4) | (given & 0xf);
32060484Sobrien				  if (offset)
32160484Sobrien				    func (stream, "], %s#%d",
32260484Sobrien					  (((given & 0x00800000) == 0)
32360484Sobrien					   ? "-" : ""), offset);
32460484Sobrien				  else
32560484Sobrien				    func (stream, "]");
32660484Sobrien				}
32760484Sobrien			      else
32860484Sobrien				{
32960484Sobrien                                  /* Register.  */
33060484Sobrien				  func (stream, "], %s%s",
33160484Sobrien					(((given & 0x00800000) == 0)
33260484Sobrien					 ? "-" : ""),
33360484Sobrien                                        arm_regnames[given & 0xf]);
33460484Sobrien				}
33560484Sobrien			    }
33660484Sobrien			}
33760484Sobrien		      break;
33860484Sobrien
33960484Sobrien		    case 'b':
34060484Sobrien		      (*info->print_address_func)
34160484Sobrien			(BDISP (given) * 4 + pc + 8, info);
34260484Sobrien		      break;
34360484Sobrien
34460484Sobrien		    case 'c':
34560484Sobrien		      func (stream, "%s",
34660484Sobrien			    arm_conditional [(given >> 28) & 0xf]);
34760484Sobrien		      break;
34860484Sobrien
34960484Sobrien		    case 'm':
35060484Sobrien		      {
35160484Sobrien			int started = 0;
35260484Sobrien			int reg;
35360484Sobrien
35460484Sobrien			func (stream, "{");
35560484Sobrien			for (reg = 0; reg < 16; reg++)
35660484Sobrien			  if ((given & (1 << reg)) != 0)
35760484Sobrien			    {
35860484Sobrien			      if (started)
35960484Sobrien				func (stream, ", ");
36060484Sobrien			      started = 1;
36160484Sobrien			      func (stream, "%s", arm_regnames[reg]);
36260484Sobrien			    }
36360484Sobrien			func (stream, "}");
36460484Sobrien		      }
36560484Sobrien		      break;
36660484Sobrien
36760484Sobrien		    case 'o':
36860484Sobrien		      if ((given & 0x02000000) != 0)
36960484Sobrien			{
37060484Sobrien			  int rotate = (given & 0xf00) >> 7;
37160484Sobrien			  int immed = (given & 0xff);
37260484Sobrien			  immed = (((immed << (32 - rotate))
37360484Sobrien				    | (immed >> rotate)) & 0xffffffff);
37460484Sobrien			  func (stream, "#%d\t; 0x%x", immed, immed);
37560484Sobrien			}
37660484Sobrien		      else
37760484Sobrien			arm_decode_shift (given, func, stream);
37860484Sobrien		      break;
37960484Sobrien
38060484Sobrien		    case 'p':
38160484Sobrien		      if ((given & 0x0000f000) == 0x0000f000)
38260484Sobrien			func (stream, "p");
38360484Sobrien		      break;
38460484Sobrien
38560484Sobrien		    case 't':
38660484Sobrien		      if ((given & 0x01200000) == 0x00200000)
38760484Sobrien			func (stream, "t");
38860484Sobrien		      break;
38960484Sobrien
39060484Sobrien		    case 'h':
39160484Sobrien		      if ((given & 0x00000020) == 0x00000020)
39260484Sobrien			func (stream, "h");
39360484Sobrien                      else
39460484Sobrien                        func (stream, "b");
39560484Sobrien		      break;
39660484Sobrien
39760484Sobrien		    case 'A':
39860484Sobrien		      func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]);
39960484Sobrien		      if ((given & 0x01000000) != 0)
40060484Sobrien			{
40160484Sobrien			  int offset = given & 0xff;
40260484Sobrien			  if (offset)
40360484Sobrien			    func (stream, ", %s#%d]%s",
40460484Sobrien				  ((given & 0x00800000) == 0 ? "-" : ""),
40560484Sobrien				  offset * 4,
40660484Sobrien				  ((given & 0x00200000) != 0 ? "!" : ""));
40760484Sobrien			  else
40860484Sobrien			    func (stream, "]");
40960484Sobrien			}
41060484Sobrien		      else
41160484Sobrien			{
41260484Sobrien			  int offset = given & 0xff;
41360484Sobrien			  if (offset)
41460484Sobrien			    func (stream, "], %s#%d",
41560484Sobrien				  ((given & 0x00800000) == 0 ? "-" : ""),
41660484Sobrien				  offset * 4);
41760484Sobrien			  else
41860484Sobrien			    func (stream, "]");
41960484Sobrien			}
42060484Sobrien		      break;
42160484Sobrien
42260484Sobrien		    case 'C':
42360484Sobrien		      switch (given & 0x00090000)
42460484Sobrien			{
42560484Sobrien			default:
42660484Sobrien			  func (stream, "_???");
42760484Sobrien			  break;
42860484Sobrien			case 0x90000:
42960484Sobrien			  func (stream, "_all");
43060484Sobrien			  break;
43160484Sobrien			case 0x10000:
43260484Sobrien			  func (stream, "_ctl");
43360484Sobrien			  break;
43460484Sobrien			case 0x80000:
43560484Sobrien			  func (stream, "_flg");
43660484Sobrien			  break;
43760484Sobrien			}
43860484Sobrien		      break;
43960484Sobrien
44060484Sobrien		    case 'F':
44160484Sobrien		      switch (given & 0x00408000)
44260484Sobrien			{
44360484Sobrien			case 0:
44460484Sobrien			  func (stream, "4");
44560484Sobrien			  break;
44660484Sobrien			case 0x8000:
44760484Sobrien			  func (stream, "1");
44860484Sobrien			  break;
44960484Sobrien			case 0x00400000:
45060484Sobrien			  func (stream, "2");
45160484Sobrien			  break;
45260484Sobrien			default:
45360484Sobrien			  func (stream, "3");
45460484Sobrien			}
45560484Sobrien		      break;
45660484Sobrien
45760484Sobrien		    case 'P':
45860484Sobrien		      switch (given & 0x00080080)
45960484Sobrien			{
46060484Sobrien			case 0:
46160484Sobrien			  func (stream, "s");
46260484Sobrien			  break;
46360484Sobrien			case 0x80:
46460484Sobrien			  func (stream, "d");
46560484Sobrien			  break;
46660484Sobrien			case 0x00080000:
46760484Sobrien			  func (stream, "e");
46860484Sobrien			  break;
46960484Sobrien			default:
47060484Sobrien			  func (stream, _("<illegal precision>"));
47160484Sobrien			  break;
47260484Sobrien			}
47360484Sobrien		      break;
47460484Sobrien		    case 'Q':
47560484Sobrien		      switch (given & 0x00408000)
47660484Sobrien			{
47760484Sobrien			case 0:
47860484Sobrien			  func (stream, "s");
47960484Sobrien			  break;
48060484Sobrien			case 0x8000:
48160484Sobrien			  func (stream, "d");
48260484Sobrien			  break;
48360484Sobrien			case 0x00400000:
48460484Sobrien			  func (stream, "e");
48560484Sobrien			  break;
48660484Sobrien			default:
48760484Sobrien			  func (stream, "p");
48860484Sobrien			  break;
48960484Sobrien			}
49060484Sobrien		      break;
49160484Sobrien		    case 'R':
49260484Sobrien		      switch (given & 0x60)
49360484Sobrien			{
49460484Sobrien			case 0:
49560484Sobrien			  break;
49660484Sobrien			case 0x20:
49760484Sobrien			  func (stream, "p");
49860484Sobrien			  break;
49960484Sobrien			case 0x40:
50060484Sobrien			  func (stream, "m");
50160484Sobrien			  break;
50260484Sobrien			default:
50360484Sobrien			  func (stream, "z");
50460484Sobrien			  break;
50560484Sobrien			}
50660484Sobrien		      break;
50760484Sobrien
50860484Sobrien		    case '0': case '1': case '2': case '3': case '4':
50960484Sobrien		    case '5': case '6': case '7': case '8': case '9':
51060484Sobrien		      {
51160484Sobrien			int bitstart = *c++ - '0';
51260484Sobrien			int bitend = 0;
51360484Sobrien			while (*c >= '0' && *c <= '9')
51460484Sobrien			  bitstart = (bitstart * 10) + *c++ - '0';
51560484Sobrien
51660484Sobrien			switch (*c)
51760484Sobrien			  {
51860484Sobrien			  case '-':
51960484Sobrien			    c++;
52060484Sobrien
52160484Sobrien			    while (*c >= '0' && *c <= '9')
52260484Sobrien			      bitend = (bitend * 10) + *c++ - '0';
52360484Sobrien
52460484Sobrien			    if (!bitend)
52560484Sobrien			      abort ();
52660484Sobrien
52760484Sobrien			    switch (*c)
52860484Sobrien			      {
52960484Sobrien			      case 'r':
53060484Sobrien				{
53160484Sobrien				  long reg;
53260484Sobrien
53360484Sobrien				  reg = given >> bitstart;
53460484Sobrien				  reg &= (2 << (bitend - bitstart)) - 1;
53560484Sobrien
53660484Sobrien				  func (stream, "%s", arm_regnames[reg]);
53760484Sobrien				}
53860484Sobrien				break;
53960484Sobrien			      case 'd':
54060484Sobrien				{
54160484Sobrien				  long reg;
54260484Sobrien
54360484Sobrien				  reg = given >> bitstart;
54460484Sobrien				  reg &= (2 << (bitend - bitstart)) - 1;
54560484Sobrien
54660484Sobrien				  func (stream, "%d", reg);
54760484Sobrien				}
54860484Sobrien				break;
54960484Sobrien			      case 'x':
55060484Sobrien				{
55160484Sobrien				  long reg;
55260484Sobrien
55360484Sobrien				  reg = given >> bitstart;
55460484Sobrien				  reg &= (2 << (bitend - bitstart)) - 1;
55560484Sobrien
55660484Sobrien				  func (stream, "0x%08x", reg);
55760484Sobrien
55860484Sobrien				  /* Some SWI instructions have special
55960484Sobrien				     meanings.  */
56060484Sobrien				  if ((given & 0x0fffffff) == 0x0FF00000)
56160484Sobrien				    func (stream, "\t; IMB");
56260484Sobrien				  else if ((given & 0x0fffffff) == 0x0FF00001)
56360484Sobrien				    func (stream, "\t; IMBRange");
56460484Sobrien				}
56560484Sobrien				break;
56660484Sobrien			      case 'X':
56760484Sobrien				{
56860484Sobrien				  long reg;
56960484Sobrien
57060484Sobrien				  reg = given >> bitstart;
57160484Sobrien				  reg &= (2 << (bitend - bitstart)) - 1;
57260484Sobrien
57360484Sobrien				  func (stream, "%01x", reg & 0xf);
57460484Sobrien				}
57560484Sobrien				break;
57660484Sobrien			      case 'f':
57760484Sobrien				{
57860484Sobrien				  long reg;
57960484Sobrien
58060484Sobrien				  reg = given >> bitstart;
58160484Sobrien				  reg &= (2 << (bitend - bitstart)) - 1;
58260484Sobrien
58360484Sobrien				  if (reg > 7)
58460484Sobrien				    func (stream, "#%s",
58560484Sobrien					  arm_fp_const[reg & 7]);
58660484Sobrien				  else
58760484Sobrien				    func (stream, "f%d", reg);
58860484Sobrien				}
58960484Sobrien				break;
59060484Sobrien			      default:
59160484Sobrien				abort ();
59260484Sobrien			      }
59360484Sobrien			    break;
59460484Sobrien
59560484Sobrien			  case '`':
59660484Sobrien			    c++;
59760484Sobrien			    if ((given & (1 << bitstart)) == 0)
59860484Sobrien			      func (stream, "%c", *c);
59960484Sobrien			    break;
60060484Sobrien			  case '\'':
60160484Sobrien			    c++;
60260484Sobrien			    if ((given & (1 << bitstart)) != 0)
60360484Sobrien			      func (stream, "%c", *c);
60460484Sobrien			    break;
60560484Sobrien			  case '?':
60660484Sobrien			    ++c;
60760484Sobrien			    if ((given & (1 << bitstart)) != 0)
60860484Sobrien			      func (stream, "%c", *c++);
60960484Sobrien			    else
61060484Sobrien			      func (stream, "%c", *++c);
61160484Sobrien			    break;
61260484Sobrien			  default:
61360484Sobrien			    abort ();
61460484Sobrien			  }
61560484Sobrien			break;
61660484Sobrien
61760484Sobrien		      default:
61860484Sobrien			abort ();
61960484Sobrien		      }
62060484Sobrien		    }
62160484Sobrien		}
62260484Sobrien	      else
62360484Sobrien		func (stream, "%c", *c);
62460484Sobrien	    }
62560484Sobrien	  return 4;
62660484Sobrien	}
62760484Sobrien    }
62860484Sobrien  abort ();
62960484Sobrien}
63060484Sobrien
63160484Sobrien/* Print one instruction from PC on INFO->STREAM.
63260484Sobrien   Return the size of the instruction. */
63360484Sobrienstatic int
63460484Sobrienprint_insn_thumb (pc, info, given)
63560484Sobrien     bfd_vma                   pc;
63660484Sobrien     struct disassemble_info * info;
63760484Sobrien     long                      given;
63860484Sobrien{
63960484Sobrien  struct thumb_opcode * insn;
64060484Sobrien  void *                stream = info->stream;
64160484Sobrien  fprintf_ftype         func = info->fprintf_func;
64260484Sobrien
64360484Sobrien  for (insn = thumb_opcodes; insn->assembler; insn++)
64460484Sobrien    {
64560484Sobrien      if ((given & insn->mask) == insn->value)
64660484Sobrien        {
64760484Sobrien          char * c = insn->assembler;
64860484Sobrien
64960484Sobrien          /* Special processing for Thumb 2 instruction BL sequence:  */
65060484Sobrien          if (!*c) /* Check for empty (not NULL) assembler string.  */
65160484Sobrien            {
65260484Sobrien	      info->bytes_per_chunk = 4;
65360484Sobrien	      info->bytes_per_line  = 4;
65460484Sobrien
65560484Sobrien                func (stream, "bl\t");
65660484Sobrien
65760484Sobrien              info->print_address_func (BDISP23 (given) * 2 + pc + 4, info);
65860484Sobrien              return 4;
65960484Sobrien            }
66060484Sobrien          else
66160484Sobrien            {
66260484Sobrien	      info->bytes_per_chunk = 2;
66360484Sobrien	      info->bytes_per_line  = 4;
66460484Sobrien
66560484Sobrien              given &= 0xffff;
66660484Sobrien
66760484Sobrien              for (; *c; c++)
66860484Sobrien                {
66960484Sobrien                  if (*c == '%')
67060484Sobrien                    {
67160484Sobrien                      int domaskpc = 0;
67260484Sobrien                      int domasklr = 0;
67360484Sobrien
67460484Sobrien                      switch (*++c)
67560484Sobrien                        {
67660484Sobrien                        case '%':
67760484Sobrien                          func (stream, "%%");
67860484Sobrien                          break;
67960484Sobrien
68060484Sobrien                        case 'S':
68160484Sobrien                          {
68260484Sobrien                            long reg;
68360484Sobrien
68460484Sobrien                            reg = (given >> 3) & 0x7;
68560484Sobrien                            if (given & (1 << 6))
68660484Sobrien                              reg += 8;
68760484Sobrien
68860484Sobrien                            func (stream, "%s", arm_regnames[reg]);
68960484Sobrien                          }
69060484Sobrien                          break;
69160484Sobrien
69260484Sobrien                        case 'D':
69360484Sobrien                          {
69460484Sobrien                            long reg;
69560484Sobrien
69660484Sobrien                            reg = given & 0x7;
69760484Sobrien                            if (given & (1 << 7))
69860484Sobrien                             reg += 8;
69960484Sobrien
70060484Sobrien                            func (stream, "%s", arm_regnames[reg]);
70160484Sobrien                          }
70260484Sobrien                          break;
70360484Sobrien
70460484Sobrien                        case 'T':
70560484Sobrien                          func (stream, "%s",
70660484Sobrien                                arm_conditional [(given >> 8) & 0xf]);
70760484Sobrien                          break;
70860484Sobrien
70960484Sobrien                        case 'N':
71060484Sobrien                          if (given & (1 << 8))
71160484Sobrien                            domasklr = 1;
71260484Sobrien                          /* Fall through.  */
71360484Sobrien                        case 'O':
71460484Sobrien                          if (*c == 'O' && (given & (1 << 8)))
71560484Sobrien                            domaskpc = 1;
71660484Sobrien                          /* Fall through.  */
71760484Sobrien                        case 'M':
71860484Sobrien                          {
71960484Sobrien                            int started = 0;
72060484Sobrien                            int reg;
72160484Sobrien
72260484Sobrien                            func (stream, "{");
72360484Sobrien
72460484Sobrien                            /* It would be nice if we could spot
72560484Sobrien                               ranges, and generate the rS-rE format: */
72660484Sobrien                            for (reg = 0; (reg < 8); reg++)
72760484Sobrien                              if ((given & (1 << reg)) != 0)
72860484Sobrien                                {
72960484Sobrien                                  if (started)
73060484Sobrien                                    func (stream, ", ");
73160484Sobrien                                  started = 1;
73260484Sobrien                                  func (stream, "%s", arm_regnames[reg]);
73360484Sobrien                                }
73460484Sobrien
73560484Sobrien                            if (domasklr)
73660484Sobrien                              {
73760484Sobrien                                if (started)
73860484Sobrien                                  func (stream, ", ");
73960484Sobrien                                started = 1;
74060484Sobrien                                func (stream, arm_regnames[14] /* "lr" */);
74160484Sobrien                              }
74260484Sobrien
74360484Sobrien                            if (domaskpc)
74460484Sobrien                              {
74560484Sobrien                                if (started)
74660484Sobrien                                  func (stream, ", ");
74760484Sobrien                                func (stream, arm_regnames[15] /* "pc" */);
74860484Sobrien                              }
74960484Sobrien
75060484Sobrien                            func (stream, "}");
75160484Sobrien                          }
75260484Sobrien                          break;
75360484Sobrien
75460484Sobrien
75560484Sobrien                        case '0': case '1': case '2': case '3': case '4':
75660484Sobrien                        case '5': case '6': case '7': case '8': case '9':
75760484Sobrien                          {
75860484Sobrien                            int bitstart = *c++ - '0';
75960484Sobrien                            int bitend = 0;
76060484Sobrien
76160484Sobrien                            while (*c >= '0' && *c <= '9')
76260484Sobrien                              bitstart = (bitstart * 10) + *c++ - '0';
76360484Sobrien
76460484Sobrien                            switch (*c)
76560484Sobrien                              {
76660484Sobrien                              case '-':
76760484Sobrien                                {
76860484Sobrien                                  long reg;
76960484Sobrien
77060484Sobrien                                  c++;
77160484Sobrien                                  while (*c >= '0' && *c <= '9')
77260484Sobrien                                    bitend = (bitend * 10) + *c++ - '0';
77360484Sobrien                                  if (!bitend)
77460484Sobrien                                    abort ();
77560484Sobrien                                  reg = given >> bitstart;
77660484Sobrien                                  reg &= (2 << (bitend - bitstart)) - 1;
77760484Sobrien                                  switch (*c)
77860484Sobrien                                    {
77960484Sobrien                                    case 'r':
78060484Sobrien                                      func (stream, "%s", arm_regnames[reg]);
78160484Sobrien                                      break;
78260484Sobrien
78360484Sobrien                                    case 'd':
78460484Sobrien                                      func (stream, "%d", reg);
78560484Sobrien                                      break;
78660484Sobrien
78760484Sobrien                                    case 'H':
78860484Sobrien                                      func (stream, "%d", reg << 1);
78960484Sobrien                                      break;
79060484Sobrien
79160484Sobrien                                    case 'W':
79260484Sobrien                                      func (stream, "%d", reg << 2);
79360484Sobrien                                      break;
79460484Sobrien
79560484Sobrien                                    case 'a':
79660484Sobrien				      /* PC-relative address -- the bottom two
79760484Sobrien					 bits of the address are dropped
79860484Sobrien					 before the calculation.  */
79960484Sobrien                                      info->print_address_func
80060484Sobrien					(((pc + 4) & ~3) + (reg << 2), info);
80160484Sobrien                                      break;
80260484Sobrien
80360484Sobrien                                    case 'x':
80460484Sobrien                                      func (stream, "0x%04x", reg);
80560484Sobrien                                      break;
80660484Sobrien
80760484Sobrien                                    case 'I':
80860484Sobrien                                      reg = ((reg ^ (1 << bitend)) - (1 << bitend));
80960484Sobrien                                      func (stream, "%d", reg);
81060484Sobrien                                      break;
81160484Sobrien
81260484Sobrien                                    case 'B':
81360484Sobrien                                      reg = ((reg ^ (1 << bitend)) - (1 << bitend));
81460484Sobrien                                      (*info->print_address_func)
81560484Sobrien                                        (reg * 2 + pc + 4, info);
81660484Sobrien                                      break;
81760484Sobrien
81860484Sobrien                                    default:
81960484Sobrien                                      abort ();
82060484Sobrien                                    }
82160484Sobrien                                }
82260484Sobrien                                break;
82360484Sobrien
82460484Sobrien                              case '\'':
82560484Sobrien                                c++;
82660484Sobrien                                if ((given & (1 << bitstart)) != 0)
82760484Sobrien                                  func (stream, "%c", *c);
82860484Sobrien                                break;
82960484Sobrien
83060484Sobrien                              case '?':
83160484Sobrien                                ++c;
83260484Sobrien                                if ((given & (1 << bitstart)) != 0)
83360484Sobrien                                  func (stream, "%c", *c++);
83460484Sobrien                                else
83560484Sobrien                                  func (stream, "%c", *++c);
83660484Sobrien                                break;
83760484Sobrien
83860484Sobrien                              default:
83960484Sobrien                                 abort ();
84060484Sobrien                              }
84160484Sobrien                          }
84260484Sobrien                          break;
84360484Sobrien
84460484Sobrien                        default:
84560484Sobrien                          abort ();
84660484Sobrien                        }
84760484Sobrien                    }
84860484Sobrien                  else
84960484Sobrien                    func (stream, "%c", *c);
85060484Sobrien                }
85160484Sobrien             }
85260484Sobrien          return 2;
85360484Sobrien       }
85460484Sobrien    }
85560484Sobrien
85660484Sobrien  /* No match.  */
85760484Sobrien  abort ();
85860484Sobrien}
85960484Sobrien
86060484Sobrien/* Parse an individual disassembler option.  */
86160484Sobrienvoid
86260484Sobrienparse_arm_disassembler_option (option)
86360484Sobrien     char * option;
86460484Sobrien{
86560484Sobrien  if (option == NULL)
86660484Sobrien    return;
86760484Sobrien
86860484Sobrien  if (strneq (option, "reg-names-", 10))
86960484Sobrien    {
87060484Sobrien      int i;
87160484Sobrien
87260484Sobrien      option += 10;
87360484Sobrien
87460484Sobrien      for (i = NUM_ARM_REGNAMES; i--;)
87560484Sobrien	if (streq (option, regnames[i].name))
87660484Sobrien	  {
87760484Sobrien	    regname_selected = i;
87860484Sobrien	    break;
87960484Sobrien	  }
88060484Sobrien
88160484Sobrien      if (i < 0)
88260484Sobrien	fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
88360484Sobrien    }
88460484Sobrien  else if (streq (option, "force-thumb"))
88560484Sobrien    force_thumb = 1;
88660484Sobrien  else if (streq (option, "no-force-thumb"))
88760484Sobrien    force_thumb = 0;
88860484Sobrien  else
88960484Sobrien    fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
89060484Sobrien
89160484Sobrien  return;
89260484Sobrien}
89360484Sobrien
89460484Sobrien/* Parse the string of disassembler options, spliting it at whitespaces.  */
89560484Sobrienstatic void
89660484Sobrienparse_disassembler_options (options)
89760484Sobrien     char * options;
89860484Sobrien{
89960484Sobrien  char * space;
90060484Sobrien
90160484Sobrien  if (options == NULL)
90260484Sobrien    return;
90360484Sobrien
90460484Sobrien  do
90560484Sobrien    {
90660484Sobrien      space = strchr (options, ' ');
90760484Sobrien
90860484Sobrien      if (space)
90960484Sobrien	{
91060484Sobrien	  * space = '\0';
91160484Sobrien	  parse_arm_disassembler_option (options);
91260484Sobrien	  * space = ' ';
91360484Sobrien	  options = space + 1;
91460484Sobrien	}
91560484Sobrien      else
91660484Sobrien	parse_arm_disassembler_option (options);
91760484Sobrien    }
91860484Sobrien  while (space);
91960484Sobrien}
92060484Sobrien
92160484Sobrien/* NOTE: There are no checks in these routines that
92260484Sobrien   the relevant number of data bytes exist.  */
92360484Sobrienstatic int
92460484Sobrienprint_insn (pc, info, little)
92560484Sobrien     bfd_vma pc;
92660484Sobrien     struct disassemble_info * info;
92760484Sobrien     boolean little;
92860484Sobrien{
92960484Sobrien  unsigned char      b[4];
93060484Sobrien  long               given;
93160484Sobrien  int                status;
93260484Sobrien  int                is_thumb;
93360484Sobrien
93460484Sobrien  if (info->disassembler_options)
93560484Sobrien    {
93660484Sobrien      parse_disassembler_options (info->disassembler_options);
93760484Sobrien
93860484Sobrien      /* To avoid repeated parsing of these options, we remove them here.  */
93960484Sobrien      info->disassembler_options = NULL;
94060484Sobrien    }
94160484Sobrien
94260484Sobrien  is_thumb = force_thumb;
94360484Sobrien
94460484Sobrien  if (!is_thumb && info->symbols != NULL)
94560484Sobrien    {
94660484Sobrien      if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
94760484Sobrien	{
94860484Sobrien	  coff_symbol_type * cs;
94960484Sobrien
95060484Sobrien	  cs = coffsymbol (*info->symbols);
95160484Sobrien	  is_thumb = (   cs->native->u.syment.n_sclass == C_THUMBEXT
95260484Sobrien		      || cs->native->u.syment.n_sclass == C_THUMBSTAT
95360484Sobrien		      || cs->native->u.syment.n_sclass == C_THUMBLABEL
95460484Sobrien		      || cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
95560484Sobrien		      || cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
95660484Sobrien	}
95760484Sobrien      else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
95860484Sobrien	{
95960484Sobrien	  elf_symbol_type *  es;
96060484Sobrien	  unsigned int       type;
96160484Sobrien
96260484Sobrien	  es = *(elf_symbol_type **)(info->symbols);
96360484Sobrien	  type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
96460484Sobrien
96560484Sobrien	  is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
96660484Sobrien	}
96760484Sobrien    }
96860484Sobrien
96960484Sobrien  info->bytes_per_chunk = 4;
97060484Sobrien  info->display_endian  = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG;
97160484Sobrien
97260484Sobrien  if (little)
97360484Sobrien    {
97460484Sobrien      status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info);
97560484Sobrien      if (status != 0 && is_thumb)
97660484Sobrien	{
97760484Sobrien	  info->bytes_per_chunk = 2;
97860484Sobrien
97960484Sobrien	  status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
98060484Sobrien	  b[3] = b[2] = 0;
98160484Sobrien	}
98260484Sobrien
98360484Sobrien      if (status != 0)
98460484Sobrien	{
98560484Sobrien	  info->memory_error_func (status, pc, info);
98660484Sobrien	  return -1;
98760484Sobrien	}
98860484Sobrien
98960484Sobrien      given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24);
99060484Sobrien    }
99160484Sobrien  else
99260484Sobrien    {
99360484Sobrien      status = info->read_memory_func
99460484Sobrien	(pc & ~ 0x3, (bfd_byte *) &b[0], 4, info);
99560484Sobrien      if (status != 0)
99660484Sobrien	{
99760484Sobrien	  info->memory_error_func (status, pc, info);
99860484Sobrien	  return -1;
99960484Sobrien	}
100060484Sobrien
100160484Sobrien      if (is_thumb)
100260484Sobrien	{
100360484Sobrien	  if (pc & 0x2)
100460484Sobrien	    {
100560484Sobrien	      given = (b[2] << 8) | b[3];
100660484Sobrien
100760484Sobrien	      status = info->read_memory_func
100860484Sobrien		((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info);
100960484Sobrien	      if (status != 0)
101060484Sobrien		{
101160484Sobrien		  info->memory_error_func (status, pc + 4, info);
101260484Sobrien		  return -1;
101360484Sobrien		}
101460484Sobrien
101560484Sobrien	      given |= (b[0] << 24) | (b[1] << 16);
101660484Sobrien	    }
101760484Sobrien	  else
101860484Sobrien	    given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16);
101960484Sobrien	}
102060484Sobrien      else
102160484Sobrien	given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]);
102260484Sobrien    }
102360484Sobrien
102460484Sobrien  if (is_thumb)
102560484Sobrien    status = print_insn_thumb (pc, info, given);
102660484Sobrien  else
102760484Sobrien    status = print_insn_arm (pc, info, given);
102860484Sobrien
102960484Sobrien  return status;
103060484Sobrien}
103160484Sobrien
103260484Sobrienint
103360484Sobrienprint_insn_big_arm (pc, info)
103460484Sobrien     bfd_vma pc;
103560484Sobrien     struct disassemble_info * info;
103660484Sobrien{
103760484Sobrien  return print_insn (pc, info, false);
103860484Sobrien}
103960484Sobrien
104060484Sobrienint
104160484Sobrienprint_insn_little_arm (pc, info)
104260484Sobrien     bfd_vma pc;
104360484Sobrien     struct disassemble_info * info;
104460484Sobrien{
104560484Sobrien  return print_insn (pc, info, true);
104660484Sobrien}
104760484Sobrien
104860484Sobrienvoid
104960484Sobrienprint_arm_disassembler_options (FILE * stream)
105060484Sobrien{
105160484Sobrien  int i;
105260484Sobrien
105360484Sobrien  fprintf (stream, _("\n\
105460484SobrienThe following ARM specific disassembler options are supported for use with\n\
105560484Sobrienthe -M switch:\n"));
105660484Sobrien
105760484Sobrien  for (i = NUM_ARM_REGNAMES; i--;)
105860484Sobrien    fprintf (stream, "  reg-names-%s %*c%s\n",
105960484Sobrien	     regnames[i].name,
106060484Sobrien	     14 - strlen (regnames[i].name), ' ',
106160484Sobrien	     regnames[i].description);
106260484Sobrien
106360484Sobrien  fprintf (stream, "  force-thumb              Assume all insns are Thumb insns\n");
106460484Sobrien  fprintf (stream, "  no-force-thumb           Examine preceeding label to determine an insn's type\n\n");
106560484Sobrien}
1066