root / arm-dis.c @ 67f36560
History | View | Annotate | Download (55.2 kB)
1 |
/* Instruction printing code for the ARM
|
---|---|
2 |
Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
|
3 |
Free Software Foundation, Inc.
|
4 |
Contributed by Richard Earnshaw (rwe@pegasus.esprit.ec.org)
|
5 |
Modification by James G. Smith (jsmith@cygnus.co.uk)
|
6 |
|
7 |
This file is part of libopcodes.
|
8 |
|
9 |
This program is free software; you can redistribute it and/or modify it under
|
10 |
the terms of the GNU General Public License as published by the Free
|
11 |
Software Foundation; either version 2 of the License, or (at your option)
|
12 |
any later version.
|
13 |
|
14 |
This program is distributed in the hope that it will be useful, but WITHOUT
|
15 |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
16 |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
17 |
more details.
|
18 |
|
19 |
You should have received a copy of the GNU General Public License
|
20 |
along with this program; if not, write to the Free Software
|
21 |
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
22 |
|
23 |
#include "dis-asm.h" |
24 |
|
25 |
struct arm_opcode {
|
26 |
unsigned long value, mask; /* recognise instruction if (op&mask)==value */ |
27 |
char *assembler; /* how to disassemble this instruction */ |
28 |
}; |
29 |
|
30 |
struct thumb_opcode
|
31 |
{ |
32 |
unsigned short value, mask; /* recognise instruction if (op&mask)==value */ |
33 |
char * assembler; /* how to disassemble this instruction */ |
34 |
}; |
35 |
|
36 |
/* format of the assembler string :
|
37 |
|
38 |
%% %
|
39 |
%<bitfield>d print the bitfield in decimal
|
40 |
%<bitfield>x print the bitfield in hex
|
41 |
%<bitfield>X print the bitfield as 1 hex digit without leading "0x"
|
42 |
%<bitfield>r print as an ARM register
|
43 |
%<bitfield>f print a floating point constant if >7 else a
|
44 |
floating point register
|
45 |
%<code>y print a single precision VFP reg.
|
46 |
Codes: 0=>Sm, 1=>Sd, 2=>Sn, 3=>multi-list, 4=>Sm pair
|
47 |
%<code>z print a double precision VFP reg
|
48 |
Codes: 0=>Dm, 1=>Dd, 2=>Dn, 3=>multi-list
|
49 |
%c print condition code (always bits 28-31)
|
50 |
%P print floating point precision in arithmetic insn
|
51 |
%Q print floating point precision in ldf/stf insn
|
52 |
%R print floating point rounding mode
|
53 |
%<bitnum>'c print specified char iff bit is one
|
54 |
%<bitnum>`c print specified char iff bit is zero
|
55 |
%<bitnum>?ab print a if bit is one else print b
|
56 |
%p print 'p' iff bits 12-15 are 15
|
57 |
%t print 't' iff bit 21 set and bit 24 clear
|
58 |
%o print operand2 (immediate or register + shift)
|
59 |
%a print address for ldr/str instruction
|
60 |
%s print address for ldr/str halfword/signextend instruction
|
61 |
%b print branch destination
|
62 |
%B print arm BLX(1) destination
|
63 |
%A print address for ldc/stc/ldf/stf instruction
|
64 |
%m print register mask for ldm/stm instruction
|
65 |
%C print the PSR sub type.
|
66 |
%F print the COUNT field of a LFM/SFM instruction.
|
67 |
Thumb specific format options:
|
68 |
%D print Thumb register (bits 0..2 as high number if bit 7 set)
|
69 |
%S print Thumb register (bits 3..5 as high number if bit 6 set)
|
70 |
%<bitfield>I print bitfield as a signed decimal
|
71 |
(top bit of range being the sign bit)
|
72 |
%M print Thumb register mask
|
73 |
%N print Thumb register mask (with LR)
|
74 |
%O print Thumb register mask (with PC)
|
75 |
%T print Thumb condition code (always bits 8-11)
|
76 |
%I print cirrus signed shift immediate: bits 0..3|4..6
|
77 |
%<bitfield>B print Thumb branch destination (signed displacement)
|
78 |
%<bitfield>W print (bitfield * 4) as a decimal
|
79 |
%<bitfield>H print (bitfield * 2) as a decimal
|
80 |
%<bitfield>a print (bitfield * 4) as a pc-rel offset + decoded symbol
|
81 |
*/
|
82 |
|
83 |
/* Note: There is a partial ordering in this table - it must be searched from
|
84 |
the top to obtain a correct match. */
|
85 |
|
86 |
static struct arm_opcode arm_opcodes[] = |
87 |
{ |
88 |
/* ARM instructions. */
|
89 |
{0xe1a00000, 0xffffffff, "nop\t\t\t(mov r0,r0)"}, |
90 |
{0x012FFF10, 0x0ffffff0, "bx%c\t%0-3r"}, |
91 |
{0x00000090, 0x0fe000f0, "mul%c%20's\t%16-19r, %0-3r, %8-11r"}, |
92 |
{0x00200090, 0x0fe000f0, "mla%c%20's\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
93 |
{0x01000090, 0x0fb00ff0, "swp%c%22'b\t%12-15r, %0-3r, [%16-19r]"}, |
94 |
{0x00800090, 0x0fa000f0, "%22?sumull%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
95 |
{0x00a00090, 0x0fa000f0, "%22?sumlal%c%20's\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
96 |
|
97 |
/* V5J instruction. */
|
98 |
{0x012fff20, 0x0ffffff0, "bxj%c\t%0-3r"}, |
99 |
|
100 |
/* XScale instructions. */
|
101 |
{0x0e200010, 0x0fff0ff0, "mia%c\tacc0, %0-3r, %12-15r"}, |
102 |
{0x0e280010, 0x0fff0ff0, "miaph%c\tacc0, %0-3r, %12-15r"}, |
103 |
{0x0e2c0010, 0x0ffc0ff0, "mia%17'T%17`B%16'T%16`B%c\tacc0, %0-3r, %12-15r"}, |
104 |
{0x0c400000, 0x0ff00fff, "mar%c\tacc0, %12-15r, %16-19r"}, |
105 |
{0x0c500000, 0x0ff00fff, "mra%c\t%12-15r, %16-19r, acc0"}, |
106 |
{0xf450f000, 0xfc70f000, "pld\t%a"}, |
107 |
|
108 |
/* V5 Instructions. */
|
109 |
{0xe1200070, 0xfff000f0, "bkpt\t0x%16-19X%12-15X%8-11X%0-3X"}, |
110 |
{0xfa000000, 0xfe000000, "blx\t%B"}, |
111 |
{0x012fff30, 0x0ffffff0, "blx%c\t%0-3r"}, |
112 |
{0x016f0f10, 0x0fff0ff0, "clz%c\t%12-15r, %0-3r"}, |
113 |
{0xfc100000, 0xfe100000, "ldc2%22'l\t%8-11d, cr%12-15d, %A"}, |
114 |
{0xfc000000, 0xfe100000, "stc2%22'l\t%8-11d, cr%12-15d, %A"}, |
115 |
{0xfe000000, 0xff000010, "cdp2\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, |
116 |
{0xfe000010, 0xff100010, "mcr2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, |
117 |
{0xfe100010, 0xff100010, "mrc2\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, |
118 |
|
119 |
/* V5E "El Segundo" Instructions. */
|
120 |
{0x000000d0, 0x0e1000f0, "ldr%cd\t%12-15r, %s"}, |
121 |
{0x000000f0, 0x0e1000f0, "str%cd\t%12-15r, %s"}, |
122 |
{0x01000080, 0x0ff000f0, "smlabb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
123 |
{0x010000a0, 0x0ff000f0, "smlatb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
124 |
{0x010000c0, 0x0ff000f0, "smlabt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
125 |
{0x010000e0, 0x0ff000f0, "smlatt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
126 |
|
127 |
{0x01200080, 0x0ff000f0, "smlawb%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
128 |
{0x012000c0, 0x0ff000f0, "smlawt%c\t%16-19r, %0-3r, %8-11r, %12-15r"}, |
129 |
|
130 |
{0x01400080, 0x0ff000f0, "smlalbb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
131 |
{0x014000a0, 0x0ff000f0, "smlaltb%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
132 |
{0x014000c0, 0x0ff000f0, "smlalbt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
133 |
{0x014000e0, 0x0ff000f0, "smlaltt%c\t%12-15r, %16-19r, %0-3r, %8-11r"}, |
134 |
|
135 |
{0x01600080, 0x0ff0f0f0, "smulbb%c\t%16-19r, %0-3r, %8-11r"}, |
136 |
{0x016000a0, 0x0ff0f0f0, "smultb%c\t%16-19r, %0-3r, %8-11r"}, |
137 |
{0x016000c0, 0x0ff0f0f0, "smulbt%c\t%16-19r, %0-3r, %8-11r"}, |
138 |
{0x016000e0, 0x0ff0f0f0, "smultt%c\t%16-19r, %0-3r, %8-11r"}, |
139 |
|
140 |
{0x012000a0, 0x0ff0f0f0, "smulwb%c\t%16-19r, %0-3r, %8-11r"}, |
141 |
{0x012000e0, 0x0ff0f0f0, "smulwt%c\t%16-19r, %0-3r, %8-11r"}, |
142 |
|
143 |
{0x01000050, 0x0ff00ff0, "qadd%c\t%12-15r, %0-3r, %16-19r"}, |
144 |
{0x01400050, 0x0ff00ff0, "qdadd%c\t%12-15r, %0-3r, %16-19r"}, |
145 |
{0x01200050, 0x0ff00ff0, "qsub%c\t%12-15r, %0-3r, %16-19r"}, |
146 |
{0x01600050, 0x0ff00ff0, "qdsub%c\t%12-15r, %0-3r, %16-19r"}, |
147 |
|
148 |
{0x0c400000, 0x0ff00000, "mcrr%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, |
149 |
{0x0c500000, 0x0ff00000, "mrrc%c\t%8-11d, %4-7d, %12-15r, %16-19r, cr%0-3d"}, |
150 |
|
151 |
/* ARM Instructions. */
|
152 |
{0x00000090, 0x0e100090, "str%c%6's%5?hb\t%12-15r, %s"}, |
153 |
{0x00100090, 0x0e100090, "ldr%c%6's%5?hb\t%12-15r, %s"}, |
154 |
{0x00000000, 0x0de00000, "and%c%20's\t%12-15r, %16-19r, %o"}, |
155 |
{0x00200000, 0x0de00000, "eor%c%20's\t%12-15r, %16-19r, %o"}, |
156 |
{0x00400000, 0x0de00000, "sub%c%20's\t%12-15r, %16-19r, %o"}, |
157 |
{0x00600000, 0x0de00000, "rsb%c%20's\t%12-15r, %16-19r, %o"}, |
158 |
{0x00800000, 0x0de00000, "add%c%20's\t%12-15r, %16-19r, %o"}, |
159 |
{0x00a00000, 0x0de00000, "adc%c%20's\t%12-15r, %16-19r, %o"}, |
160 |
{0x00c00000, 0x0de00000, "sbc%c%20's\t%12-15r, %16-19r, %o"}, |
161 |
{0x00e00000, 0x0de00000, "rsc%c%20's\t%12-15r, %16-19r, %o"}, |
162 |
{0x0120f000, 0x0db0f000, "msr%c\t%22?SCPSR%C, %o"}, |
163 |
{0x010f0000, 0x0fbf0fff, "mrs%c\t%12-15r, %22?SCPSR"}, |
164 |
{0x01000000, 0x0de00000, "tst%c%p\t%16-19r, %o"}, |
165 |
{0x01200000, 0x0de00000, "teq%c%p\t%16-19r, %o"}, |
166 |
{0x01400000, 0x0de00000, "cmp%c%p\t%16-19r, %o"}, |
167 |
{0x01600000, 0x0de00000, "cmn%c%p\t%16-19r, %o"}, |
168 |
{0x01800000, 0x0de00000, "orr%c%20's\t%12-15r, %16-19r, %o"}, |
169 |
{0x01a00000, 0x0de00000, "mov%c%20's\t%12-15r, %o"}, |
170 |
{0x01c00000, 0x0de00000, "bic%c%20's\t%12-15r, %16-19r, %o"}, |
171 |
{0x01e00000, 0x0de00000, "mvn%c%20's\t%12-15r, %o"}, |
172 |
{0x04000000, 0x0e100000, "str%c%22'b%t\t%12-15r, %a"}, |
173 |
{0x06000000, 0x0e100ff0, "str%c%22'b%t\t%12-15r, %a"}, |
174 |
{0x04000000, 0x0c100010, "str%c%22'b%t\t%12-15r, %a"}, |
175 |
{0x06000010, 0x0e000010, "undefined"}, |
176 |
{0x04100000, 0x0c100000, "ldr%c%22'b%t\t%12-15r, %a"}, |
177 |
{0x08000000, 0x0e100000, "stm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"}, |
178 |
{0x08100000, 0x0e100000, "ldm%c%23?id%24?ba\t%16-19r%21'!, %m%22'^"}, |
179 |
{0x0a000000, 0x0e000000, "b%24'l%c\t%b"}, |
180 |
{0x0f000000, 0x0f000000, "swi%c\t%0-23x"}, |
181 |
|
182 |
/* Floating point coprocessor (FPA) instructions */
|
183 |
{0x0e000100, 0x0ff08f10, "adf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
184 |
{0x0e100100, 0x0ff08f10, "muf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
185 |
{0x0e200100, 0x0ff08f10, "suf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
186 |
{0x0e300100, 0x0ff08f10, "rsf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
187 |
{0x0e400100, 0x0ff08f10, "dvf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
188 |
{0x0e500100, 0x0ff08f10, "rdf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
189 |
{0x0e600100, 0x0ff08f10, "pow%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
190 |
{0x0e700100, 0x0ff08f10, "rpw%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
191 |
{0x0e800100, 0x0ff08f10, "rmf%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
192 |
{0x0e900100, 0x0ff08f10, "fml%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
193 |
{0x0ea00100, 0x0ff08f10, "fdv%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
194 |
{0x0eb00100, 0x0ff08f10, "frd%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
195 |
{0x0ec00100, 0x0ff08f10, "pol%c%P%R\t%12-14f, %16-18f, %0-3f"}, |
196 |
{0x0e008100, 0x0ff08f10, "mvf%c%P%R\t%12-14f, %0-3f"}, |
197 |
{0x0e108100, 0x0ff08f10, "mnf%c%P%R\t%12-14f, %0-3f"}, |
198 |
{0x0e208100, 0x0ff08f10, "abs%c%P%R\t%12-14f, %0-3f"}, |
199 |
{0x0e308100, 0x0ff08f10, "rnd%c%P%R\t%12-14f, %0-3f"}, |
200 |
{0x0e408100, 0x0ff08f10, "sqt%c%P%R\t%12-14f, %0-3f"}, |
201 |
{0x0e508100, 0x0ff08f10, "log%c%P%R\t%12-14f, %0-3f"}, |
202 |
{0x0e608100, 0x0ff08f10, "lgn%c%P%R\t%12-14f, %0-3f"}, |
203 |
{0x0e708100, 0x0ff08f10, "exp%c%P%R\t%12-14f, %0-3f"}, |
204 |
{0x0e808100, 0x0ff08f10, "sin%c%P%R\t%12-14f, %0-3f"}, |
205 |
{0x0e908100, 0x0ff08f10, "cos%c%P%R\t%12-14f, %0-3f"}, |
206 |
{0x0ea08100, 0x0ff08f10, "tan%c%P%R\t%12-14f, %0-3f"}, |
207 |
{0x0eb08100, 0x0ff08f10, "asn%c%P%R\t%12-14f, %0-3f"}, |
208 |
{0x0ec08100, 0x0ff08f10, "acs%c%P%R\t%12-14f, %0-3f"}, |
209 |
{0x0ed08100, 0x0ff08f10, "atn%c%P%R\t%12-14f, %0-3f"}, |
210 |
{0x0ee08100, 0x0ff08f10, "urd%c%P%R\t%12-14f, %0-3f"}, |
211 |
{0x0ef08100, 0x0ff08f10, "nrm%c%P%R\t%12-14f, %0-3f"}, |
212 |
{0x0e000110, 0x0ff00f1f, "flt%c%P%R\t%16-18f, %12-15r"}, |
213 |
{0x0e100110, 0x0fff0f98, "fix%c%R\t%12-15r, %0-2f"}, |
214 |
{0x0e200110, 0x0fff0fff, "wfs%c\t%12-15r"}, |
215 |
{0x0e300110, 0x0fff0fff, "rfs%c\t%12-15r"}, |
216 |
{0x0e400110, 0x0fff0fff, "wfc%c\t%12-15r"}, |
217 |
{0x0e500110, 0x0fff0fff, "rfc%c\t%12-15r"}, |
218 |
{0x0e90f110, 0x0ff8fff0, "cmf%c\t%16-18f, %0-3f"}, |
219 |
{0x0eb0f110, 0x0ff8fff0, "cnf%c\t%16-18f, %0-3f"}, |
220 |
{0x0ed0f110, 0x0ff8fff0, "cmfe%c\t%16-18f, %0-3f"}, |
221 |
{0x0ef0f110, 0x0ff8fff0, "cnfe%c\t%16-18f, %0-3f"}, |
222 |
{0x0c000100, 0x0e100f00, "stf%c%Q\t%12-14f, %A"}, |
223 |
{0x0c100100, 0x0e100f00, "ldf%c%Q\t%12-14f, %A"}, |
224 |
{0x0c000200, 0x0e100f00, "sfm%c\t%12-14f, %F, %A"}, |
225 |
{0x0c100200, 0x0e100f00, "lfm%c\t%12-14f, %F, %A"}, |
226 |
|
227 |
/* Floating point coprocessor (VFP) instructions */
|
228 |
{0x0eb00bc0, 0x0fff0ff0, "fabsd%c\t%1z, %0z"}, |
229 |
{0x0eb00ac0, 0x0fbf0fd0, "fabss%c\t%1y, %0y"}, |
230 |
{0x0e300b00, 0x0ff00ff0, "faddd%c\t%1z, %2z, %0z"}, |
231 |
{0x0e300a00, 0x0fb00f50, "fadds%c\t%1y, %2y, %1y"}, |
232 |
{0x0eb40b40, 0x0fff0f70, "fcmp%7'ed%c\t%1z, %0z"}, |
233 |
{0x0eb40a40, 0x0fbf0f50, "fcmp%7'es%c\t%1y, %0y"}, |
234 |
{0x0eb50b40, 0x0fff0f70, "fcmp%7'ezd%c\t%1z"}, |
235 |
{0x0eb50a40, 0x0fbf0f70, "fcmp%7'ezs%c\t%1y"}, |
236 |
{0x0eb00b40, 0x0fff0ff0, "fcpyd%c\t%1z, %0z"}, |
237 |
{0x0eb00a40, 0x0fbf0fd0, "fcpys%c\t%1y, %0y"}, |
238 |
{0x0eb70ac0, 0x0fff0fd0, "fcvtds%c\t%1z, %0y"}, |
239 |
{0x0eb70bc0, 0x0fbf0ff0, "fcvtsd%c\t%1y, %0z"}, |
240 |
{0x0e800b00, 0x0ff00ff0, "fdivd%c\t%1z, %2z, %0z"}, |
241 |
{0x0e800a00, 0x0fb00f50, "fdivs%c\t%1y, %2y, %0y"}, |
242 |
{0x0d100b00, 0x0f700f00, "fldd%c\t%1z, %A"}, |
243 |
{0x0c900b00, 0x0fd00f00, "fldmia%0?xd%c\t%16-19r%21'!, %3z"}, |
244 |
{0x0d300b00, 0x0ff00f00, "fldmdb%0?xd%c\t%16-19r!, %3z"}, |
245 |
{0x0d100a00, 0x0f300f00, "flds%c\t%1y, %A"}, |
246 |
{0x0c900a00, 0x0f900f00, "fldmias%c\t%16-19r%21'!, %3y"}, |
247 |
{0x0d300a00, 0x0fb00f00, "fldmdbs%c\t%16-19r!, %3y"}, |
248 |
{0x0e000b00, 0x0ff00ff0, "fmacd%c\t%1z, %2z, %0z"}, |
249 |
{0x0e000a00, 0x0fb00f50, "fmacs%c\t%1y, %2y, %0y"}, |
250 |
{0x0e200b10, 0x0ff00fff, "fmdhr%c\t%2z, %12-15r"}, |
251 |
{0x0e000b10, 0x0ff00fff, "fmdlr%c\t%2z, %12-15r"}, |
252 |
{0x0c400b10, 0x0ff00ff0, "fmdrr%c\t%0z, %12-15r, %16-19r"}, |
253 |
{0x0e300b10, 0x0ff00fff, "fmrdh%c\t%12-15r, %2z"}, |
254 |
{0x0e100b10, 0x0ff00fff, "fmrdl%c\t%12-15r, %2z"}, |
255 |
{0x0c500b10, 0x0ff00ff0, "fmrrd%c\t%12-15r, %16-19r, %0z"}, |
256 |
{0x0c500a10, 0x0ff00fd0, "fmrrs%c\t%12-15r, %16-19r, %4y"}, |
257 |
{0x0e100a10, 0x0ff00f7f, "fmrs%c\t%12-15r, %2y"}, |
258 |
{0x0ef1fa10, 0x0fffffff, "fmstat%c"}, |
259 |
{0x0ef00a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpsid"}, |
260 |
{0x0ef10a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpscr"}, |
261 |
{0x0ef80a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpexc"}, |
262 |
{0x0ef90a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst\t@ Impl def"}, |
263 |
{0x0efa0a10, 0x0fff0fff, "fmrx%c\t%12-15r, fpinst2\t@ Impl def"}, |
264 |
{0x0ef00a10, 0x0ff00fff, "fmrx%c\t%12-15r, <impl def 0x%16-19x>"}, |
265 |
{0x0e100b00, 0x0ff00ff0, "fmscd%c\t%1z, %2z, %0z"}, |
266 |
{0x0e100a00, 0x0fb00f50, "fmscs%c\t%1y, %2y, %0y"}, |
267 |
{0x0e000a10, 0x0ff00f7f, "fmsr%c\t%2y, %12-15r"}, |
268 |
{0x0c400a10, 0x0ff00fd0, "fmsrr%c\t%12-15r, %16-19r, %4y"}, |
269 |
{0x0e200b00, 0x0ff00ff0, "fmuld%c\t%1z, %2z, %0z"}, |
270 |
{0x0e200a00, 0x0fb00f50, "fmuls%c\t%1y, %2y, %0y"}, |
271 |
{0x0ee00a10, 0x0fff0fff, "fmxr%c\tfpsid, %12-15r"}, |
272 |
{0x0ee10a10, 0x0fff0fff, "fmxr%c\tfpscr, %12-15r"}, |
273 |
{0x0ee80a10, 0x0fff0fff, "fmxr%c\tfpexc, %12-15r"}, |
274 |
{0x0ee90a10, 0x0fff0fff, "fmxr%c\tfpinst, %12-15r\t@ Impl def"}, |
275 |
{0x0eea0a10, 0x0fff0fff, "fmxr%c\tfpinst2, %12-15r\t@ Impl def"}, |
276 |
{0x0ee00a10, 0x0ff00fff, "fmxr%c\t<impl def 0x%16-19x>, %12-15r"}, |
277 |
{0x0eb10b40, 0x0fff0ff0, "fnegd%c\t%1z, %0z"}, |
278 |
{0x0eb10a40, 0x0fbf0fd0, "fnegs%c\t%1y, %0y"}, |
279 |
{0x0e000b40, 0x0ff00ff0, "fnmacd%c\t%1z, %2z, %0z"}, |
280 |
{0x0e000a40, 0x0fb00f50, "fnmacs%c\t%1y, %2y, %0y"}, |
281 |
{0x0e100b40, 0x0ff00ff0, "fnmscd%c\t%1z, %2z, %0z"}, |
282 |
{0x0e100a40, 0x0fb00f50, "fnmscs%c\t%1y, %2y, %0y"}, |
283 |
{0x0e200b40, 0x0ff00ff0, "fnmuld%c\t%1z, %2z, %0z"}, |
284 |
{0x0e200a40, 0x0fb00f50, "fnmuls%c\t%1y, %2y, %0y"}, |
285 |
{0x0eb80bc0, 0x0fff0fd0, "fsitod%c\t%1z, %0y"}, |
286 |
{0x0eb80ac0, 0x0fbf0fd0, "fsitos%c\t%1y, %0y"}, |
287 |
{0x0eb10bc0, 0x0fff0ff0, "fsqrtd%c\t%1z, %0z"}, |
288 |
{0x0eb10ac0, 0x0fbf0fd0, "fsqrts%c\t%1y, %0y"}, |
289 |
{0x0d000b00, 0x0f700f00, "fstd%c\t%1z, %A"}, |
290 |
{0x0c800b00, 0x0fd00f00, "fstmia%0?xd%c\t%16-19r%21'!, %3z"}, |
291 |
{0x0d200b00, 0x0ff00f00, "fstmdb%0?xd%c\t%16-19r!, %3z"}, |
292 |
{0x0d000a00, 0x0f300f00, "fsts%c\t%1y, %A"}, |
293 |
{0x0c800a00, 0x0f900f00, "fstmias%c\t%16-19r%21'!, %3y"}, |
294 |
{0x0d200a00, 0x0fb00f00, "fstmdbs%c\t%16-19r!, %3y"}, |
295 |
{0x0e300b40, 0x0ff00ff0, "fsubd%c\t%1z, %2z, %0z"}, |
296 |
{0x0e300a40, 0x0fb00f50, "fsubs%c\t%1y, %2y, %0y"}, |
297 |
{0x0ebc0b40, 0x0fbe0f70, "fto%16?sui%7'zd%c\t%1y, %0z"}, |
298 |
{0x0ebc0a40, 0x0fbe0f50, "fto%16?sui%7'zs%c\t%1y, %0y"}, |
299 |
{0x0eb80b40, 0x0fff0fd0, "fuitod%c\t%1z, %0y"}, |
300 |
{0x0eb80a40, 0x0fbf0fd0, "fuitos%c\t%1y, %0y"}, |
301 |
|
302 |
/* Cirrus coprocessor instructions. */
|
303 |
{0x0d100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, |
304 |
{0x0c100400, 0x0f500f00, "cfldrs%c\tmvf%12-15d, %A"}, |
305 |
{0x0d500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, |
306 |
{0x0c500400, 0x0f500f00, "cfldrd%c\tmvd%12-15d, %A"}, |
307 |
{0x0d100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, |
308 |
{0x0c100500, 0x0f500f00, "cfldr32%c\tmvfx%12-15d, %A"}, |
309 |
{0x0d500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, |
310 |
{0x0c500500, 0x0f500f00, "cfldr64%c\tmvdx%12-15d, %A"}, |
311 |
{0x0d000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, |
312 |
{0x0c000400, 0x0f500f00, "cfstrs%c\tmvf%12-15d, %A"}, |
313 |
{0x0d400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, |
314 |
{0x0c400400, 0x0f500f00, "cfstrd%c\tmvd%12-15d, %A"}, |
315 |
{0x0d000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, |
316 |
{0x0c000500, 0x0f500f00, "cfstr32%c\tmvfx%12-15d, %A"}, |
317 |
{0x0d400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, |
318 |
{0x0c400500, 0x0f500f00, "cfstr64%c\tmvdx%12-15d, %A"}, |
319 |
{0x0e000450, 0x0ff00ff0, "cfmvsr%c\tmvf%16-19d, %12-15r"}, |
320 |
{0x0e100450, 0x0ff00ff0, "cfmvrs%c\t%12-15r, mvf%16-19d"}, |
321 |
{0x0e000410, 0x0ff00ff0, "cfmvdlr%c\tmvd%16-19d, %12-15r"}, |
322 |
{0x0e100410, 0x0ff00ff0, "cfmvrdl%c\t%12-15r, mvd%16-19d"}, |
323 |
{0x0e000430, 0x0ff00ff0, "cfmvdhr%c\tmvd%16-19d, %12-15r"}, |
324 |
{0x0e100430, 0x0ff00fff, "cfmvrdh%c\t%12-15r, mvd%16-19d"}, |
325 |
{0x0e000510, 0x0ff00fff, "cfmv64lr%c\tmvdx%16-19d, %12-15r"}, |
326 |
{0x0e100510, 0x0ff00fff, "cfmvr64l%c\t%12-15r, mvdx%16-19d"}, |
327 |
{0x0e000530, 0x0ff00fff, "cfmv64hr%c\tmvdx%16-19d, %12-15r"}, |
328 |
{0x0e100530, 0x0ff00fff, "cfmvr64h%c\t%12-15r, mvdx%16-19d"}, |
329 |
{0x0e100610, 0x0ff0fff0, "cfmval32%c\tmvax%0-3d, mvfx%16-19d"}, |
330 |
{0x0e000610, 0x0ff0fff0, "cfmv32al%c\tmvfx%0-3d, mvax%16-19d"}, |
331 |
{0x0e100630, 0x0ff0fff0, "cfmvam32%c\tmvax%0-3d, mvfx%16-19d"}, |
332 |
{0x0e000630, 0x0ff0fff0, "cfmv32am%c\tmvfx%0-3d, mvax%16-19d"}, |
333 |
{0x0e100650, 0x0ff0fff0, "cfmvah32%c\tmvax%0-3d, mvfx%16-19d"}, |
334 |
{0x0e000650, 0x0ff0fff0, "cfmv32ah%c\tmvfx%0-3d, mvax%16-19d"}, |
335 |
{0x0e000670, 0x0ff0fff0, "cfmv32a%c\tmvfx%0-3d, mvax%16-19d"}, |
336 |
{0x0e100670, 0x0ff0fff0, "cfmva32%c\tmvax%0-3d, mvfx%16-19d"}, |
337 |
{0x0e000690, 0x0ff0fff0, "cfmv64a%c\tmvdx%0-3d, mvax%16-19d"}, |
338 |
{0x0e100690, 0x0ff0fff0, "cfmva64%c\tmvax%0-3d, mvdx%16-19d"}, |
339 |
{0x0e1006b0, 0x0ff0fff0, "cfmvsc32%c\tdspsc, mvfx%16-19d"}, |
340 |
{0x0e0006b0, 0x0ff0fff0, "cfmv32sc%c\tmvfx%0-3d, dspsc"}, |
341 |
{0x0e000400, 0x0ff00fff, "cfcpys%c\tmvf%12-15d, mvf%16-19d"}, |
342 |
{0x0e000420, 0x0ff00fff, "cfcpyd%c\tmvd%12-15d, mvd%16-19d"}, |
343 |
{0x0e000460, 0x0ff00fff, "cfcvtsd%c\tmvd%12-15d, mvf%16-19d"}, |
344 |
{0x0e000440, 0x0ff00fff, "cfcvtds%c\tmvf%12-15d, mvd%16-19d"}, |
345 |
{0x0e000480, 0x0ff00fff, "cfcvt32s%c\tmvf%12-15d, mvfx%16-19d"}, |
346 |
{0x0e0004a0, 0x0ff00fff, "cfcvt32d%c\tmvd%12-15d, mvfx%16-19d"}, |
347 |
{0x0e0004c0, 0x0ff00fff, "cfcvt64s%c\tmvf%12-15d, mvdx%16-19d"}, |
348 |
{0x0e0004e0, 0x0ff00fff, "cfcvt64d%c\tmvd%12-15d, mvdx%16-19d"}, |
349 |
{0x0e100580, 0x0ff00fff, "cfcvts32%c\tmvfx%12-15d, mvf%16-19d"}, |
350 |
{0x0e1005a0, 0x0ff00fff, "cfcvtd32%c\tmvfx%12-15d, mvd%16-19d"}, |
351 |
{0x0e1005c0, 0x0ff00fff, "cftruncs32%c\tmvfx%12-15d, mvf%16-19d"}, |
352 |
{0x0e1005e0, 0x0ff00fff, "cftruncd32%c\tmvfx%12-15d, mvd%16-19d"}, |
353 |
{0x0e000550, 0x0ff00ff0, "cfrshl32%c\tmvfx%16-19d, mvfx%0-3d, %12-15r"}, |
354 |
{0x0e000570, 0x0ff00ff0, "cfrshl64%c\tmvdx%16-19d, mvdx%0-3d, %12-15r"}, |
355 |
{0x0e000500, 0x0ff00f00, "cfsh32%c\tmvfx%12-15d, mvfx%16-19d, #%I"}, |
356 |
{0x0e200500, 0x0ff00f00, "cfsh64%c\tmvdx%12-15d, mvdx%16-19d, #%I"}, |
357 |
{0x0e100490, 0x0ff00ff0, "cfcmps%c\t%12-15r, mvf%16-19d, mvf%0-3d"}, |
358 |
{0x0e1004b0, 0x0ff00ff0, "cfcmpd%c\t%12-15r, mvd%16-19d, mvd%0-3d"}, |
359 |
{0x0e100590, 0x0ff00ff0, "cfcmp32%c\t%12-15r, mvfx%16-19d, mvfx%0-3d"}, |
360 |
{0x0e1005b0, 0x0ff00ff0, "cfcmp64%c\t%12-15r, mvdx%16-19d, mvdx%0-3d"}, |
361 |
{0x0e300400, 0x0ff00fff, "cfabss%c\tmvf%12-15d, mvf%16-19d"}, |
362 |
{0x0e300420, 0x0ff00fff, "cfabsd%c\tmvd%12-15d, mvd%16-19d"}, |
363 |
{0x0e300440, 0x0ff00fff, "cfnegs%c\tmvf%12-15d, mvf%16-19d"}, |
364 |
{0x0e300460, 0x0ff00fff, "cfnegd%c\tmvd%12-15d, mvd%16-19d"}, |
365 |
{0x0e300480, 0x0ff00ff0, "cfadds%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, |
366 |
{0x0e3004a0, 0x0ff00ff0, "cfaddd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, |
367 |
{0x0e3004c0, 0x0ff00ff0, "cfsubs%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, |
368 |
{0x0e3004e0, 0x0ff00ff0, "cfsubd%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, |
369 |
{0x0e100400, 0x0ff00ff0, "cfmuls%c\tmvf%12-15d, mvf%16-19d, mvf%0-3d"}, |
370 |
{0x0e100420, 0x0ff00ff0, "cfmuld%c\tmvd%12-15d, mvd%16-19d, mvd%0-3d"}, |
371 |
{0x0e300500, 0x0ff00fff, "cfabs32%c\tmvfx%12-15d, mvfx%16-19d"}, |
372 |
{0x0e300520, 0x0ff00fff, "cfabs64%c\tmvdx%12-15d, mvdx%16-19d"}, |
373 |
{0x0e300540, 0x0ff00fff, "cfneg32%c\tmvfx%12-15d, mvfx%16-19d"}, |
374 |
{0x0e300560, 0x0ff00fff, "cfneg64%c\tmvdx%12-15d, mvdx%16-19d"}, |
375 |
{0x0e300580, 0x0ff00ff0, "cfadd32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
376 |
{0x0e3005a0, 0x0ff00ff0, "cfadd64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, |
377 |
{0x0e3005c0, 0x0ff00ff0, "cfsub32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
378 |
{0x0e3005e0, 0x0ff00ff0, "cfsub64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, |
379 |
{0x0e100500, 0x0ff00ff0, "cfmul32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
380 |
{0x0e100520, 0x0ff00ff0, "cfmul64%c\tmvdx%12-15d, mvdx%16-19d, mvdx%0-3d"}, |
381 |
{0x0e100540, 0x0ff00ff0, "cfmac32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
382 |
{0x0e100560, 0x0ff00ff0, "cfmsc32%c\tmvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
383 |
{0x0e000600, 0x0ff00f00, "cfmadd32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
384 |
{0x0e100600, 0x0ff00f00, "cfmsub32%c\tmvax%5-7d, mvfx%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
385 |
{0x0e200600, 0x0ff00f00, "cfmadda32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
386 |
{0x0e300600, 0x0ff00f00, "cfmsuba32%c\tmvax%5-7d, mvax%12-15d, mvfx%16-19d, mvfx%0-3d"}, |
387 |
|
388 |
/* Generic coprocessor instructions */
|
389 |
{0x0e000000, 0x0f000010, "cdp%c\t%8-11d, %20-23d, cr%12-15d, cr%16-19d, cr%0-3d, {%5-7d}"}, |
390 |
{0x0e100010, 0x0f100010, "mrc%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, |
391 |
{0x0e000010, 0x0f100010, "mcr%c\t%8-11d, %21-23d, %12-15r, cr%16-19d, cr%0-3d, {%5-7d}"}, |
392 |
{0x0c000000, 0x0e100000, "stc%c%22'l\t%8-11d, cr%12-15d, %A"}, |
393 |
{0x0c100000, 0x0e100000, "ldc%c%22'l\t%8-11d, cr%12-15d, %A"}, |
394 |
|
395 |
/* The rest. */
|
396 |
{0x00000000, 0x00000000, "undefined instruction %0-31x"}, |
397 |
{0x00000000, 0x00000000, 0} |
398 |
}; |
399 |
|
400 |
#define BDISP(x) ((((x) & 0xffffff) ^ 0x800000) - 0x800000) /* 26 bit */ |
401 |
|
402 |
static struct thumb_opcode thumb_opcodes[] = |
403 |
{ |
404 |
/* Thumb instructions. */
|
405 |
|
406 |
/* ARM V5 ISA extends Thumb. */
|
407 |
{0xbe00, 0xff00, "bkpt\t%0-7x"}, |
408 |
{0x4780, 0xff87, "blx\t%3-6r"}, /* note: 4 bit register number. */ |
409 |
/* Note: this is BLX(2). BLX(1) is done in arm-dis.c/print_insn_thumb()
|
410 |
as an extension of the special processing there for Thumb BL.
|
411 |
BL and BLX(1) involve 2 successive 16-bit instructions, which must
|
412 |
always appear together in the correct order. So, the empty
|
413 |
string is put in this table, and the string interpreter takes <empty>
|
414 |
to mean it has a pair of BL-ish instructions. */
|
415 |
{0x46C0, 0xFFFF, "nop\t\t\t(mov r8, r8)"}, |
416 |
/* Format 5 instructions do not update the PSR. */
|
417 |
{0x1C00, 0xFFC0, "mov\t%0-2r, %3-5r\t\t(add %0-2r, %3-5r, #%6-8d)"}, |
418 |
/* Format 4. */
|
419 |
{0x4000, 0xFFC0, "and\t%0-2r, %3-5r"}, |
420 |
{0x4040, 0xFFC0, "eor\t%0-2r, %3-5r"}, |
421 |
{0x4080, 0xFFC0, "lsl\t%0-2r, %3-5r"}, |
422 |
{0x40C0, 0xFFC0, "lsr\t%0-2r, %3-5r"}, |
423 |
{0x4100, 0xFFC0, "asr\t%0-2r, %3-5r"}, |
424 |
{0x4140, 0xFFC0, "adc\t%0-2r, %3-5r"}, |
425 |
{0x4180, 0xFFC0, "sbc\t%0-2r, %3-5r"}, |
426 |
{0x41C0, 0xFFC0, "ror\t%0-2r, %3-5r"}, |
427 |
{0x4200, 0xFFC0, "tst\t%0-2r, %3-5r"}, |
428 |
{0x4240, 0xFFC0, "neg\t%0-2r, %3-5r"}, |
429 |
{0x4280, 0xFFC0, "cmp\t%0-2r, %3-5r"}, |
430 |
{0x42C0, 0xFFC0, "cmn\t%0-2r, %3-5r"}, |
431 |
{0x4300, 0xFFC0, "orr\t%0-2r, %3-5r"}, |
432 |
{0x4340, 0xFFC0, "mul\t%0-2r, %3-5r"}, |
433 |
{0x4380, 0xFFC0, "bic\t%0-2r, %3-5r"}, |
434 |
{0x43C0, 0xFFC0, "mvn\t%0-2r, %3-5r"}, |
435 |
/* format 13 */
|
436 |
{0xB000, 0xFF80, "add\tsp, #%0-6W"}, |
437 |
{0xB080, 0xFF80, "sub\tsp, #%0-6W"}, |
438 |
/* format 5 */
|
439 |
{0x4700, 0xFF80, "bx\t%S"}, |
440 |
{0x4400, 0xFF00, "add\t%D, %S"}, |
441 |
{0x4500, 0xFF00, "cmp\t%D, %S"}, |
442 |
{0x4600, 0xFF00, "mov\t%D, %S"}, |
443 |
/* format 14 */
|
444 |
{0xB400, 0xFE00, "push\t%N"}, |
445 |
{0xBC00, 0xFE00, "pop\t%O"}, |
446 |
/* format 2 */
|
447 |
{0x1800, 0xFE00, "add\t%0-2r, %3-5r, %6-8r"}, |
448 |
{0x1A00, 0xFE00, "sub\t%0-2r, %3-5r, %6-8r"}, |
449 |
{0x1C00, 0xFE00, "add\t%0-2r, %3-5r, #%6-8d"}, |
450 |
{0x1E00, 0xFE00, "sub\t%0-2r, %3-5r, #%6-8d"}, |
451 |
/* format 8 */
|
452 |
{0x5200, 0xFE00, "strh\t%0-2r, [%3-5r, %6-8r]"}, |
453 |
{0x5A00, 0xFE00, "ldrh\t%0-2r, [%3-5r, %6-8r]"}, |
454 |
{0x5600, 0xF600, "ldrs%11?hb\t%0-2r, [%3-5r, %6-8r]"}, |
455 |
/* format 7 */
|
456 |
{0x5000, 0xFA00, "str%10'b\t%0-2r, [%3-5r, %6-8r]"}, |
457 |
{0x5800, 0xFA00, "ldr%10'b\t%0-2r, [%3-5r, %6-8r]"}, |
458 |
/* format 1 */
|
459 |
{0x0000, 0xF800, "lsl\t%0-2r, %3-5r, #%6-10d"}, |
460 |
{0x0800, 0xF800, "lsr\t%0-2r, %3-5r, #%6-10d"}, |
461 |
{0x1000, 0xF800, "asr\t%0-2r, %3-5r, #%6-10d"}, |
462 |
/* format 3 */
|
463 |
{0x2000, 0xF800, "mov\t%8-10r, #%0-7d"}, |
464 |
{0x2800, 0xF800, "cmp\t%8-10r, #%0-7d"}, |
465 |
{0x3000, 0xF800, "add\t%8-10r, #%0-7d"}, |
466 |
{0x3800, 0xF800, "sub\t%8-10r, #%0-7d"}, |
467 |
/* format 6 */
|
468 |
{0x4800, 0xF800, "ldr\t%8-10r, [pc, #%0-7W]\t(%0-7a)"}, /* TODO: Disassemble PC relative "LDR rD,=<symbolic>" */ |
469 |
/* format 9 */
|
470 |
{0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"}, |
471 |
{0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"}, |
472 |
{0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"}, |
473 |
{0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"}, |
474 |
/* format 10 */
|
475 |
{0x8000, 0xF800, "strh\t%0-2r, [%3-5r, #%6-10H]"}, |
476 |
{0x8800, 0xF800, "ldrh\t%0-2r, [%3-5r, #%6-10H]"}, |
477 |
/* format 11 */
|
478 |
{0x9000, 0xF800, "str\t%8-10r, [sp, #%0-7W]"}, |
479 |
{0x9800, 0xF800, "ldr\t%8-10r, [sp, #%0-7W]"}, |
480 |
/* format 12 */
|
481 |
{0xA000, 0xF800, "add\t%8-10r, pc, #%0-7W\t(adr %8-10r,%0-7a)"}, |
482 |
{0xA800, 0xF800, "add\t%8-10r, sp, #%0-7W"}, |
483 |
/* format 15 */
|
484 |
{0xC000, 0xF800, "stmia\t%8-10r!,%M"}, |
485 |
{0xC800, 0xF800, "ldmia\t%8-10r!,%M"}, |
486 |
/* format 18 */
|
487 |
{0xE000, 0xF800, "b\t%0-10B"}, |
488 |
{0xE800, 0xF800, "undefined"}, |
489 |
/* format 19 */
|
490 |
{0xF000, 0xF800, ""}, /* special processing required in disassembler */ |
491 |
{0xF800, 0xF800, "second half of BL instruction %0-15x"}, |
492 |
/* format 16 */
|
493 |
{0xD000, 0xFF00, "beq\t%0-7B"}, |
494 |
{0xD100, 0xFF00, "bne\t%0-7B"}, |
495 |
{0xD200, 0xFF00, "bcs\t%0-7B"}, |
496 |
{0xD300, 0xFF00, "bcc\t%0-7B"}, |
497 |
{0xD400, 0xFF00, "bmi\t%0-7B"}, |
498 |
{0xD500, 0xFF00, "bpl\t%0-7B"}, |
499 |
{0xD600, 0xFF00, "bvs\t%0-7B"}, |
500 |
{0xD700, 0xFF00, "bvc\t%0-7B"}, |
501 |
{0xD800, 0xFF00, "bhi\t%0-7B"}, |
502 |
{0xD900, 0xFF00, "bls\t%0-7B"}, |
503 |
{0xDA00, 0xFF00, "bge\t%0-7B"}, |
504 |
{0xDB00, 0xFF00, "blt\t%0-7B"}, |
505 |
{0xDC00, 0xFF00, "bgt\t%0-7B"}, |
506 |
{0xDD00, 0xFF00, "ble\t%0-7B"}, |
507 |
/* format 17 */
|
508 |
{0xDE00, 0xFF00, "bal\t%0-7B"}, |
509 |
{0xDF00, 0xFF00, "swi\t%0-7d"}, |
510 |
/* format 9 */
|
511 |
{0x6000, 0xF800, "str\t%0-2r, [%3-5r, #%6-10W]"}, |
512 |
{0x6800, 0xF800, "ldr\t%0-2r, [%3-5r, #%6-10W]"}, |
513 |
{0x7000, 0xF800, "strb\t%0-2r, [%3-5r, #%6-10d]"}, |
514 |
{0x7800, 0xF800, "ldrb\t%0-2r, [%3-5r, #%6-10d]"}, |
515 |
/* the rest */
|
516 |
{0x0000, 0x0000, "undefined instruction %0-15x"}, |
517 |
{0x0000, 0x0000, 0} |
518 |
}; |
519 |
|
520 |
#define BDISP23(x) ((((((x) & 0x07ff) << 11) | (((x) & 0x07ff0000) >> 16)) \ |
521 |
^ 0x200000) - 0x200000) /* 23bit */ |
522 |
|
523 |
#ifndef streq
|
524 |
#define streq(a,b) (strcmp ((a), (b)) == 0) |
525 |
#endif
|
526 |
|
527 |
#ifndef strneq
|
528 |
#define strneq(a,b,n) (strncmp ((a), (b), (n)) == 0) |
529 |
#endif
|
530 |
|
531 |
#ifndef NUM_ELEM
|
532 |
#define NUM_ELEM(a) (sizeof (a) / sizeof (a)[0]) |
533 |
#endif
|
534 |
|
535 |
static char * arm_conditional[] = |
536 |
{"eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", |
537 |
"hi", "ls", "ge", "lt", "gt", "le", "", "nv"}; |
538 |
|
539 |
typedef struct |
540 |
{ |
541 |
const char * name; |
542 |
const char * description; |
543 |
const char * reg_names[16]; |
544 |
} |
545 |
arm_regname; |
546 |
|
547 |
static arm_regname regnames[] =
|
548 |
{ |
549 |
{ "raw" , "Select raw register names", |
550 |
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"}}, |
551 |
{ "gcc", "Select register names used by GCC", |
552 |
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc" }}, |
553 |
{ "std", "Select register names used in ARM's ISA documentation", |
554 |
{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10", "r11", "r12", "sp", "lr", "pc" }}, |
555 |
{ "apcs", "Select register names used in the APCS", |
556 |
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "sl", "fp", "ip", "sp", "lr", "pc" }}, |
557 |
{ "atpcs", "Select register names used in the ATPCS", |
558 |
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "IP", "SP", "LR", "PC" }}, |
559 |
{ "special-atpcs", "Select special register names used in the ATPCS", |
560 |
{ "a1", "a2", "a3", "a4", "v1", "v2", "v3", "WR", "v5", "SB", "SL", "FP", "IP", "SP", "LR", "PC" }} |
561 |
}; |
562 |
|
563 |
/* Default to STD register name set. */
|
564 |
static unsigned int regname_selected = 2; |
565 |
|
566 |
#define NUM_ARM_REGNAMES NUM_ELEM (regnames)
|
567 |
#define arm_regnames regnames[regname_selected].reg_names
|
568 |
|
569 |
static boolean force_thumb = false; |
570 |
|
571 |
static char * arm_fp_const[] = |
572 |
{"0.0", "1.0", "2.0", "3.0", "4.0", "5.0", "0.5", "10.0"}; |
573 |
|
574 |
static char * arm_shift[] = |
575 |
{"lsl", "lsr", "asr", "ror"}; |
576 |
|
577 |
/* Forward declarations. */
|
578 |
static void arm_decode_shift PARAMS ((long, fprintf_ftype, void *)); |
579 |
static int print_insn_arm1 PARAMS ((bfd_vma, struct disassemble_info *, long)); |
580 |
static int print_insn_thumb PARAMS ((bfd_vma, struct disassemble_info *, long)); |
581 |
static void parse_disassembler_options PARAMS ((char *)); |
582 |
int get_arm_regname_num_options (void); |
583 |
int set_arm_regname_option (int option); |
584 |
int get_arm_regnames (int option, const char **setname, |
585 |
const char **setdescription, |
586 |
const char ***register_names); |
587 |
|
588 |
/* Functions. */
|
589 |
int
|
590 |
get_arm_regname_num_options () |
591 |
{ |
592 |
return NUM_ARM_REGNAMES;
|
593 |
} |
594 |
|
595 |
int
|
596 |
set_arm_regname_option (option) |
597 |
int option;
|
598 |
{ |
599 |
int old = regname_selected;
|
600 |
regname_selected = option; |
601 |
return old;
|
602 |
} |
603 |
|
604 |
int
|
605 |
get_arm_regnames (option, setname, setdescription, register_names) |
606 |
int option;
|
607 |
const char **setname; |
608 |
const char **setdescription; |
609 |
const char ***register_names; |
610 |
{ |
611 |
*setname = regnames[option].name; |
612 |
*setdescription = regnames[option].description; |
613 |
*register_names = regnames[option].reg_names; |
614 |
return 16; |
615 |
} |
616 |
|
617 |
static void |
618 |
arm_decode_shift (given, func, stream) |
619 |
long given;
|
620 |
fprintf_ftype func; |
621 |
void * stream;
|
622 |
{ |
623 |
func (stream, "%s", arm_regnames[given & 0xf]); |
624 |
|
625 |
if ((given & 0xff0) != 0) |
626 |
{ |
627 |
if ((given & 0x10) == 0) |
628 |
{ |
629 |
int amount = (given & 0xf80) >> 7; |
630 |
int shift = (given & 0x60) >> 5; |
631 |
|
632 |
if (amount == 0) |
633 |
{ |
634 |
if (shift == 3) |
635 |
{ |
636 |
func (stream, ", rrx");
|
637 |
return;
|
638 |
} |
639 |
|
640 |
amount = 32;
|
641 |
} |
642 |
|
643 |
func (stream, ", %s #%d", arm_shift[shift], amount);
|
644 |
} |
645 |
else
|
646 |
func (stream, ", %s %s", arm_shift[(given & 0x60) >> 5], |
647 |
arm_regnames[(given & 0xf00) >> 8]); |
648 |
} |
649 |
} |
650 |
|
651 |
/* Print one instruction from PC on INFO->STREAM.
|
652 |
Return the size of the instruction (always 4 on ARM). */
|
653 |
|
654 |
static int |
655 |
print_insn_arm1 (pc, info, given) |
656 |
bfd_vma pc; |
657 |
struct disassemble_info * info;
|
658 |
long given;
|
659 |
{ |
660 |
struct arm_opcode * insn;
|
661 |
void * stream = info->stream;
|
662 |
fprintf_ftype func = info->fprintf_func; |
663 |
|
664 |
for (insn = arm_opcodes; insn->assembler; insn++)
|
665 |
{ |
666 |
if ((given & insn->mask) == insn->value)
|
667 |
{ |
668 |
char * c;
|
669 |
|
670 |
for (c = insn->assembler; *c; c++)
|
671 |
{ |
672 |
if (*c == '%') |
673 |
{ |
674 |
switch (*++c)
|
675 |
{ |
676 |
case '%': |
677 |
func (stream, "%%");
|
678 |
break;
|
679 |
|
680 |
case 'a': |
681 |
if (((given & 0x000f0000) == 0x000f0000) |
682 |
&& ((given & 0x02000000) == 0)) |
683 |
{ |
684 |
int offset = given & 0xfff; |
685 |
|
686 |
func (stream, "[pc");
|
687 |
|
688 |
if (given & 0x01000000) |
689 |
{ |
690 |
if ((given & 0x00800000) == 0) |
691 |
offset = - offset; |
692 |
|
693 |
/* Pre-indexed. */
|
694 |
func (stream, ", #%d]", offset);
|
695 |
|
696 |
offset += pc + 8;
|
697 |
|
698 |
/* Cope with the possibility of write-back
|
699 |
being used. Probably a very dangerous thing
|
700 |
for the programmer to do, but who are we to
|
701 |
argue ? */
|
702 |
if (given & 0x00200000) |
703 |
func (stream, "!");
|
704 |
} |
705 |
else
|
706 |
{ |
707 |
/* Post indexed. */
|
708 |
func (stream, "], #%d", offset);
|
709 |
|
710 |
/* ie ignore the offset. */
|
711 |
offset = pc + 8;
|
712 |
} |
713 |
|
714 |
func (stream, "\t; ");
|
715 |
info->print_address_func (offset, info); |
716 |
} |
717 |
else
|
718 |
{ |
719 |
func (stream, "[%s",
|
720 |
arm_regnames[(given >> 16) & 0xf]); |
721 |
if ((given & 0x01000000) != 0) |
722 |
{ |
723 |
if ((given & 0x02000000) == 0) |
724 |
{ |
725 |
int offset = given & 0xfff; |
726 |
if (offset)
|
727 |
func (stream, ", %s#%d",
|
728 |
(((given & 0x00800000) == 0) |
729 |
? "-" : ""), offset); |
730 |
} |
731 |
else
|
732 |
{ |
733 |
func (stream, ", %s",
|
734 |
(((given & 0x00800000) == 0) |
735 |
? "-" : "")); |
736 |
arm_decode_shift (given, func, stream); |
737 |
} |
738 |
|
739 |
func (stream, "]%s",
|
740 |
((given & 0x00200000) != 0) ? "!" : ""); |
741 |
} |
742 |
else
|
743 |
{ |
744 |
if ((given & 0x02000000) == 0) |
745 |
{ |
746 |
int offset = given & 0xfff; |
747 |
if (offset)
|
748 |
func (stream, "], %s#%d",
|
749 |
(((given & 0x00800000) == 0) |
750 |
? "-" : ""), offset); |
751 |
else
|
752 |
func (stream, "]");
|
753 |
} |
754 |
else
|
755 |
{ |
756 |
func (stream, "], %s",
|
757 |
(((given & 0x00800000) == 0) |
758 |
? "-" : "")); |
759 |
arm_decode_shift (given, func, stream); |
760 |
} |
761 |
} |
762 |
} |
763 |
break;
|
764 |
|
765 |
case 's': |
766 |
if ((given & 0x004f0000) == 0x004f0000) |
767 |
{ |
768 |
/* PC relative with immediate offset. */
|
769 |
int offset = ((given & 0xf00) >> 4) | (given & 0xf); |
770 |
|
771 |
if ((given & 0x00800000) == 0) |
772 |
offset = -offset; |
773 |
|
774 |
func (stream, "[pc, #%d]\t; ", offset);
|
775 |
|
776 |
(*info->print_address_func) |
777 |
(offset + pc + 8, info);
|
778 |
} |
779 |
else
|
780 |
{ |
781 |
func (stream, "[%s",
|
782 |
arm_regnames[(given >> 16) & 0xf]); |
783 |
if ((given & 0x01000000) != 0) |
784 |
{ |
785 |
/* Pre-indexed. */
|
786 |
if ((given & 0x00400000) == 0x00400000) |
787 |
{ |
788 |
/* Immediate. */
|
789 |
int offset = ((given & 0xf00) >> 4) | (given & 0xf); |
790 |
if (offset)
|
791 |
func (stream, ", %s#%d",
|
792 |
(((given & 0x00800000) == 0) |
793 |
? "-" : ""), offset); |
794 |
} |
795 |
else
|
796 |
{ |
797 |
/* Register. */
|
798 |
func (stream, ", %s%s",
|
799 |
(((given & 0x00800000) == 0) |
800 |
? "-" : ""), |
801 |
arm_regnames[given & 0xf]);
|
802 |
} |
803 |
|
804 |
func (stream, "]%s",
|
805 |
((given & 0x00200000) != 0) ? "!" : ""); |
806 |
} |
807 |
else
|
808 |
{ |
809 |
/* Post-indexed. */
|
810 |
if ((given & 0x00400000) == 0x00400000) |
811 |
{ |
812 |
/* Immediate. */
|
813 |
int offset = ((given & 0xf00) >> 4) | (given & 0xf); |
814 |
if (offset)
|
815 |
func (stream, "], %s#%d",
|
816 |
(((given & 0x00800000) == 0) |
817 |
? "-" : ""), offset); |
818 |
else
|
819 |
func (stream, "]");
|
820 |
} |
821 |
else
|
822 |
{ |
823 |
/* Register. */
|
824 |
func (stream, "], %s%s",
|
825 |
(((given & 0x00800000) == 0) |
826 |
? "-" : ""), |
827 |
arm_regnames[given & 0xf]);
|
828 |
} |
829 |
} |
830 |
} |
831 |
break;
|
832 |
|
833 |
case 'b': |
834 |
(*info->print_address_func) |
835 |
(BDISP (given) * 4 + pc + 8, info); |
836 |
break;
|
837 |
|
838 |
case 'c': |
839 |
func (stream, "%s",
|
840 |
arm_conditional [(given >> 28) & 0xf]); |
841 |
break;
|
842 |
|
843 |
case 'm': |
844 |
{ |
845 |
int started = 0; |
846 |
int reg;
|
847 |
|
848 |
func (stream, "{");
|
849 |
for (reg = 0; reg < 16; reg++) |
850 |
if ((given & (1 << reg)) != 0) |
851 |
{ |
852 |
if (started)
|
853 |
func (stream, ", ");
|
854 |
started = 1;
|
855 |
func (stream, "%s", arm_regnames[reg]);
|
856 |
} |
857 |
func (stream, "}");
|
858 |
} |
859 |
break;
|
860 |
|
861 |
case 'o': |
862 |
if ((given & 0x02000000) != 0) |
863 |
{ |
864 |
int rotate = (given & 0xf00) >> 7; |
865 |
int immed = (given & 0xff); |
866 |
immed = (((immed << (32 - rotate))
|
867 |
| (immed >> rotate)) & 0xffffffff);
|
868 |
func (stream, "#%d\t; 0x%x", immed, immed);
|
869 |
} |
870 |
else
|
871 |
arm_decode_shift (given, func, stream); |
872 |
break;
|
873 |
|
874 |
case 'p': |
875 |
if ((given & 0x0000f000) == 0x0000f000) |
876 |
func (stream, "p");
|
877 |
break;
|
878 |
|
879 |
case 't': |
880 |
if ((given & 0x01200000) == 0x00200000) |
881 |
func (stream, "t");
|
882 |
break;
|
883 |
|
884 |
case 'A': |
885 |
func (stream, "[%s", arm_regnames [(given >> 16) & 0xf]); |
886 |
if ((given & 0x01000000) != 0) |
887 |
{ |
888 |
int offset = given & 0xff; |
889 |
if (offset)
|
890 |
func (stream, ", %s#%d]%s",
|
891 |
((given & 0x00800000) == 0 ? "-" : ""), |
892 |
offset * 4,
|
893 |
((given & 0x00200000) != 0 ? "!" : "")); |
894 |
else
|
895 |
func (stream, "]");
|
896 |
} |
897 |
else
|
898 |
{ |
899 |
int offset = given & 0xff; |
900 |
if (offset)
|
901 |
func (stream, "], %s#%d",
|
902 |
((given & 0x00800000) == 0 ? "-" : ""), |
903 |
offset * 4);
|
904 |
else
|
905 |
func (stream, "]");
|
906 |
} |
907 |
break;
|
908 |
|
909 |
case 'B': |
910 |
/* Print ARM V5 BLX(1) address: pc+25 bits. */
|
911 |
{ |
912 |
bfd_vma address; |
913 |
bfd_vma offset = 0;
|
914 |
|
915 |
if (given & 0x00800000) |
916 |
/* Is signed, hi bits should be ones. */
|
917 |
offset = (-1) ^ 0x00ffffff; |
918 |
|
919 |
/* Offset is (SignExtend(offset field)<<2). */
|
920 |
offset += given & 0x00ffffff;
|
921 |
offset <<= 2;
|
922 |
address = offset + pc + 8;
|
923 |
|
924 |
if (given & 0x01000000) |
925 |
/* H bit allows addressing to 2-byte boundaries. */
|
926 |
address += 2;
|
927 |
|
928 |
info->print_address_func (address, info); |
929 |
} |
930 |
break;
|
931 |
|
932 |
case 'I': |
933 |
/* Print a Cirrus/DSP shift immediate. */
|
934 |
/* Immediates are 7bit signed ints with bits 0..3 in
|
935 |
bits 0..3 of opcode and bits 4..6 in bits 5..7
|
936 |
of opcode. */
|
937 |
{ |
938 |
int imm;
|
939 |
|
940 |
imm = (given & 0xf) | ((given & 0xe0) >> 1); |
941 |
|
942 |
/* Is ``imm'' a negative number? */
|
943 |
if (imm & 0x40) |
944 |
imm |= (-1 << 7); |
945 |
|
946 |
func (stream, "%d", imm);
|
947 |
} |
948 |
|
949 |
break;
|
950 |
|
951 |
case 'C': |
952 |
func (stream, "_");
|
953 |
if (given & 0x80000) |
954 |
func (stream, "f");
|
955 |
if (given & 0x40000) |
956 |
func (stream, "s");
|
957 |
if (given & 0x20000) |
958 |
func (stream, "x");
|
959 |
if (given & 0x10000) |
960 |
func (stream, "c");
|
961 |
break;
|
962 |
|
963 |
case 'F': |
964 |
switch (given & 0x00408000) |
965 |
{ |
966 |
case 0: |
967 |
func (stream, "4");
|
968 |
break;
|
969 |
case 0x8000: |
970 |
func (stream, "1");
|
971 |
break;
|
972 |
case 0x00400000: |
973 |
func (stream, "2");
|
974 |
break;
|
975 |
default:
|
976 |
func (stream, "3");
|
977 |
} |
978 |
break;
|
979 |
|
980 |
case 'P': |
981 |
switch (given & 0x00080080) |
982 |
{ |
983 |
case 0: |
984 |
func (stream, "s");
|
985 |
break;
|
986 |
case 0x80: |
987 |
func (stream, "d");
|
988 |
break;
|
989 |
case 0x00080000: |
990 |
func (stream, "e");
|
991 |
break;
|
992 |
default:
|
993 |
func (stream, _("<illegal precision>"));
|
994 |
break;
|
995 |
} |
996 |
break;
|
997 |
case 'Q': |
998 |
switch (given & 0x00408000) |
999 |
{ |
1000 |
case 0: |
1001 |
func (stream, "s");
|
1002 |
break;
|
1003 |
case 0x8000: |
1004 |
func (stream, "d");
|
1005 |
break;
|
1006 |
case 0x00400000: |
1007 |
func (stream, "e");
|
1008 |
break;
|
1009 |
default:
|
1010 |
func (stream, "p");
|
1011 |
break;
|
1012 |
} |
1013 |
break;
|
1014 |
case 'R': |
1015 |
switch (given & 0x60) |
1016 |
{ |
1017 |
case 0: |
1018 |
break;
|
1019 |
case 0x20: |
1020 |
func (stream, "p");
|
1021 |
break;
|
1022 |
case 0x40: |
1023 |
func (stream, "m");
|
1024 |
break;
|
1025 |
default:
|
1026 |
func (stream, "z");
|
1027 |
break;
|
1028 |
} |
1029 |
break;
|
1030 |
|
1031 |
case '0': case '1': case '2': case '3': case '4': |
1032 |
case '5': case '6': case '7': case '8': case '9': |
1033 |
{ |
1034 |
int bitstart = *c++ - '0'; |
1035 |
int bitend = 0; |
1036 |
while (*c >= '0' && *c <= '9') |
1037 |
bitstart = (bitstart * 10) + *c++ - '0'; |
1038 |
|
1039 |
switch (*c)
|
1040 |
{ |
1041 |
case '-': |
1042 |
c++; |
1043 |
|
1044 |
while (*c >= '0' && *c <= '9') |
1045 |
bitend = (bitend * 10) + *c++ - '0'; |
1046 |
|
1047 |
if (!bitend)
|
1048 |
abort (); |
1049 |
|
1050 |
switch (*c)
|
1051 |
{ |
1052 |
case 'r': |
1053 |
{ |
1054 |
long reg;
|
1055 |
|
1056 |
reg = given >> bitstart; |
1057 |
reg &= (2 << (bitend - bitstart)) - 1; |
1058 |
|
1059 |
func (stream, "%s", arm_regnames[reg]);
|
1060 |
} |
1061 |
break;
|
1062 |
case 'd': |
1063 |
{ |
1064 |
long reg;
|
1065 |
|
1066 |
reg = given >> bitstart; |
1067 |
reg &= (2 << (bitend - bitstart)) - 1; |
1068 |
|
1069 |
func (stream, "%d", reg);
|
1070 |
} |
1071 |
break;
|
1072 |
case 'x': |
1073 |
{ |
1074 |
long reg;
|
1075 |
|
1076 |
reg = given >> bitstart; |
1077 |
reg &= (2 << (bitend - bitstart)) - 1; |
1078 |
|
1079 |
func (stream, "0x%08x", reg);
|
1080 |
|
1081 |
/* Some SWI instructions have special
|
1082 |
meanings. */
|
1083 |
if ((given & 0x0fffffff) == 0x0FF00000) |
1084 |
func (stream, "\t; IMB");
|
1085 |
else if ((given & 0x0fffffff) == 0x0FF00001) |
1086 |
func (stream, "\t; IMBRange");
|
1087 |
} |
1088 |
break;
|
1089 |
case 'X': |
1090 |
{ |
1091 |
long reg;
|
1092 |
|
1093 |
reg = given >> bitstart; |
1094 |
reg &= (2 << (bitend - bitstart)) - 1; |
1095 |
|
1096 |
func (stream, "%01x", reg & 0xf); |
1097 |
} |
1098 |
break;
|
1099 |
case 'f': |
1100 |
{ |
1101 |
long reg;
|
1102 |
|
1103 |
reg = given >> bitstart; |
1104 |
reg &= (2 << (bitend - bitstart)) - 1; |
1105 |
|
1106 |
if (reg > 7) |
1107 |
func (stream, "#%s",
|
1108 |
arm_fp_const[reg & 7]);
|
1109 |
else
|
1110 |
func (stream, "f%d", reg);
|
1111 |
} |
1112 |
break;
|
1113 |
default:
|
1114 |
abort (); |
1115 |
} |
1116 |
break;
|
1117 |
|
1118 |
case 'y': |
1119 |
case 'z': |
1120 |
{ |
1121 |
int single = *c == 'y'; |
1122 |
int regno;
|
1123 |
|
1124 |
switch (bitstart)
|
1125 |
{ |
1126 |
case 4: /* Sm pair */ |
1127 |
func (stream, "{");
|
1128 |
/* Fall through. */
|
1129 |
case 0: /* Sm, Dm */ |
1130 |
regno = given & 0x0000000f;
|
1131 |
if (single)
|
1132 |
{ |
1133 |
regno <<= 1;
|
1134 |
regno += (given >> 5) & 1; |
1135 |
} |
1136 |
break;
|
1137 |
|
1138 |
case 1: /* Sd, Dd */ |
1139 |
regno = (given >> 12) & 0x0000000f; |
1140 |
if (single)
|
1141 |
{ |
1142 |
regno <<= 1;
|
1143 |
regno += (given >> 22) & 1; |
1144 |
} |
1145 |
break;
|
1146 |
|
1147 |
case 2: /* Sn, Dn */ |
1148 |
regno = (given >> 16) & 0x0000000f; |
1149 |
if (single)
|
1150 |
{ |
1151 |
regno <<= 1;
|
1152 |
regno += (given >> 7) & 1; |
1153 |
} |
1154 |
break;
|
1155 |
|
1156 |
case 3: /* List */ |
1157 |
func (stream, "{");
|
1158 |
regno = (given >> 12) & 0x0000000f; |
1159 |
if (single)
|
1160 |
{ |
1161 |
regno <<= 1;
|
1162 |
regno += (given >> 22) & 1; |
1163 |
} |
1164 |
break;
|
1165 |
|
1166 |
|
1167 |
default:
|
1168 |
abort (); |
1169 |
} |
1170 |
|
1171 |
func (stream, "%c%d", single ? 's' : 'd', regno); |
1172 |
|
1173 |
if (bitstart == 3) |
1174 |
{ |
1175 |
int count = given & 0xff; |
1176 |
|
1177 |
if (single == 0) |
1178 |
count >>= 1;
|
1179 |
|
1180 |
if (--count)
|
1181 |
{ |
1182 |
func (stream, "-%c%d",
|
1183 |
single ? 's' : 'd', |
1184 |
regno + count); |
1185 |
} |
1186 |
|
1187 |
func (stream, "}");
|
1188 |
} |
1189 |
else if (bitstart == 4) |
1190 |
func (stream, ", %c%d}", single ? 's' : 'd', |
1191 |
regno + 1);
|
1192 |
|
1193 |
break;
|
1194 |
} |
1195 |
|
1196 |
case '`': |
1197 |
c++; |
1198 |
if ((given & (1 << bitstart)) == 0) |
1199 |
func (stream, "%c", *c);
|
1200 |
break;
|
1201 |
case '\'': |
1202 |
c++; |
1203 |
if ((given & (1 << bitstart)) != 0) |
1204 |
func (stream, "%c", *c);
|
1205 |
break;
|
1206 |
case '?': |
1207 |
++c; |
1208 |
if ((given & (1 << bitstart)) != 0) |
1209 |
func (stream, "%c", *c++);
|
1210 |
else
|
1211 |
func (stream, "%c", *++c);
|
1212 |
break;
|
1213 |
default:
|
1214 |
abort (); |
1215 |
} |
1216 |
break;
|
1217 |
|
1218 |
default:
|
1219 |
abort (); |
1220 |
} |
1221 |
} |
1222 |
} |
1223 |
else
|
1224 |
func (stream, "%c", *c);
|
1225 |
} |
1226 |
return 4; |
1227 |
} |
1228 |
} |
1229 |
abort (); |
1230 |
} |
1231 |
|
1232 |
/* Print one instruction from PC on INFO->STREAM.
|
1233 |
Return the size of the instruction. */
|
1234 |
|
1235 |
static int |
1236 |
print_insn_thumb (pc, info, given) |
1237 |
bfd_vma pc; |
1238 |
struct disassemble_info * info;
|
1239 |
long given;
|
1240 |
{ |
1241 |
struct thumb_opcode * insn;
|
1242 |
void * stream = info->stream;
|
1243 |
fprintf_ftype func = info->fprintf_func; |
1244 |
|
1245 |
for (insn = thumb_opcodes; insn->assembler; insn++)
|
1246 |
{ |
1247 |
if ((given & insn->mask) == insn->value)
|
1248 |
{ |
1249 |
char * c = insn->assembler;
|
1250 |
|
1251 |
/* Special processing for Thumb 2 instruction BL sequence: */
|
1252 |
if (!*c) /* Check for empty (not NULL) assembler string. */ |
1253 |
{ |
1254 |
long offset;
|
1255 |
|
1256 |
info->bytes_per_chunk = 4;
|
1257 |
info->bytes_per_line = 4;
|
1258 |
|
1259 |
offset = BDISP23 (given); |
1260 |
offset = offset * 2 + pc + 4; |
1261 |
|
1262 |
if ((given & 0x10000000) == 0) |
1263 |
{ |
1264 |
func (stream, "blx\t");
|
1265 |
offset &= 0xfffffffc;
|
1266 |
} |
1267 |
else
|
1268 |
func (stream, "bl\t");
|
1269 |
|
1270 |
info->print_address_func (offset, info); |
1271 |
return 4; |
1272 |
} |
1273 |
else
|
1274 |
{ |
1275 |
info->bytes_per_chunk = 2;
|
1276 |
info->bytes_per_line = 4;
|
1277 |
|
1278 |
given &= 0xffff;
|
1279 |
|
1280 |
for (; *c; c++)
|
1281 |
{ |
1282 |
if (*c == '%') |
1283 |
{ |
1284 |
int domaskpc = 0; |
1285 |
int domasklr = 0; |
1286 |
|
1287 |
switch (*++c)
|
1288 |
{ |
1289 |
case '%': |
1290 |
func (stream, "%%");
|
1291 |
break;
|
1292 |
|
1293 |
case 'S': |
1294 |
{ |
1295 |
long reg;
|
1296 |
|
1297 |
reg = (given >> 3) & 0x7; |
1298 |
if (given & (1 << 6)) |
1299 |
reg += 8;
|
1300 |
|
1301 |
func (stream, "%s", arm_regnames[reg]);
|
1302 |
} |
1303 |
break;
|
1304 |
|
1305 |
case 'D': |
1306 |
{ |
1307 |
long reg;
|
1308 |
|
1309 |
reg = given & 0x7;
|
1310 |
if (given & (1 << 7)) |
1311 |
reg += 8;
|
1312 |
|
1313 |
func (stream, "%s", arm_regnames[reg]);
|
1314 |
} |
1315 |
break;
|
1316 |
|
1317 |
case 'T': |
1318 |
func (stream, "%s",
|
1319 |
arm_conditional [(given >> 8) & 0xf]); |
1320 |
break;
|
1321 |
|
1322 |
case 'N': |
1323 |
if (given & (1 << 8)) |
1324 |
domasklr = 1;
|
1325 |
/* Fall through. */
|
1326 |
case 'O': |
1327 |
if (*c == 'O' && (given & (1 << 8))) |
1328 |
domaskpc = 1;
|
1329 |
/* Fall through. */
|
1330 |
case 'M': |
1331 |
{ |
1332 |
int started = 0; |
1333 |
int reg;
|
1334 |
|
1335 |
func (stream, "{");
|
1336 |
|
1337 |
/* It would be nice if we could spot
|
1338 |
ranges, and generate the rS-rE format: */
|
1339 |
for (reg = 0; (reg < 8); reg++) |
1340 |
if ((given & (1 << reg)) != 0) |
1341 |
{ |
1342 |
if (started)
|
1343 |
func (stream, ", ");
|
1344 |
started = 1;
|
1345 |
func (stream, "%s", arm_regnames[reg]);
|
1346 |
} |
1347 |
|
1348 |
if (domasklr)
|
1349 |
{ |
1350 |
if (started)
|
1351 |
func (stream, ", ");
|
1352 |
started = 1;
|
1353 |
func (stream, arm_regnames[14] /* "lr" */); |
1354 |
} |
1355 |
|
1356 |
if (domaskpc)
|
1357 |
{ |
1358 |
if (started)
|
1359 |
func (stream, ", ");
|
1360 |
func (stream, arm_regnames[15] /* "pc" */); |
1361 |
} |
1362 |
|
1363 |
func (stream, "}");
|
1364 |
} |
1365 |
break;
|
1366 |
|
1367 |
|
1368 |
case '0': case '1': case '2': case '3': case '4': |
1369 |
case '5': case '6': case '7': case '8': case '9': |
1370 |
{ |
1371 |
int bitstart = *c++ - '0'; |
1372 |
int bitend = 0; |
1373 |
|
1374 |
while (*c >= '0' && *c <= '9') |
1375 |
bitstart = (bitstart * 10) + *c++ - '0'; |
1376 |
|
1377 |
switch (*c)
|
1378 |
{ |
1379 |
case '-': |
1380 |
{ |
1381 |
long reg;
|
1382 |
|
1383 |
c++; |
1384 |
while (*c >= '0' && *c <= '9') |
1385 |
bitend = (bitend * 10) + *c++ - '0'; |
1386 |
if (!bitend)
|
1387 |
abort (); |
1388 |
reg = given >> bitstart; |
1389 |
reg &= (2 << (bitend - bitstart)) - 1; |
1390 |
switch (*c)
|
1391 |
{ |
1392 |
case 'r': |
1393 |
func (stream, "%s", arm_regnames[reg]);
|
1394 |
break;
|
1395 |
|
1396 |
case 'd': |
1397 |
func (stream, "%d", reg);
|
1398 |
break;
|
1399 |
|
1400 |
case 'H': |
1401 |
func (stream, "%d", reg << 1); |
1402 |
break;
|
1403 |
|
1404 |
case 'W': |
1405 |
func (stream, "%d", reg << 2); |
1406 |
break;
|
1407 |
|
1408 |
case 'a': |
1409 |
/* PC-relative address -- the bottom two
|
1410 |
bits of the address are dropped
|
1411 |
before the calculation. */
|
1412 |
info->print_address_func |
1413 |
(((pc + 4) & ~3) + (reg << 2), info); |
1414 |
break;
|
1415 |
|
1416 |
case 'x': |
1417 |
func (stream, "0x%04x", reg);
|
1418 |
break;
|
1419 |
|
1420 |
case 'I': |
1421 |
reg = ((reg ^ (1 << bitend)) - (1 << bitend)); |
1422 |
func (stream, "%d", reg);
|
1423 |
break;
|
1424 |
|
1425 |
case 'B': |
1426 |
reg = ((reg ^ (1 << bitend)) - (1 << bitend)); |
1427 |
(*info->print_address_func) |
1428 |
(reg * 2 + pc + 4, info); |
1429 |
break;
|
1430 |
|
1431 |
default:
|
1432 |
abort (); |
1433 |
} |
1434 |
} |
1435 |
break;
|
1436 |
|
1437 |
case '\'': |
1438 |
c++; |
1439 |
if ((given & (1 << bitstart)) != 0) |
1440 |
func (stream, "%c", *c);
|
1441 |
break;
|
1442 |
|
1443 |
case '?': |
1444 |
++c; |
1445 |
if ((given & (1 << bitstart)) != 0) |
1446 |
func (stream, "%c", *c++);
|
1447 |
else
|
1448 |
func (stream, "%c", *++c);
|
1449 |
break;
|
1450 |
|
1451 |
default:
|
1452 |
abort (); |
1453 |
} |
1454 |
} |
1455 |
break;
|
1456 |
|
1457 |
default:
|
1458 |
abort (); |
1459 |
} |
1460 |
} |
1461 |
else
|
1462 |
func (stream, "%c", *c);
|
1463 |
} |
1464 |
} |
1465 |
return 2; |
1466 |
} |
1467 |
} |
1468 |
|
1469 |
/* No match. */
|
1470 |
abort (); |
1471 |
} |
1472 |
|
1473 |
/* Parse an individual disassembler option. */
|
1474 |
|
1475 |
void
|
1476 |
parse_arm_disassembler_option (option) |
1477 |
char * option;
|
1478 |
{ |
1479 |
if (option == NULL) |
1480 |
return;
|
1481 |
|
1482 |
if (strneq (option, "reg-names-", 10)) |
1483 |
{ |
1484 |
int i;
|
1485 |
|
1486 |
option += 10;
|
1487 |
|
1488 |
for (i = NUM_ARM_REGNAMES; i--;)
|
1489 |
if (streq (option, regnames[i].name))
|
1490 |
{ |
1491 |
regname_selected = i; |
1492 |
break;
|
1493 |
} |
1494 |
|
1495 |
if (i < 0) |
1496 |
fprintf (stderr, _("Unrecognised register name set: %s\n"), option);
|
1497 |
} |
1498 |
else if (streq (option, "force-thumb")) |
1499 |
force_thumb = 1;
|
1500 |
else if (streq (option, "no-force-thumb")) |
1501 |
force_thumb = 0;
|
1502 |
else
|
1503 |
fprintf (stderr, _("Unrecognised disassembler option: %s\n"), option);
|
1504 |
|
1505 |
return;
|
1506 |
} |
1507 |
|
1508 |
/* Parse the string of disassembler options, spliting it at whitespaces. */
|
1509 |
|
1510 |
static void |
1511 |
parse_disassembler_options (options) |
1512 |
char * options;
|
1513 |
{ |
1514 |
char * space;
|
1515 |
|
1516 |
if (options == NULL) |
1517 |
return;
|
1518 |
|
1519 |
do
|
1520 |
{ |
1521 |
space = strchr (options, ' ');
|
1522 |
|
1523 |
if (space)
|
1524 |
{ |
1525 |
* space = '\0';
|
1526 |
parse_arm_disassembler_option (options); |
1527 |
* space = ' ';
|
1528 |
options = space + 1;
|
1529 |
} |
1530 |
else
|
1531 |
parse_arm_disassembler_option (options); |
1532 |
} |
1533 |
while (space);
|
1534 |
} |
1535 |
|
1536 |
/* NOTE: There are no checks in these routines that
|
1537 |
the relevant number of data bytes exist. */
|
1538 |
|
1539 |
int
|
1540 |
print_insn_arm (pc, info) |
1541 |
bfd_vma pc; |
1542 |
struct disassemble_info * info;
|
1543 |
{ |
1544 |
unsigned char b[4]; |
1545 |
long given;
|
1546 |
int status;
|
1547 |
int is_thumb;
|
1548 |
int little;
|
1549 |
|
1550 |
if (info->disassembler_options)
|
1551 |
{ |
1552 |
parse_disassembler_options (info->disassembler_options); |
1553 |
|
1554 |
/* To avoid repeated parsing of these options, we remove them here. */
|
1555 |
info->disassembler_options = NULL;
|
1556 |
} |
1557 |
|
1558 |
is_thumb = force_thumb; |
1559 |
if (pc & 1) |
1560 |
{ |
1561 |
is_thumb = 1;
|
1562 |
pc &= ~(bfd_vma) 1;
|
1563 |
} |
1564 |
|
1565 |
#if 0
|
1566 |
if (!is_thumb && info->symbols != NULL)
|
1567 |
{
|
1568 |
if (bfd_asymbol_flavour (*info->symbols) == bfd_target_coff_flavour)
|
1569 |
{
|
1570 |
coff_symbol_type * cs;
|
1571 |
|
1572 |
cs = coffsymbol (*info->symbols);
|
1573 |
is_thumb = ( cs->native->u.syment.n_sclass == C_THUMBEXT
|
1574 |
|| cs->native->u.syment.n_sclass == C_THUMBSTAT
|
1575 |
|| cs->native->u.syment.n_sclass == C_THUMBLABEL
|
1576 |
|| cs->native->u.syment.n_sclass == C_THUMBEXTFUNC
|
1577 |
|| cs->native->u.syment.n_sclass == C_THUMBSTATFUNC);
|
1578 |
}
|
1579 |
else if (bfd_asymbol_flavour (*info->symbols) == bfd_target_elf_flavour)
|
1580 |
{
|
1581 |
elf_symbol_type * es;
|
1582 |
unsigned int type;
|
1583 |
|
1584 |
es = *(elf_symbol_type **)(info->symbols);
|
1585 |
type = ELF_ST_TYPE (es->internal_elf_sym.st_info);
|
1586 |
|
1587 |
is_thumb = (type == STT_ARM_TFUNC) || (type == STT_ARM_16BIT);
|
1588 |
}
|
1589 |
}
|
1590 |
#endif
|
1591 |
|
1592 |
little = (info->endian == BFD_ENDIAN_LITTLE); |
1593 |
info->bytes_per_chunk = 4;
|
1594 |
info->display_endian = little ? BFD_ENDIAN_LITTLE : BFD_ENDIAN_BIG; |
1595 |
|
1596 |
if (little)
|
1597 |
{ |
1598 |
status = info->read_memory_func (pc, (bfd_byte *) &b[0], 4, info); |
1599 |
if (status != 0 && is_thumb) |
1600 |
{ |
1601 |
info->bytes_per_chunk = 2;
|
1602 |
|
1603 |
status = info->read_memory_func (pc, (bfd_byte *) b, 2, info);
|
1604 |
b[3] = b[2] = 0; |
1605 |
} |
1606 |
|
1607 |
if (status != 0) |
1608 |
{ |
1609 |
info->memory_error_func (status, pc, info); |
1610 |
return -1; |
1611 |
} |
1612 |
|
1613 |
given = (b[0]) | (b[1] << 8) | (b[2] << 16) | (b[3] << 24); |
1614 |
} |
1615 |
else
|
1616 |
{ |
1617 |
status = info->read_memory_func |
1618 |
(pc & ~ 0x3, (bfd_byte *) &b[0], 4, info); |
1619 |
if (status != 0) |
1620 |
{ |
1621 |
info->memory_error_func (status, pc, info); |
1622 |
return -1; |
1623 |
} |
1624 |
|
1625 |
if (is_thumb)
|
1626 |
{ |
1627 |
if (pc & 0x2) |
1628 |
{ |
1629 |
given = (b[2] << 8) | b[3]; |
1630 |
|
1631 |
status = info->read_memory_func |
1632 |
((pc + 4) & ~ 0x3, (bfd_byte *) b, 4, info); |
1633 |
if (status != 0) |
1634 |
{ |
1635 |
info->memory_error_func (status, pc + 4, info);
|
1636 |
return -1; |
1637 |
} |
1638 |
|
1639 |
given |= (b[0] << 24) | (b[1] << 16); |
1640 |
} |
1641 |
else
|
1642 |
given = (b[0] << 8) | b[1] | (b[2] << 24) | (b[3] << 16); |
1643 |
} |
1644 |
else
|
1645 |
given = (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | (b[3]); |
1646 |
} |
1647 |
|
1648 |
if (info->flags & INSN_HAS_RELOC)
|
1649 |
/* If the instruction has a reloc associated with it, then
|
1650 |
the offset field in the instruction will actually be the
|
1651 |
addend for the reloc. (We are using REL type relocs).
|
1652 |
In such cases, we can ignore the pc when computing
|
1653 |
addresses, since the addend is not currently pc-relative. */
|
1654 |
pc = 0;
|
1655 |
if (is_thumb)
|
1656 |
status = print_insn_thumb (pc, info, given); |
1657 |
else
|
1658 |
status = print_insn_arm1 (pc, info, given); |
1659 |
|
1660 |
return status;
|
1661 |
} |
1662 |
|
1663 |
void
|
1664 |
print_arm_disassembler_options (FILE * stream) |
1665 |
{ |
1666 |
int i;
|
1667 |
|
1668 |
fprintf (stream, _("\n\
|
1669 |
The following ARM specific disassembler options are supported for use with\n\
|
1670 |
the -M switch:\n"));
|
1671 |
|
1672 |
for (i = NUM_ARM_REGNAMES; i--;)
|
1673 |
fprintf (stream, " reg-names-%s %*c%s\n",
|
1674 |
regnames[i].name, |
1675 |
(int)(14 - strlen (regnames[i].name)), ' ', |
1676 |
regnames[i].description); |
1677 |
|
1678 |
fprintf (stream, " force-thumb Assume all insns are Thumb insns\n");
|
1679 |
fprintf (stream, " no-force-thumb Examine preceeding label to determine an insn's type\n\n");
|
1680 |
} |