2 Thumb Dissassembler. Still a work in progress.
4 Wrong output is a bug, so please fix it.
5 Hex output means there is not yet an entry or a decode bug.
6 gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit
7 16-bit stream of Thumb2 instruction. Then there are big case
8 statements to print everything out. If you are adding instructions
9 try to reuse existing case entries if possible.
11 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
13 All rights reserved. This program and the accompanying materials
14 are licensed and made available under the terms and conditions of the BSD License
15 which accompanies this distribution. The full text of the license may be found at
16 http://opensource.org/licenses/bsd-license.php
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
24 #include <Library/BaseLib.h>
25 #include <Library/PrintLib.h>
27 extern CHAR8
*gCondition
[];
31 // Thumb address modes
32 #define LOAD_STORE_FORMAT1 1
33 #define LOAD_STORE_FORMAT2 2
34 #define LOAD_STORE_FORMAT3 3
35 #define LOAD_STORE_FORMAT4 4
36 #define LOAD_STORE_MULTIPLE_FORMAT1 5
38 #define POP_FORMAT 106
40 #define CONDITIONAL_BRANCH 8
41 #define UNCONDITIONAL_BRANCH 9
42 #define UNCONDITIONAL_BRANCH_SHORT 109
43 #define BRANCH_EXCHANGE 10
44 #define DATA_FORMAT1 11
45 #define DATA_FORMAT2 12
46 #define DATA_FORMAT3 13
47 #define DATA_FORMAT4 14
48 #define DATA_FORMAT5 15
49 #define DATA_FORMAT6_SP 16
50 #define DATA_FORMAT6_PC 116
51 #define DATA_FORMAT7 17
52 #define DATA_FORMAT8 19
54 #define ENDIAN_FORMAT 21
58 // Thumb2 address modes
64 #define STM_FORMAT 205
65 #define LDM_REG_IMM12_SIGNED 206
66 #define LDM_REG_IMM12_LSL 207
67 #define LDM_REG_IMM8 208
68 #define LDM_REG_IMM12 209
69 #define LDM_REG_INDIRECT_LSL 210
70 #define LDM_REG_IMM8_SIGNED 211
71 #define LDRD_REG_IMM8 212
74 #define SRS_FORMAT 215
75 #define RFE_FORMAT 216
76 #define LDRD_REG_IMM8_SIGNED 217
88 THUMB_INSTRUCTIONS gOpThumb
[] = {
89 // Thumb 16-bit instrucitons
91 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5
},
92 { "ADR", 0xa000, 0xf800, ADR_FORMAT
}, // ADR <Rd>, <label>
93 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2
},
94 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3
},
95 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1
},
96 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8
}, // A8.6.9
97 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC
},
98 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP
},
99 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7
},
101 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5
},
103 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4
},
104 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5
},
106 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH
},
107 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT
},
108 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE
},
109 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE
},
111 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5
},
112 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
113 { "CBZ", 0xb100, 0xfd00, DATA_CBZ
},
114 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ
},
115 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5
},
117 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3
},
118 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5
},
119 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8
},
121 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT
},
122 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
123 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5
},
125 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
126 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1
},
127 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
},
128 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3
},
129 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4
},
130 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1
},
131 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2
},
132 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1
},
133 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2
},
134 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2
},
135 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2
},
137 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5
}, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
138 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4
},
139 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5
},
140 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4
},
141 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5
},
143 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3
},
144 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3
},
145 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
147 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5
},
148 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5
},
149 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5
},
150 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5
},
151 { "POP" , 0xbc00, 0xfe00, POP_FORMAT
},
152 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT
},
154 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5
},
155 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5
},
156 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5
},
158 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5
},
159 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
160 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT
},
162 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
163 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1
},
164 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2
},
165 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3
},
166 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4
},
167 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1
},
168 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
},
169 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1
},
170 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2
},
172 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2
},
173 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3
},
174 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1
},
175 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7
},
177 { "SWI" , 0xdf00, 0xff00, IMMED_8
},
178 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5
},
179 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5
},
180 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5
},
181 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5
},
182 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5
}
186 THUMB_INSTRUCTIONS gOpThumb2
[] = {
187 //Instruct OpCode OpCode Mask Addressig Mode
188 { "B", 0xf0008000, 0xf800d000, B_T3
}, // B<c> <label>
189 { "B", 0xf0009000, 0xf800d000, B_T4
}, // B<c> <label>
190 { "BL", 0xf000d000, 0xf800d000, B_T4
}, // BL<c> <label>
191 { "BLX", 0xf000c000, 0xf800d000, BL_T2
}, // BLX<c> <label>
193 { "POP", 0xe8bd0000, 0xffff2000, POP_T2
}, // POP <registers>
194 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3
}, // POP <register>
195 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2
}, // PUSH <registers>
196 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3
}, // PUSH <register>
197 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT
}, // STM <Rn>{!},<registers>
198 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT
}, // STMDB <Rn>{!},<registers>
199 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT
}, // LDM <Rn>{!},<registers>
200 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT
}, // LDMDB <Rn>{!},<registers>
202 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12
}, // LDR <rt>, [<rn>, {, #<imm12>]}
203 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12
}, // LDRB <rt>, [<rn>, {, #<imm12>]}
204 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRH <rt>, [<rn>, {, #<imm12>]}
205 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12
}, // LDRSB <rt>, [<rn>, {, #<imm12>]}
206 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRSH <rt>, [<rn>, {, #<imm12>]}
208 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDR <Rt>, <label>
209 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRB <Rt>, <label>
210 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRH <Rt>, <label>
211 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
212 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
214 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
215 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
216 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
217 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
218 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
220 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8
}, // LDR <rt>, [<rn>, {, #<imm8>]}
221 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRBT <rt>, [<rn>, {, #<imm8>]}
222 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]}
223 { "LDRSB", 0xf9900800, 0xfff00800, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
224 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
225 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8
}, // LDRSH <rt>, [<rn>, {, #<imm8>]}
226 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
227 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRT <rt>, [<rn>, {, #<imm8>]}
229 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
230 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8
}, // LDRD <rt>, <rt2>, <label>
232 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8
}, // LDREX <Rt>, [Rn, {#imm8}]]
233 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB
}, // LDREXB <Rt>, [<Rn>]
234 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB
}, // LDREXH <Rt>, [<Rn>]
236 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // LDREXD <Rt>, <Rt2>, [<Rn>]
238 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12
}, // STR <rt>, [<rn>, {, #<imm12>]}
239 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12
}, // STRB <rt>, [<rn>, {, #<imm12>]}
240 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12
}, // STRH <rt>, [<rn>, {, #<imm12>]}
242 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
243 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
244 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
246 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8
}, // STR <rt>, [<rn>, {, #<imm8>]}
247 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8
}, // STRH <rt>, [<rn>, {, #<imm8>]}
248 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8
}, // STRBT <rt>, [<rn>, {, #<imm8>]}
249 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8
}, // STRHT <rt>, [<rn>, {, #<imm8>]}
250 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8
}, // STRT <rt>, [<rn>, {, #<imm8>]}
252 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
254 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8
}, // STREX <Rt>, [Rn, {#imm8}]]
255 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB
}, // STREXB <Rd>, <Rt>, [<Rn>]
256 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB
}, // STREXH <Rd>, <Rt>, [<Rn>]
258 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
260 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT
}, // SRSDB<c> SP{!},#<mode>
261 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT
}, // SRS{IA}<c> SP{!},#<mode>
262 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT
}, // RFEDB<c> <Rn>{!}
263 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT
} // RFE{IA}<c> <Rn>{!}
266 CHAR8 mThumbMregListStr
[4*15 + 1];
273 UINTN Index
, Start
, End
;
277 Str
= mThumbMregListStr
;
279 AsciiStrCat (Str
, "{");
281 for (Index
= 0, First
= TRUE
; Index
<= 15; Index
++) {
282 if ((RegBitMask
& (1 << Index
)) != 0) {
284 for (Index
++; ((RegBitMask
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
289 AsciiStrCat (Str
, ",");
295 AsciiStrCat (Str
, gReg
[Start
]);
297 AsciiStrCat (Str
, gReg
[Start
]);
298 AsciiStrCat (Str
, "-");
299 AsciiStrCat (Str
, gReg
[End
]);
304 AsciiStrCat (Str
, "ERROR");
306 AsciiStrCat (Str
, "}");
308 // BugBug: Make caller pass in buffer it is cleaner
309 return mThumbMregListStr
;
318 if (((Data
& TopBit
) == 0) || (TopBit
== BIT31
)) {
325 } while ((TopBit
& BIT31
) != BIT31
);
331 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
332 point to next instructin.
334 We cheat and only decode instructions that access
335 memory. If the instruction is not found we dump the instruction in hex.
337 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
338 @param Buf Buffer to sprintf disassembly into.
339 @param Size Size of Buf in bytes.
340 @param Extended TRUE dump hex for instruction too.
344 DisassembleThumbInstruction (
345 IN UINT16
**OpCodePtrPtr
,
356 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
357 BOOLEAN H1
, H2
, imod
;
360 BOOLEAN S
, J1
, J2
, P
, U
, W
;
362 OpCodePtr
= *OpCodePtrPtr
;
363 OpCode
= **OpCodePtrPtr
;
365 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
366 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
368 // These register names match branch form, but not others
370 Rn
= (OpCode
>> 3) & 0x7;
371 Rm
= (OpCode
>> 6) & 0x7;
372 H1
= (OpCode
& BIT7
) != 0;
373 H2
= (OpCode
& BIT6
) != 0;
374 imod
= (OpCode
& BIT4
) != 0;
375 PC
= (UINT32
)(UINTN
)OpCodePtr
;
377 // Increment by the minimum instruction size, Thumb2 could be bigger
380 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
381 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
383 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
385 Offset
= AsciiSPrint (Buf
, Size
, "%-6a", gOpThumb
[Index
].Start
);
387 switch (gOpThumb
[Index
].AddressMode
) {
388 case LOAD_STORE_FORMAT1
:
389 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
390 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 4) & 0x7c);
392 case LOAD_STORE_FORMAT2
:
393 // A6.5.1 <Rd>, [<Rn>, <Rm>]
394 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d, r%d]", Rd
, Rn
, Rm
);
396 case LOAD_STORE_FORMAT3
:
397 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
398 Target
= (OpCode
& 0xff) << 2;
399 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [pc, #0x%x] ;0x%08x", (OpCode
>> 8) & 7, Target
, PC
+ 2 + Target
);
401 case LOAD_STORE_FORMAT4
:
403 Target
= (OpCode
& 0xff) << 2;
404 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, Target
, PC
+ 2 + Target
);
407 case LOAD_STORE_MULTIPLE_FORMAT1
:
409 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
& 0xff));
414 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT15
: 0)));
419 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT14
: 0)));
425 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
428 case CONDITIONAL_BRANCH
:
429 // A6.3.1 B<cond> <target_address>
430 // Patch in the condition code. A little hack but based on "%-6a"
431 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
432 Buf
[Offset
-5] = *Cond
++;
433 Buf
[Offset
-4] = *Cond
;
434 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
436 case UNCONDITIONAL_BRANCH_SHORT
:
437 // A6.3.2 B <target_address>
438 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
441 case BRANCH_EXCHANGE
:
442 // A6.3.3 BX|BLX <Rm>
443 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2
? 8:0)]);
447 // A6.4.3 <Rd>, <Rn>, <Rm>
448 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
451 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
452 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
455 // A6.4.3 <Rd>|<Rn>, #imm8
456 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
459 // A6.4.3 <Rd>|<Rm>, #immed_5
460 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
463 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
464 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
466 case DATA_FORMAT6_SP
:
467 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
468 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
470 case DATA_FORMAT6_PC
:
471 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
472 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
475 // A6.4.3 SP, SP, #<7_Bit_immed>
476 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
479 // A6.4.3 <Rd>|<Rn>, <Rm>
480 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1
? 8:0)], gReg
[Rn
| (H2
? 8:0)]);
485 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", imod
? "ID":"IE", ((OpCode
& BIT2
) == 0) ? "":"a", ((OpCode
& BIT1
) == 0) ? "":"i", ((OpCode
& BIT0
) == 0) ? "":"f");
490 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");
494 // CB{N}Z <Rn>, <Lable>
495 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
496 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], PC
+ 4 + Target
);
501 Target
= (OpCode
& 0xff) << 2;
502 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PC
+ 4 + Target
);
509 // Thumb2 are 32-bit instructions
511 Rt
= (OpCode32
>> 12) & 0xf;
512 Rt2
= (OpCode32
>> 8) & 0xf;
513 Rm
= (OpCode32
& 0xf);
514 Rn
= (OpCode32
>> 16) & 0xf;
515 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
516 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
518 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
520 Offset
= AsciiSPrint (Buf
, Size
, " %-6a", gOpThumb2
[Index
].Start
);
522 switch (gOpThumb2
[Index
].AddressMode
) {
524 Cond
= gCondition
[(OpCode32
>> 22) & 0xf];
525 Buf
[Offset
-5] = *Cond
++;
526 Buf
[Offset
-4] = *Cond
;
527 // S:J2:J1:imm6:imm11:0
528 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3f000);
529 Target
|= ((OpCode32
& BIT11
) == BIT11
)? BIT19
: 0; // J2
530 Target
|= ((OpCode32
& BIT13
) == BIT13
)? BIT18
: 0; // J1
531 Target
|= ((OpCode32
& BIT26
) == BIT26
)? BIT20
: 0; // S
532 Target
= SignExtend32 (Target
, BIT20
);
533 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
536 // S:I1:I2:imm10:imm11:0
537 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3ff000);
538 S
= (OpCode32
& BIT26
) == BIT26
;
539 J1
= (OpCode32
& BIT13
) == BIT13
;
540 J2
= (OpCode32
& BIT11
) == BIT11
;
541 Target
|= (!(J2
^ S
) ? BIT22
: 0); // I2
542 Target
|= (!(J1
^ S
) ? BIT23
: 0); // I1
543 Target
|= (S
? BIT24
: 0); // S
544 Target
= SignExtend32 (Target
, BIT24
);
545 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
549 // S:I1:I2:imm10:imm11:00
550 Target
= ((OpCode32
<< 2) & 0x1ffc) + ((OpCode32
>> 3) & 0x7fe000);
551 S
= (OpCode32
& BIT26
) == BIT26
;
552 J1
= (OpCode32
& BIT13
) == BIT13
;
553 J2
= (OpCode32
& BIT11
) == BIT11
;
554 Target
|= (!(J2
^ S
) ? BIT23
: 0); // I2
555 Target
|= (!(J1
^ S
) ? BIT24
: 0); // I1
556 Target
|= (S
? BIT25
: 0); // S
557 Target
= SignExtend32 (Target
, BIT25
);
558 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
562 // <reglist> some must be zero, handled in table
563 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList (OpCode32
& 0xffff));
568 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[(OpCode32
>> 12) & 0xf]);
572 // <Rn>{!}, <registers>
573 W
= (OpCode32
& BIT21
) == BIT21
;
574 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a %a", gReg
[(OpCode32
>> 16) & 0xf], W
? "!":"", ThumbMRegList (OpCode32
& 0xffff));
577 case LDM_REG_IMM12_SIGNED
:
579 Target
= OpCode32
& 0xfff;
580 if ((OpCode32
& BIT23
) == 0) {
581 // U == 0 means subtrack, U == 1 means add
584 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PC
+ 4 + Target
);
587 case LDM_REG_INDIRECT_LSL
:
588 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
589 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
590 if (((OpCode32
>> 4) && 3) == 0) {
591 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
593 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL #%d]", (OpCode32
>> 4) && 3);
598 // <rt>, [<rn>, {, #<imm12>]}
599 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
600 if ((OpCode32
&& 0xfff) == 0) {
601 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
603 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #0x%x]", OpCode32
& 0xfff);
608 // <rt>, [<rn>, {, #<imm8>}]{!}
609 W
= (OpCode32
& BIT8
) == BIT8
;
610 U
= (OpCode32
& BIT9
) == BIT9
;
611 P
= (OpCode32
& BIT10
) == BIT10
;
612 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
614 if ((OpCode32
&& 0xff) == 0) {
615 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", W
?"!":"");
617 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", OpCode32
& 0xff, U
?"":"-" ,W
?"!":"");
620 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x]%a", OpCode32
& 0xff, U
?"":"-");
624 case LDRD_REG_IMM8_SIGNED
:
625 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
626 P
= (OpCode32
& BIT24
) == BIT24
; // index = P
627 U
= (OpCode32
& BIT23
) == BIT23
;
628 W
= (OpCode32
& BIT21
) == BIT21
;
629 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
631 if ((OpCode32
&& 0xff) == 0) {
632 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
634 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", U
?"":"-", (OpCode32
& 0xff) << 2, W
?"!":"");
637 if ((OpCode32
&& 0xff) != 0) {
638 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", U
?"":"-", (OpCode32
& 0xff) << 2);
644 // LDRD <rt>, <rt2>, <label>
645 Target
= (OpCode32
& 0xff) << 2;
646 if ((OpCode32
& BIT23
) == 0) {
647 // U == 0 means subtrack, U == 1 means add
650 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], PC
+ 4 + Target
);
655 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
659 // LDREXD <Rt>, <Rt2>, [<Rn>]
660 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
665 W
= (OpCode32
& BIT21
) == BIT21
;
666 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", W
?"!":"", OpCode32
& 0x1f);
671 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], W
?"!":"");
678 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
684 DisassembleArmInstruction (
685 IN UINT32
**OpCodePtr
,
693 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
694 point to next instructin.
696 We cheat and only decode instructions that access
697 memory. If the instruction is not found we dump the instruction in hex.
699 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
700 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
701 @param Extended TRUE dump hex for instruction too.
702 @param Buf Buffer to sprintf disassembly into.
703 @param Size Size of Buf in bytes.
707 DisassembleInstruction (
708 IN UINT8
**OpCodePtr
,
716 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, Extended
);
718 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);