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
377 return (Data
+ 4) & 0xfffffffc;
381 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
382 point to next instructin.
384 We cheat and only decode instructions that access
385 memory. If the instruction is not found we dump the instruction in hex.
387 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
388 @param Buf Buffer to sprintf disassembly into.
389 @param Size Size of Buf in bytes.
390 @param Extended TRUE dump hex for instruction too.
394 DisassembleThumbInstruction (
395 IN UINT16
**OpCodePtrPtr
,
406 UINT16 Rd
, Rn
, Rm
, Rt
, Rt2
;
407 BOOLEAN H1
, H2
, imod
;
410 BOOLEAN S
, J1
, J2
, P
, U
, W
;
412 OpCodePtr
= *OpCodePtrPtr
;
413 OpCode
= **OpCodePtrPtr
;
415 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
416 OpCode32
= (((UINT32
)OpCode
) << 16) | *(OpCodePtr
+ 1);
418 // These register names match branch form, but not others
420 Rn
= (OpCode
>> 3) & 0x7;
421 Rm
= (OpCode
>> 6) & 0x7;
422 H1
= (OpCode
& BIT7
) != 0;
423 H2
= (OpCode
& BIT6
) != 0;
424 imod
= (OpCode
& BIT4
) != 0;
425 PC
= (UINT32
)(UINTN
)OpCodePtr
;
427 // Increment by the minimum instruction size, Thumb2 could be bigger
430 for (Index
= 0; Index
< sizeof (gOpThumb
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
431 if ((OpCode
& gOpThumb
[Index
].Mask
) == gOpThumb
[Index
].OpCode
) {
433 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode
, gOpThumb
[Index
].Start
);
435 Offset
= AsciiSPrint (Buf
, Size
, "%-6a", gOpThumb
[Index
].Start
);
437 switch (gOpThumb
[Index
].AddressMode
) {
438 case LOAD_STORE_FORMAT1
:
439 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
440 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 4) & 0x7c);
442 case LOAD_STORE_FORMAT1_H
:
443 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
444 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 5) & 0x3f);
446 case LOAD_STORE_FORMAT1_B
:
447 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]
448 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d #0x%x]", Rd
, Rn
, (OpCode
>> 6) & 0x1f);
451 case LOAD_STORE_FORMAT2
:
452 // A6.5.1 <Rd>, [<Rn>, <Rm>]
453 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [r%d, r%d]", Rd
, Rn
, Rm
);
455 case LOAD_STORE_FORMAT3
:
456 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]
457 Target
= (OpCode
& 0xff) << 2;
458 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [pc, #0x%x] ;0x%08x", (OpCode
>> 8) & 7, Target
, PCAlign4 (PC
) + Target
);
460 case LOAD_STORE_FORMAT4
:
462 Target
= (OpCode
& 0xff) << 2;
463 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, [sp, #0x%x]", (OpCode
>> 8) & 7, Target
);
466 case LOAD_STORE_MULTIPLE_FORMAT1
:
468 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d!, %a", (OpCode
>> 8) & 7, ThumbMRegList (OpCode
& 0xff));
473 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT15
: 0)));
478 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList ((OpCode
& 0xff) | ((OpCode
& BIT8
) == BIT8
? BIT14
: 0)));
484 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%x", OpCode
& 0xff);
487 case CONDITIONAL_BRANCH
:
488 // A6.3.1 B<cond> <target_address>
489 // Patch in the condition code. A little hack but based on "%-6a"
490 Cond
= gCondition
[(OpCode
>> 8) & 0xf];
491 Buf
[Offset
-5] = *Cond
++;
492 Buf
[Offset
-4] = *Cond
;
493 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0xff) << 1, BIT8
));
495 case UNCONDITIONAL_BRANCH_SHORT
:
496 // A6.3.2 B <target_address>
497 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%04x", PC
+ 4 + SignExtend32 ((OpCode
& 0x3ff) << 1, BIT11
));
500 case BRANCH_EXCHANGE
:
501 // A6.3.3 BX|BLX <Rm>
502 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[Rn
| (H2
? 8:0)]);
506 // A6.4.3 <Rd>, <Rn>, <Rm>
507 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, r%d", Rd
, Rn
, Rm
);
510 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
511 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rd
, Rn
, Rm
);
514 // A6.4.3 <Rd>|<Rn>, #imm8
515 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, #0x%x", (OpCode
>> 8) & 7, OpCode
& 0xff);
518 // A6.4.3 <Rd>|<Rm>, #immed_5
519 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d, 0x%x", Rn
, Rd
, (OpCode
>> 6) & 0x1f);
522 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
523 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, r%d", Rd
, Rn
);
525 case DATA_FORMAT6_SP
:
526 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
527 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, sp, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
529 case DATA_FORMAT6_PC
:
530 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>
531 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " r%d, pc, 0x%x", (OpCode
>> 8) & 7, (OpCode
& 0xff) << 2);
534 // A6.4.3 SP, SP, #<7_Bit_immed>
535 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " sp, sp, 0x%x", (OpCode
& 0x7f)*4);
538 // A6.4.3 <Rd>|<Rn>, <Rm>
539 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[Rd
| (H1
? 8:0)], gReg
[Rn
| (H2
? 8:0)]);
544 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "%a %a%a%a", imod
? "ID":"IE", ((OpCode
& BIT2
) == 0) ? "":"a", ((OpCode
& BIT1
) == 0) ? "":"i", ((OpCode
& BIT0
) == 0) ? "":"f");
549 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", (OpCode
& BIT3
) == 0 ? "LE":"BE");
553 // CB{N}Z <Rn>, <Lable>
554 Target
= ((OpCode
>> 2) & 0x3e) | (((OpCode
& BIT9
) == BIT9
) ? BIT6
: 0);
555 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[Rd
], PC
+ 4 + Target
);
560 Target
= (OpCode
& 0xff) << 2;
561 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %08x", gReg
[(OpCode
>> 8) & 7], PCAlign4 (PC
) + Target
);
568 // Thumb2 are 32-bit instructions
570 Rt
= (OpCode32
>> 12) & 0xf;
571 Rt2
= (OpCode32
>> 8) & 0xf;
572 Rd
= (OpCode32
>> 8) & 0xf;
573 Rm
= (OpCode32
& 0xf);
574 Rn
= (OpCode32
>> 16) & 0xf;
575 for (Index
= 0; Index
< sizeof (gOpThumb2
)/sizeof (THUMB_INSTRUCTIONS
); Index
++) {
576 if ((OpCode32
& gOpThumb2
[Index
].Mask
) == gOpThumb2
[Index
].OpCode
) {
578 Offset
= AsciiSPrint (Buf
, Size
, "0x%04x %-6a", OpCode32
, gOpThumb2
[Index
].Start
);
580 Offset
= AsciiSPrint (Buf
, Size
, " %-6a", gOpThumb2
[Index
].Start
);
582 switch (gOpThumb2
[Index
].AddressMode
) {
584 Cond
= gCondition
[(OpCode32
>> 22) & 0xf];
585 Buf
[Offset
-5] = *Cond
++;
586 Buf
[Offset
-4] = *Cond
;
587 // S:J2:J1:imm6:imm11:0
588 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3f000);
589 Target
|= ((OpCode32
& BIT11
) == BIT11
)? BIT19
: 0; // J2
590 Target
|= ((OpCode32
& BIT13
) == BIT13
)? BIT18
: 0; // J1
591 Target
|= ((OpCode32
& BIT26
) == BIT26
)? BIT20
: 0; // S
592 Target
= SignExtend32 (Target
, BIT20
);
593 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
596 // S:I1:I2:imm10:imm11:0
597 Target
= ((OpCode32
<< 1) & 0xffe) + ((OpCode32
>> 4) & 0x3ff000);
598 S
= (OpCode32
& BIT26
) == BIT26
;
599 J1
= (OpCode32
& BIT13
) == BIT13
;
600 J2
= (OpCode32
& BIT11
) == BIT11
;
601 Target
|= (!(J2
^ S
) ? BIT22
: 0); // I2
602 Target
|= (!(J1
^ S
) ? BIT23
: 0); // I1
603 Target
|= (S
? BIT24
: 0); // S
604 Target
= SignExtend32 (Target
, BIT24
);
605 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PC
+ 4 + Target
);
609 // BLX S:I1:I2:imm10:imm11:0
610 Target
= ((OpCode32
<< 1) & 0xffc) + ((OpCode32
>> 4) & 0x3ff000);
611 S
= (OpCode32
& BIT26
) == BIT26
;
612 J1
= (OpCode32
& BIT13
) == BIT13
;
613 J2
= (OpCode32
& BIT11
) == BIT11
;
614 Target
|= (!(J2
^ S
) ? BIT23
: 0); // I2
615 Target
|= (!(J1
^ S
) ? BIT24
: 0); // I1
616 Target
|= (S
? BIT25
: 0); // S
617 Target
= SignExtend32 (Target
, BIT25
);
618 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " 0x%08x", PCAlign4 (PC
) + Target
);
622 // <reglist> some must be zero, handled in table
623 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", ThumbMRegList (OpCode32
& 0xffff));
628 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a", gReg
[(OpCode32
>> 12) & 0xf]);
632 // <Rn>{!}, <registers>
633 W
= (OpCode32
& BIT21
) == BIT21
;
634 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, %a", gReg
[(OpCode32
>> 16) & 0xf], W
? "!":"", ThumbMRegList (OpCode32
& 0xffff));
637 case LDM_REG_IMM12_SIGNED
:
639 Target
= OpCode32
& 0xfff;
640 if ((OpCode32
& BIT23
) == 0) {
641 // U == 0 means subtrack, U == 1 means add
644 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a", gReg
[(OpCode32
>> 12) & 0xf], PCAlign4 (PC
) + Target
);
647 case LDM_REG_INDIRECT_LSL
:
648 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}
649 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a, %a", gReg
[Rt
], gReg
[Rn
], gReg
[Rm
]);
650 if (((OpCode32
>> 4) && 3) == 0) {
651 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
653 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL #%d]", (OpCode32
>> 4) && 3);
658 // <rt>, [<rn>, {, #<imm12>]}
659 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
660 if ((OpCode32
&& 0xfff) == 0) {
661 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
663 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #0x%x]", OpCode32
& 0xfff);
669 // <rt>, [<rn>, {, #<imm8>}]{!}
670 W
= (OpCode32
& BIT8
) == BIT8
;
671 U
= (OpCode32
& BIT9
) == BIT9
;
672 P
= (OpCode32
& BIT10
) == BIT10
;
673 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a", gReg
[Rt
], gReg
[Rn
]);
675 if ((OpCode32
&& 0xff) == 0) {
676 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]%a", W
?"!":"");
678 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", OpCode32
& 0xff, U
?"":"-" , W
?"!":"");
681 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "], #%a0x%x]", OpCode32
& 0xff, U
?"":"-");
685 case LDRD_REG_IMM8_SIGNED
:
686 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
687 P
= (OpCode32
& BIT24
) == BIT24
; // index = P
688 U
= (OpCode32
& BIT23
) == BIT23
;
689 W
= (OpCode32
& BIT21
) == BIT21
;
690 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, [%a", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
692 if ((OpCode32
&& 0xff) == 0) {
693 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, "]");
695 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x]%a", U
?"":"-", (OpCode32
& 0xff) << 2, W
?"!":"");
698 if ((OpCode32
&& 0xff) != 0) {
699 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", #%a0x%x", U
?"":"-", (OpCode32
& 0xff) << 2);
705 // LDRD <rt>, <rt2>, <label>
706 Target
= (OpCode32
& 0xff) << 2;
707 if ((OpCode32
& BIT23
) == 0) {
708 // U == 0 means subtrack, U == 1 means add
711 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, %a, %a", gReg
[Rt
], gReg
[Rt2
], PC
+ 4 + Target
);
716 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, [%a]", gReg
[Rt
], gReg
[Rn
]);
720 // LDREXD <Rt>, <Rt2>, [<Rn>]
721 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, [%a]", gReg
[Rt
], gReg
[Rt2
], gReg
[Rn
]);
726 W
= (OpCode32
& BIT21
) == BIT21
;
727 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " SP%a, #0x%x", W
?"!":"", OpCode32
& 0x1f);
732 W
= (OpCode32
& BIT21
) == BIT21
;
733 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a%a, #0x%x", gReg
[Rn
], W
?"!":"");
737 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
738 if ((OpCode32
& BIT20
) == BIT20
) {
739 Buf
[Offset
- 3] = 'S'; // assume %-6a
741 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 4) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
742 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, #0x%x", gReg
[Rd
], gReg
[Rn
], Target
);
746 // ADC <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
747 if ((OpCode32
& BIT20
) == BIT20
) {
748 Buf
[Offset
- 3] = 'S'; // assume %-6a
750 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
751 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a, %a", gReg
[Rd
], gReg
[Rn
], gReg
[Rm
]);
753 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
758 // ADDR <Rd>, <label>
759 Target
= (OpCode32
& 0xff) | ((OpCode32
>> 8) & 0x700) | ((OpCode
& BIT26
) == BIT26
? BIT11
: 0);
760 if ((OpCode
& (BIT23
| BIT21
)) == (BIT23
| BIT21
)) {
761 Target
= PCAlign4 (PC
) - Target
;
763 Target
= PCAlign4 (PC
) + Target
;
765 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, 0x%08x", gReg
[Rd
], Target
);
769 // CMN <Rn>, <Rm>, {,<shift> #<const>}
770 if ((OpCode32
& BIT20
) == BIT20
) {
771 Buf
[Offset
- 3] = 'S'; // assume %-6a
773 Target
= ((OpCode32
>> 6) & 3) | ((OpCode32
>> 10) & 0x1c0);
774 Offset
+= AsciiSPrint (&Buf
[Offset
], Size
- Offset
, " %a, ,%a", gReg
[Rn
], gReg
[Rm
]);
776 AsciiSPrint (&Buf
[Offset
], Size
- Offset
, ", LSL %d", gShiftType
[(OpCode
>> 5) & 3], Target
);
783 AsciiSPrint (Buf
, Size
, "0x%08x", OpCode32
);
789 DisassembleArmInstruction (
790 IN UINT32
**OpCodePtr
,
798 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
799 point to next instructin.
801 We cheat and only decode instructions that access
802 memory. If the instruction is not found we dump the instruction in hex.
804 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble.
805 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream
806 @param Extended TRUE dump hex for instruction too.
807 @param Buf Buffer to sprintf disassembly into.
808 @param Size Size of Buf in bytes.
812 DisassembleInstruction (
813 IN UINT8
**OpCodePtr
,
821 DisassembleThumbInstruction ((UINT16
**)OpCodePtr
, Buf
, Size
, Extended
);
823 DisassembleArmInstruction ((UINT32
**)OpCodePtr
, Buf
, Size
, Extended
);