diff options
Diffstat (limited to 'opcodes/arm-dis.c')
-rw-r--r-- | opcodes/arm-dis.c | 242 |
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; |