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/DebugLib.h>
26 #include <Library/PrintLib.h>
28 extern CHAR8
*gCondition
[];
32 // Thumb address modes
33 #define LOAD_STORE_FORMAT1 1
34 #define LOAD_STORE_FORMAT1_H 101
35 #define LOAD_STORE_FORMAT1_B 111
36 #define LOAD_STORE_FORMAT2 2
37 #define LOAD_STORE_FORMAT3 3
38 #define LOAD_STORE_FORMAT4 4
39 #define LOAD_STORE_MULTIPLE_FORMAT1 5
41 #define POP_FORMAT 106
43 #define CONDITIONAL_BRANCH 8
44 #define UNCONDITIONAL_BRANCH 9
45 #define UNCONDITIONAL_BRANCH_SHORT 109
46 #define BRANCH_EXCHANGE 10
47 #define DATA_FORMAT1 11
48 #define DATA_FORMAT2 12
49 #define DATA_FORMAT3 13
50 #define DATA_FORMAT4 14
51 #define DATA_FORMAT5 15
52 #define DATA_FORMAT6_SP 16
53 #define DATA_FORMAT6_PC 116
54 #define DATA_FORMAT7 17
55 #define DATA_FORMAT8 19
57 #define ENDIAN_FORMAT 21
61 // Thumb2 address modes
67 #define STM_FORMAT 205
68 #define LDM_REG_IMM12_SIGNED 206
69 #define LDM_REG_IMM12_LSL 207
70 #define LDM_REG_IMM8 208
71 #define LDM_REG_IMM12 209
72 #define LDM_REG_INDIRECT_LSL 210
73 #define LDM_REG_IMM8_SIGNED 211
74 #define LDRD_REG_IMM8 212
77 #define SRS_FORMAT 215
78 #define RFE_FORMAT 216
79 #define LDRD_REG_IMM8_SIGNED 217
82 #define ADR_THUMB2 220
83 #define CMN_THUMB2 221
92 THUMB_INSTRUCTIONS gOpThumb
[] = {
93 // Thumb 16-bit instrucitons
95 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5
},
96 { "ADR", 0xa000, 0xf800, ADR_FORMAT
}, // ADR <Rd>, <label>
97 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2
},
98 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3
},
99 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1
},
100 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8
}, // A8.6.9
101 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC
},
102 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP
},
103 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7
},
105 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5
},
107 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4
},
108 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5
},
110 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH
},
111 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT
},
112 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE
},
113 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE
},
115 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5
},
116 { "BKPT", 0xdf00, 0xff00, IMMED_8
},
117 { "CBZ", 0xb100, 0xfd00, DATA_CBZ
},
118 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ
},
119 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5
},
121 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3
},
122 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5
},
123 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8
},
125 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT
},
126 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
127 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5
},
129 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
130 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1
},
131 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
},
132 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3
},
133 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4
},
134 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1_B
},
135 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2
},
136 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1_H
},
137 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2
},
138 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2
},
139 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2
},
141 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5
}, // LSL with imm5 == 0 is a MOVS, so this must go before LSL
142 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4
},
143 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5
},
144 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4
},
145 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5
},
147 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3
},
148 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3
},
149 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8
},
151 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5
},
152 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5
},
153 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5
},
154 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5
},
155 { "POP" , 0xbc00, 0xfe00, POP_FORMAT
},
156 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT
},
158 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5
},
159 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5
},
160 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5
},
162 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5
},
163 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5
},
164 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT
},
166 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1
},
167 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1
},
168 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2
},
169 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3
},
170 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4
},
171 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1_B
},
172 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2
},
173 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1_H
},
174 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2
},
176 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2
},
177 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3
},
178 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1
},
179 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7
},
181 { "SWI" , 0xdf00, 0xff00, IMMED_8
},
182 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5
},
183 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5
},
184 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5
},
185 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5
},
186 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5
}
190 THUMB_INSTRUCTIONS gOpThumb2
[] = {
191 //Instruct OpCode OpCode Mask Addressig Mode
193 { "ADR", 0xf2af0000, 0xfbff8000, ADR_THUMB2
}, // ADDR <Rd>, <label> ;Needs to go before ADDW
194 { "CMN", 0xf1100f00, 0xfff08f00, CMN_THUMB2
}, // CMN <Rn>, <Rm>, {,<shift> #<const>} ;Needs to go before ADD
196 { "ADC", 0xf1400000, 0xfbe08000, ADD_IMM12
}, // ADC{S} <Rd>, <Rn>, #<const>
197 { "ADC", 0xeb400000, 0xffe08000, ADD_IMM5
}, // ADC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
198 { "ADD", 0xf1000000, 0xfbe08000, ADD_IMM12
}, // ADD{S} <Rd>, <Rn>, #<const>
199 { "ADD", 0xeb000000, 0xffe08000, ADD_IMM5
}, // ADD{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
200 { "ADDW", 0xf2000000, 0xfbe08000, ADD_IMM12
}, // ADDW{S} <Rd>, <Rn>, #<const>
201 { "AND", 0xf0000000, 0xfbe08000, ADD_IMM12
}, // AND{S} <Rd>, <Rn>, #<const>
202 { "AND", 0xea000000, 0xffe08000, ADD_IMM5
}, // AND{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
203 { "BIC", 0xf0200000, 0xfbe08000, ADD_IMM12
}, // BIC{S} <Rd>, <Rn>, #<const>
204 { "BIC", 0xea200000, 0xffe08000, ADD_IMM5
}, // BIC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
205 { "EOR", 0xf0800000, 0xfbe08000, ADD_IMM12
}, // EOR{S} <Rd>, <Rn>, #<const>
206 { "EOR", 0xea800000, 0xffe08000, ADD_IMM5
}, // EOR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
207 { "ORN", 0xf0600000, 0xfbe08000, ADD_IMM12
}, // ORN{S} <Rd>, <Rn>, #<const>
208 { "ORN", 0xea600000, 0xffe08000, ADD_IMM5
}, // ORN{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
209 { "ORR", 0xf0400000, 0xfbe08000, ADD_IMM12
}, // ORR{S} <Rd>, <Rn>, #<const>
210 { "ORR", 0xea400000, 0xffe08000, ADD_IMM5
}, // ORR{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
211 { "RSB", 0xf1c00000, 0xfbe08000, ADD_IMM12
}, // RSB{S} <Rd>, <Rn>, #<const>
212 { "RSB", 0xebc00000, 0xffe08000, ADD_IMM5
}, // RSB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
213 { "SBC", 0xf1600000, 0xfbe08000, ADD_IMM12
}, // SBC{S} <Rd>, <Rn>, #<const>
214 { "SBC", 0xeb600000, 0xffe08000, ADD_IMM5
}, // SBC{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
215 { "SUB", 0xf1a00000, 0xfbe08000, ADD_IMM12
}, // SUB{S} <Rd>, <Rn>, #<const>
216 { "SUB", 0xeba00000, 0xffe08000, ADD_IMM5
}, // SUB{S} <Rd>, <Rn>, <Rm> {,<shift> #<const>}
218 { "B", 0xf0008000, 0xf800d000, B_T3
}, // B<c> <label>
219 { "B", 0xf0009000, 0xf800d000, B_T4
}, // B<c> <label>
220 { "BL", 0xf000d000, 0xf800d000, B_T4
}, // BL<c> <label>
221 { "BLX", 0xf000c000, 0xf800d000, BL_T2
}, // BLX<c> <label>
223 { "POP", 0xe8bd0000, 0xffff2000, POP_T2
}, // POP <registers>
224 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3
}, // POP <register>
225 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2
}, // PUSH <registers>
226 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3
}, // PUSH <register>
227 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT
}, // STM <Rn>{!},<registers>
228 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT
}, // STMDB <Rn>{!},<registers>
229 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT
}, // LDM <Rn>{!},<registers>
230 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT
}, // LDMDB <Rn>{!},<registers>
232 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12
}, // LDR <rt>, [<rn>, {, #<imm12>]}
233 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12
}, // LDRB <rt>, [<rn>, {, #<imm12>]}
234 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRH <rt>, [<rn>, {, #<imm12>]}
235 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12
}, // LDRSB <rt>, [<rn>, {, #<imm12>]}
236 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12
}, // LDRSH <rt>, [<rn>, {, #<imm12>]}
238 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDR <Rt>, <label>
239 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRB <Rt>, <label>
240 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRH <Rt>, <label>
241 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
242 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED
}, // LDRSB <Rt>, <label>
244 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
245 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
246 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
247 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
248 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
250 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8
}, // LDR <rt>, [<rn>, {, #<imm8>]}
251 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRBT <rt>, [<rn>, {, #<imm8>]}
252 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]}
253 { "LDRSB", 0xf9900800, 0xfff00800, LDM_REG_IMM8
}, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form?
254 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form?
255 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8
}, // LDRSH <rt>, [<rn>, {, #<imm8>]}
256 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRSHT <rt>, [<rn>, {, #<imm8>]}
257 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8
}, // LDRT <rt>, [<rn>, {, #<imm8>]}
259 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
260 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8
}, // LDRD <rt>, <rt2>, <label>
262 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8
}, // LDREX <Rt>, [Rn, {#imm8}]]
263 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB
}, // LDREXB <Rt>, [<Rn>]
264 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB
}, // LDREXH <Rt>, [<Rn>]
266 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // LDREXD <Rt>, <Rt2>, [<Rn>]
268 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12
}, // STR <rt>, [<rn>, {, #<imm12>]}
269 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12
}, // STRB <rt>, [<rn>, {, #<imm12>]}
270 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12
}, // STRH <rt>, [<rn>, {, #<imm12>]}
272 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}
273 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}
274 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL
}, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}
276 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8
}, // STR <rt>, [<rn>, {, #<imm8>]}
277 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8
}, // STRH <rt>, [<rn>, {, #<imm8>]}
278 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8
}, // STRBT <rt>, [<rn>, {, #<imm8>]}
279 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8
}, // STRHT <rt>, [<rn>, {, #<imm8>]}
280 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8
}, // STRT <rt>, [<rn>, {, #<imm8>]}
282 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED
}, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
284 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8
}, // STREX <Rt>, [Rn, {#imm8}]]
285 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB
}, // STREXB <Rd>, <Rt>, [<Rn>]
286 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB
}, // STREXH <Rd>, <Rt>, [<Rn>]
288 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD
}, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
290 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT
}, // SRSDB<c> SP{!},#<mode>
291 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT
}, // SRS{IA}<c> SP{!},#<mode>
292 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT
}, // RFEDB<c> <Rn>{!}
293 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT
} // RFE{IA}<c> <Rn>{!}
296 CHAR8
*gShiftType
[] = {
303 CHAR8 mThumbMregListStr
[4*15 + 1];
310 UINTN Index
, Start
, End
;
314 Str
= mThumbMregListStr
;
316 AsciiStrCat (Str
, "{");
318 for (Index
= 0, First
= TRUE
; Index
<= 15; Index
++) {
319 if ((RegBitMask
& (1 << Index
)) != 0) {
321 for (Index
++; ((RegBitMask
& (1 << Index
)) != 0) && (Index
<= 9); Index
++) {
326 AsciiStrCat (Str
, ",");
332 AsciiStrCat (Str
, gReg
[Start
]);
334 AsciiStrCat (Str
, gReg
[Start
]);
335 AsciiStrCat (Str
, "-");
336 AsciiStrCat (Str
, gReg
[End
]);
341 AsciiStrCat (Str
, "ERROR");
343 AsciiStrCat (Str
, "}");
345 // BugBug: Make caller pass in buffer it is cleaner
346 return mThumbMregListStr
;
355 if (((Data
& TopBit
) == 0) || (TopBit
== BIT31
)) {
362 } while ((TopBit
& BIT31
) != BIT31
);
368 // Some instructions specify the PC is always considered aligned
369 // The PC is after the instruction that is excuting. So you pass
370 // in the instruction address and you get back the aligned answer
376 return (Data
+ 4) & 0xfffffffc;
380 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
381 point to next instructin.
383 We cheat and only decode instructions that access
384 memory. If the instruction is not found we dump the instruction in hex.
386 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
387 @param Buf Buffer to sprintf disassembly into.
388 @param Size Size of Buf in bytes.
389 @param Extended TRUE dump hex for instruction too.
393 DisassembleThumbInstruction (
394 IN UINT16
**OpCodePtrPtr
,
405 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
406 BOOLEAN H1
, H2
, imod
;
409 BOOLEAN S
, J1
, J2
, P
, U
, W
;
411 OpCodePtr
= *OpCodePtrPtr
;
412 OpCode
= **OpCodePtrPtr
;
414 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
415 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
417 // These register names match branch form, but not others
419 Rn
= (OpCode
>> 3) & 0x7;
420 Rm
= (OpCode
>> 6) & 0x7;
421 H1
= (OpCode
& BIT7
) != 0;
422 H2
= (OpCode
& BIT6
) != 0;
423 imod
= (OpCode
& BIT4
) != 0;
424 PC
= (UINT32
)(UINTN
)OpCodePtr
;
426 // Increment by the minimum instruction size, Thumb2 could be bigger
429 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
430 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
432 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
434 Offset
= AsciiSPrint (Buf
, Size
, "%-6a", gOpThumb
[Index
].Start
);
436 switch (gOpThumb
[Index
].AddressMode
) {
437 case LOAD_STORE_FORMAT1
:
438 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
439 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 4) & 0x7c);
441 case LOAD_STORE_FORMAT1_H
:
442 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
443 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 5) & 0x3f);
445 case LOAD_STORE_FORMAT1_B
:
446 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
447 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 6) & 0x1f);
450 case LOAD_STORE_FORMAT2
:
451 // A6.5.1 <Rd>, [<Rn>, <Rm>]
452 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d, r%d]", Rd
, Rn
, Rm
);
454 case LOAD_STORE_FORMAT3
:
455 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
456 Target
= (OpCode
& 0xff) << 2;
457 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [pc, #0x%x] ;0x%08x", (OpCode
>> 8) & 7, Target
, PCAlign4 (PC
) + Target
);
459 case LOAD_STORE_FORMAT4
:
461 Target
= (OpCode
& 0xff) << 2;
462 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, Target
);
465 case LOAD_STORE_MULTIPLE_FORMAT1
:
467 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
& 0xff));
472 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT15
: 0)));
477 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT14
: 0)));
483 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
486 case CONDITIONAL_BRANCH
:
487 // A6.3.1 B<cond> <target_address>
488 // Patch in the condition code. A little hack but based on "%-6a"
489 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
490 Buf
[Offset
-5] = *Cond
++;
491 Buf
[Offset
-4] = *Cond
;
492 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
494 case UNCONDITIONAL_BRANCH_SHORT
:
495 // A6.3.2 B <target_address>
496 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
499 case BRANCH_EXCHANGE
:
500 // A6.3.3 BX|BLX <Rm>
501 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2
? 8:0)]);
505 // A6.4.3 <Rd>, <Rn>, <Rm>
506 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
509 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
510 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
513 // A6.4.3 <Rd>|<Rn>, #imm8
514 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
517 // A6.4.3 <Rd>|<Rm>, #immed_5
518 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
521 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
522 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
524 case DATA_FORMAT6_SP
:
525 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
526 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
528 case DATA_FORMAT6_PC
:
529 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
530 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
533 // A6.4.3 SP, SP, #<7_Bit_immed>
534 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
537 // A6.4.3 <Rd>|<Rn>, <Rm>
538 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1
? 8:0)], gReg
[Rn
| (H2
? 8:0)]);
543 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", imod
? "ID":"IE", ((OpCode
& BIT2
) == 0) ? "":"a", ((OpCode
& BIT1
) == 0) ? "":"i", ((OpCode
& BIT0
) == 0) ? "":"f");
548 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");
552 // CB{N}Z <Rn>, <Lable>
553 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
554 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], PC
+ 4 + Target
);
559 Target
= (OpCode
& 0xff) << 2;
560 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PCAlign4 (PC
) + Target
);
567 // Thumb2 are 32-bit instructions
569 Rt
= (OpCode32
>> 12) & 0xf;
570 Rt2
= (OpCode32
>> 8) & 0xf;
571 Rd
= (OpCode32
>> 8) & 0xf;
572 Rm
= (OpCode32
& 0xf);
573 Rn
= (OpCode32
>> 16) & 0xf;
574 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
575 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
577 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
579 Offset
= AsciiSPrint (Buf
, Size
, " %-6a", gOpThumb2
[Index
].Start
);
581 switch (gOpThumb2
[Index
].AddressMode
) {
583 Cond
= gCondition
[(OpCode32
>> 22) & 0xf];
584 Buf
[Offset
-5] = *Cond
++;
585 Buf
[Offset
-4] = *Cond
;
586 // S:J2:J1:imm6:imm11:0
587 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3f000);
588 Target
|= ((OpCode32
& BIT11
) == BIT11
)? BIT19
: 0; // J2
589 Target
|= ((OpCode32
& BIT13
) == BIT13
)? BIT18
: 0; // J1
590 Target
|= ((OpCode32
& BIT26
) == BIT26
)? BIT20
: 0; // S
591 Target
= SignExtend32 (Target
, BIT20
);
592 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
595 // S:I1:I2:imm10:imm11:0
596 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3ff000);
597 S
= (OpCode32
& BIT26
) == BIT26
;
598 J1
= (OpCode32
& BIT13
) == BIT13
;
599 J2
= (OpCode32
& BIT11
) == BIT11
;
600 Target
|= (!(J2
^ S
) ? BIT22
: 0); // I2
601 Target
|= (!(J1
^ S
) ? BIT23
: 0); // I1
602 Target
|= (S
? BIT24
: 0); // S
603 Target
= SignExtend32 (Target
, BIT24
);
604 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
608 // BLX S:I1:I2:imm10:imm11:0
609 Target
= ((OpCode32
<< 1) & 0xffc) + ((OpCode32
>> 4) & 0x3ff000);
610 S
= (OpCode32
& BIT26
) == BIT26
;
611 J1
= (OpCode32
& BIT13
) == BIT13
;
612 J2
= (OpCode32
& BIT11
) == BIT11
;
613 Target
|= (!(J2
^ S
) ? BIT23
: 0); // I2
614 Target
|= (!(J1
^ S
) ? BIT24
: 0); // I1
615 Target
|= (S
? BIT25
: 0); // S
616 Target
= SignExtend32 (Target
, BIT25
);
617 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PCAlign4 (PC
) + Target
);
621 // <reglist> some must be zero, handled in table
622 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList (OpCode32
& 0xffff));
627 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[(OpCode32
>> 12) & 0xf]);
631 // <Rn>{!}, <registers>
632 W
= (OpCode32
& BIT21
) == BIT21
;
633 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, %a", gReg
[(OpCode32
>> 16) & 0xf], W
? "!":"", ThumbMRegList (OpCode32
& 0xffff));
636 case LDM_REG_IMM12_SIGNED
:
638 Target
= OpCode32
& 0xfff;
639 if ((OpCode32
& BIT23
) == 0) {
640 // U == 0 means subtrack, U == 1 means add
643 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PCAlign4 (PC
) + Target
);
646 case LDM_REG_INDIRECT_LSL
:
647 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
648 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
649 if (((OpCode32
>> 4) && 3) == 0) {
650 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
652 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL #%d]", (OpCode32
>> 4) && 3);
657 // <rt>, [<rn>, {, #<imm12>]}
658 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
659 if ((OpCode32
&& 0xfff) == 0) {
660 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
662 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #0x%x]", OpCode32
& 0xfff);
668 // <rt>, [<rn>, {, #<imm8>}]{!}
669 W
= (OpCode32
& BIT8
) == BIT8
;
670 U
= (OpCode32
& BIT9
) == BIT9
;
671 P
= (OpCode32
& BIT10
) == BIT10
;
672 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
674 if ((OpCode32
&& 0xff) == 0) {
675 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", W
?"!":"");
677 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", OpCode32
& 0xff, U
?"":"-" , W
?"!":"");
680 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x]", OpCode32
& 0xff, U
?"":"-");
684 case LDRD_REG_IMM8_SIGNED
:
685 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
686 P
= (OpCode32
& BIT24
) == BIT24
; // index = P
687 U
= (OpCode32
& BIT23
) == BIT23
;
688 W
= (OpCode32
& BIT21
) == BIT21
;
689 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
691 if ((OpCode32
&& 0xff) == 0) {
692 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
694 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", U
?"":"-", (OpCode32
& 0xff) << 2, W
?"!":"");
697 if ((OpCode32
&& 0xff) != 0) {
698 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", U
?"":"-", (OpCode32
& 0xff) << 2);
704 // LDRD <rt>, <rt2>, <label>
705 Target
= (OpCode32
& 0xff) << 2;
706 if ((OpCode32
& BIT23
) == 0) {
707 // U == 0 means subtrack, U == 1 means add
710 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], PC
+ 4 + Target
);
715 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
719 // LDREXD <Rt>, <Rt2>, [<Rn>]
720 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
725 W
= (OpCode32
& BIT21
) == BIT21
;
726 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", W
?"!":"", OpCode32
& 0x1f);
731 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], W
?"!":"");
735 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
736 if ((OpCode32
& BIT20
) == BIT20
) {
737 Buf
[Offset
- 3] = 'S'; // assume %-6a
739 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
740 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, #0x%x", gReg
[Rd
], gReg
[Rn
], Target
);
744 // ADC <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
745 if ((OpCode32
& BIT20
) == BIT20
) {
746 Buf
[Offset
- 3] = 'S'; // assume %-6a
748 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
749 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
751 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
756 // ADDR <Rd>, <label>
757 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 8) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
758 if ((OpCode
& (BIT23
| BIT21
)) == (BIT23
| BIT21
)) {
759 Target
= PCAlign4 (PC
) - Target
;
761 Target
= PCAlign4 (PC
) + Target
;
763 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, 0x%08x", gReg
[Rd
], Target
);
767 // CMN <Rn>, <Rm>, {,<shift> #<const>}
768 if ((OpCode32
& BIT20
) == BIT20
) {
769 Buf
[Offset
- 3] = 'S'; // assume %-6a
771 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
772 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a", gReg
[Rn
], gReg
[Rm
]);
774 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
781 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
787 DisassembleArmInstruction (
788 IN UINT32
**OpCodePtr
,
796 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
797 point to next instructin.
799 We cheat and only decode instructions that access
800 memory. If the instruction is not found we dump the instruction in hex.
802 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
803 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
804 @param Extended TRUE dump hex for instruction too.
805 @param Buf Buffer to sprintf disassembly into.
806 @param Size Size of Buf in bytes.
810 DisassembleInstruction (
811 IN UINT8
**OpCodePtr
,
819 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, Extended
);
821 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);