aboutsummaryrefslogtreecommitdiff
path: root/opcodes/arm-dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'opcodes/arm-dis.c')
-rw-r--r--opcodes/arm-dis.c242
1 files changed, 103 insertions, 139 deletions
diff --git a/opcodes/arm-dis.c b/opcodes/arm-dis.c
index e623f92..a1540b7 100644
--- a/opcodes/arm-dis.c
+++ b/opcodes/arm-dis.c
@@ -49,66 +49,57 @@
#define WORD_ADDRESS(pc) ((pc) & ~0x3)
-/* Format of the disassembler control string :
-
+/* Opcode tables: ARM, 16-bit Thumb, 32-bit Thumb. All three are partially
+ ordered: they must be searched linearly from the top to obtain a correct
+ match. */
+
+/* print_insn_arm recognizes the following format control codes:
+
%% %
+
+ %a print address for ldr/str instruction
+ %s print address for ldr/str halfword/signextend instruction
+ %b print branch destination
+ %c print condition code (always bits 28-31)
+ %m print register mask for ldm/stm instruction
+ %o print operand2 (immediate or register + shift)
+ %p print 'p' iff bits 12-15 are 15
+ %t print 't' iff bit 21 set and bit 24 clear
+ %A print address for ldc/stc/ldf/stf instruction
+ %B print arm BLX(1) destination
+ %I print cirrus signed shift immediate: bits 0..3|4..6
+ %C print the PSR sub type.
+ %F print the COUNT field of a LFM/SFM instruction.
+ %P print floating point precision in arithmetic insn
+ %Q print floating point precision in ldf/stf insn
+ %R print floating point rounding mode
+
+ %<bitfield>r print as an ARM register
%<bitfield>d print the bitfield in decimal
+ %<bitfield>W print the bitfield plus one in decimal
%<bitfield>x print the bitfield in hex
%<bitfield>X print the bitfield as 1 hex digit without leading "0x"
- %<bitfield>W print the bitfield plus one in decimal
- %<bitfield>r print as an ARM register
%<bitfield>f print a floating point constant if >7 else a
floating point register
+ %<bitfield>w print as an iWMMXt width field - [bhwd]ss/us
+ %<bitfield>g print as an iWMMXt 64-bit register
+ %<bitfield>G print as an iWMMXt general purpose or control register
+
%<code>y print a single precision VFP reg.
Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
%<code>z print a double precision VFP reg
Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
- %c print condition code (always bits 28-31)
- %P print floating point precision in arithmetic insn
- %Q print floating point precision in ldf/stf insn
- %R print floating point rounding mode
%<bitnum>'c print specified char iff bit is one
%<bitnum>`c print specified char iff bit is zero
%<bitnum>?ab print a if bit is one else print b
- %p print 'p' iff bits 12-15 are 15
- %t print 't' iff bit 21 set and bit 24 clear
- %o print operand2 (immediate or register + shift)
- %a print address for ldr/str instruction
- %s print address for ldr/str halfword/signextend instruction
- %b print branch destination
- %B print arm BLX(1) destination
- %A print address for ldc/stc/ldf/stf instruction
- %m print register mask for ldm/stm instruction
- %C print the PSR sub type.
- %F print the COUNT field of a LFM/SFM instruction.
- %E print the LSB and WIDTH fields of a BFI or BFC instruction.
- %V print the 16-bit immediate field of a MOVT or MOVW instruction.
-IWMMXT specific format options:
- %<bitfield>g print as an iWMMXt 64-bit register
- %<bitfield>G print as an iWMMXt general purpose or control register
- %<bitfield>w print as an iWMMXt width field - [bhwd]ss/us
- %Z print the Immediate of a WSHUFH instruction.
+
%L print as an iWMMXt N/M width field.
- %l like 'A' except use byte offsets for 'B' & 'H' versions
-Thumb specific format options:
- %D print Thumb register (bits 0..2 as high number if bit 7 set)
- %S print Thumb register (bits 3..5 as high number if bit 6 set)
- %<bitfield>I print bitfield as a signed decimal
- (top bit of range being the sign bit)
- %M print Thumb register mask
- %N print Thumb register mask (with LR)
- %O print Thumb register mask (with PC)
- %I print cirrus signed shift immediate: bits 0..3|4..6
- %<bitfield>B print Thumb branch destination (signed displacement)
- %<bitfield>W print (bitfield * 4) as a decimal
- %<bitfield>H print (bitfield * 2) as a decimal
- %<bitfield>a print (bitfield * 4) as a pc-rel offset + decoded symbol
- %<bitfield>c print bitfield as a condition code
- %e print arm SMI operand (bits 0..7,8..19).
- %s print Thumb right-shift immediate (6..10; 0 == 32). */
+ %Z print the Immediate of a WSHUFH instruction.
+ %l like 'A' except use byte offsets for 'B' & 'H' versions.
-/* Note: There is a partial ordering in this table - it must be searched from
- the top to obtain a correct match. */
+ %e print arm SMI operand (bits 0..7,8..19).
+ %E print the LSB and WIDTH fields of a BFI or BFC instruction.
+ %V print the 16-bit immediate field of a MOVT or MOVW instruction. */
static const struct arm_opcode arm_opcodes[] =
{
@@ -632,6 +623,27 @@ static const struct arm_opcode arm_opcodes[] =
{0, 0x00000000, 0x00000000, 0}
};
+/* print_insn_thumb16 recognizes the following format control codes:
+
+ %S print Thumb register (bits 3..5 as high number if bit 6 set)
+ %D print Thumb register (bits 0..2 as high number if bit 7 set)
+ %<bitfield>I print bitfield as a signed decimal
+ (top bit of range being the sign bit)
+ %N print Thumb register mask (with LR)
+ %O print Thumb register mask (with PC)
+ %M print Thumb register mask
+ %b print CZB's 6-bit unsigned branch destination
+ %s print Thumb right-shift immediate (6..10; 0 == 32).
+ %<bitfield>r print bitfield as an ARM register
+ %<bitfield>d print bitfield as a decimal
+ %<bitfield>H print (bitfield * 2) as a decimal
+ %<bitfield>W print (bitfield * 4) as a decimal
+ %<bitfield>a print (bitfield * 4) as a pc-rel offset + decoded symbol
+ %<bitfield>B print Thumb branch destination (signed displacement)
+ %<bitfield>c print bitfield as a condition code
+ %<bitnum>'c print specified char iff bit is one
+ %<bitnum>?ab print a if bit is one else print b. */
+
static const struct thumb_opcode thumb_opcodes[] =
{
/* Thumb instructions. */
@@ -761,17 +773,9 @@ static const struct thumb_opcode thumb_opcodes[] =
We adopt the convention that hw1 is the high 16 bits of .value and
.mask, hw2 the low 16 bits.
- %-escapes defined for these instructions:
+ print_insn_thumb32 recognizes the following format control codes:
%% %
- %<bitfield>d print bitfield in decimal
- %<bitfield>W print bitfield*4 in decimal
- %<bitfield>r print bitfield as an ARM register
- %<bitfield>c print bitfield as a condition code
-
- %<bitnum>'c print "c" iff bit is one
- %<bitnum>`c print "c" iff bit is zero
- %<bitnum>?ab print "a" if bit is one, else "b"
%I print a 12-bit immediate from hw1[10],hw2[14:12,7:0]
%M print a modified 12-bit immediate (same location)
@@ -786,11 +790,20 @@ static const struct thumb_opcode thumb_opcodes[] =
%E print the lsb and width fields of a bfc/bfi instruction
%F print the lsb and width fields of a sbfx/ubfx instruction
- %B print an unconditional branch offset
%b print a conditional branch offset
+ %B print an unconditional branch offset
%s print the shift field of an SSAT instruction
%R print the rotation field of an SXT instruction
+ %<bitfield>d print bitfield in decimal
+ %<bitfield>W print bitfield*4 in decimal
+ %<bitfield>r print bitfield as an ARM register
+ %<bitfield>c print bitfield as a condition code
+
+ %<bitnum>'c print "c" iff bit is one
+ %<bitnum>`c print "c" iff bit is zero
+ %<bitnum>?ab print "a" if bit is one, else "b"
+
With one exception at the bottom (done because BL and BLX(1) need
to come dead last), this table was machine-sorted first in
decreasing order of number of bits set in the mask, then in
@@ -1062,39 +1075,15 @@ static char * arm_fp_const[] =
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_thumb16
- PARAMS ((bfd_vma, struct disassemble_info *, long));
-static int print_insn_thumb32
- PARAMS ((bfd_vma, struct disassemble_info *, long));
-static void parse_disassembler_options
- PARAMS ((char *));
-static int print_insn
- PARAMS ((bfd_vma, struct disassemble_info *, bfd_boolean));
-static int set_iwmmxt_regnames
- PARAMS ((void));
-
-int get_arm_regname_num_options
- PARAMS ((void));
-int set_arm_regname_option
- PARAMS ((int));
-int get_arm_regnames
- PARAMS ((int, const char **, const char **, const char ***));
-
/* Functions. */
int
-get_arm_regname_num_options ()
+get_arm_regname_num_options (void)
{
return NUM_ARM_REGNAMES;
}
int
-set_arm_regname_option (option)
- int option;
+set_arm_regname_option (int option)
{
int old = regname_selected;
regname_selected = option;
@@ -1102,11 +1091,8 @@ set_arm_regname_option (option)
}
int
-get_arm_regnames (option, setname, setdescription, register_names)
- int option;
- const char **setname;
- const char **setdescription;
- const char ***register_names;
+get_arm_regnames (int option, const char **setname, const char **setdescription,
+ const char ***register_names)
{
*setname = regnames[option].name;
*setdescription = regnames[option].description;
@@ -1115,10 +1101,7 @@ get_arm_regnames (option, setname, setdescription, register_names)
}
static void
-arm_decode_shift (given, func, stream)
- long given;
- fprintf_ftype func;
- void * stream;
+arm_decode_shift (long given, fprintf_ftype func, void *stream)
{
func (stream, "%s", arm_regnames[given & 0xf]);
@@ -1149,7 +1132,7 @@ arm_decode_shift (given, func, stream)
}
static int
-set_iwmmxt_regnames ()
+set_iwmmxt_regnames (void)
{
const char * setname;
const char * setdesc;
@@ -1165,15 +1148,11 @@ set_iwmmxt_regnames ()
return iwmmxt_regnames;
}
-
-/* Print one instruction from PC on INFO->STREAM.
- Return the size of the instruction (always 4 on ARM). */
-static int
-print_insn_arm (pc, info, given)
- bfd_vma pc;
- struct disassemble_info *info;
- long given;
+/* Print one ARM instruction from PC on INFO->STREAM. */
+
+static void
+print_insn_arm (bfd_vma pc, struct disassemble_info *info, long given)
{
const struct arm_opcode *insn;
void *stream = info->stream;
@@ -1911,20 +1890,16 @@ print_insn_arm (pc, info, given)
else
func (stream, "%c", *c);
}
- return 4;
+ return;
}
}
abort ();
}
-/* Print one instruction from PC on INFO->STREAM.
- Return the size of the instruction. */
+/* Print one 16-bit Thumb instruction from PC on INFO->STREAM. */
-static int
-print_insn_thumb16 (pc, info, given)
- bfd_vma pc;
- struct disassemble_info *info;
- long given;
+static void
+print_insn_thumb16 (bfd_vma pc, struct disassemble_info *info, long given)
{
const struct thumb_opcode *insn;
void *stream = info->stream;
@@ -2093,11 +2068,6 @@ print_insn_thumb16 (pc, info, given)
func (stream, "0x%04x", reg);
break;
- case 'I':
- reg = ((reg ^ (1 << bitend)) - (1 << bitend));
- func (stream, "%d", reg);
- break;
-
case 'B':
reg = ((reg ^ (1 << bitend)) - (1 << bitend));
(*info->print_address_func)
@@ -2145,18 +2115,17 @@ print_insn_thumb16 (pc, info, given)
abort ();
}
}
- return 2;
+ return;
}
/* No match. */
abort ();
}
-static int
-print_insn_thumb32 (pc, info, given)
- bfd_vma pc;
- struct disassemble_info *info;
- long given;
+/* Print one 32-bit Thumb instruction from PC on INFO->STREAM. */
+
+static void
+print_insn_thumb32 (bfd_vma pc, struct disassemble_info *info, long given)
{
const struct arm_opcode *insn;
void *stream = info->stream;
@@ -2554,7 +2523,7 @@ print_insn_thumb32 (pc, info, given)
abort ();
}
}
- return 4;
+ return;
}
/* No match. */
@@ -2581,8 +2550,7 @@ arm_symbol_is_valid (asymbol * sym,
/* Parse an individual disassembler option. */
void
-parse_arm_disassembler_option (option)
- char * option;
+parse_arm_disassembler_option (char *option)
{
if (option == NULL)
return;
@@ -2619,8 +2587,7 @@ parse_arm_disassembler_option (option)
or commas. (Whitespace separators supported for backwards compatibility). */
static void
-parse_disassembler_options (options)
- char * options;
+parse_disassembler_options (char *options)
{
if (options == NULL)
return;
@@ -2642,16 +2609,14 @@ parse_disassembler_options (options)
the relevant number of data bytes exist. */
static int
-print_insn (pc, info, little)
- bfd_vma pc;
- struct disassemble_info * info;
- bfd_boolean little;
+print_insn (bfd_vma pc, struct disassemble_info *info, bfd_boolean little)
{
unsigned char b[4];
long given;
int status;
int is_thumb;
- int (*printer) (bfd_vma, struct disassemble_info *, long);
+ int size;
+ void (*printer) (bfd_vma, struct disassemble_info *, long);
if (info->disassembler_options)
{
@@ -2697,6 +2662,7 @@ print_insn (pc, info, little)
is four bytes long and is either ordered 0123 or 3210. */
printer = print_insn_arm;
info->bytes_per_chunk = 4;
+ size = 4;
status = info->read_memory_func (pc, (bfd_byte *)b, 4, info);
if (little)
@@ -2710,8 +2676,10 @@ print_insn (pc, info, little)
instruction lengths. Fortunately, the bits that determine
the length of the current instruction are always to be found
in the first two bytes. */
-
+ printer = print_insn_thumb16;
info->bytes_per_chunk = 2;
+ size = 2;
+
status = info->read_memory_func (pc, (bfd_byte *)b, 2, info);
if (!status)
{
@@ -2733,9 +2701,8 @@ print_insn (pc, info, little)
given = (b[1]) | (b[0] << 8) | (given << 16);
printer = print_insn_thumb32;
+ size = 4;
}
- else
- printer = print_insn_thumb16;
}
}
@@ -2752,27 +2719,24 @@ print_insn (pc, info, little)
addresses, since the addend is not currently pc-relative. */
pc = 0;
- return printer (pc, info, given);
+ printer (pc, info, given);
+ return size;
}
int
-print_insn_big_arm (pc, info)
- bfd_vma pc;
- struct disassemble_info * info;
+print_insn_big_arm (bfd_vma pc, struct disassemble_info *info)
{
return print_insn (pc, info, FALSE);
}
int
-print_insn_little_arm (pc, info)
- bfd_vma pc;
- struct disassemble_info * info;
+print_insn_little_arm (bfd_vma pc, struct disassemble_info *info)
{
return print_insn (pc, info, TRUE);
}
void
-print_arm_disassembler_options (FILE * stream)
+print_arm_disassembler_options (FILE *stream)
{
int i;