]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
0f4139d5852d6b7ac0a101dc5497352aa18423f9
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ThumbDisassembler.c
1 /** @file
2 Thumb Dissassembler. Still a work in progress.
3
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.
10
11 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
12
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
17
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.
20
21 **/
22
23 #include <Base.h>
24 #include <Library/BaseLib.h>
25 #include <Library/DebugLib.h>
26 #include <Library/PrintLib.h>
27
28 extern CHAR8 *gCondition[];
29
30 extern CHAR8 *gReg[];
31
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
40 #define PUSH_FORMAT 6
41 #define POP_FORMAT 106
42 #define IMMED_8 7
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
56 #define CPS_FORMAT 20
57 #define ENDIAN_FORMAT 21
58 #define DATA_CBZ 22
59 #define ADR_FORMAT 23
60
61 // Thumb2 address modes
62 #define B_T3 200
63 #define B_T4 201
64 #define BL_T2 202
65 #define POP_T2 203
66 #define POP_T3 204
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
75 #define LDREXB 213
76 #define LDREXD 214
77 #define SRS_FORMAT 215
78 #define RFE_FORMAT 216
79 #define LDRD_REG_IMM8_SIGNED 217
80 #define ADD_IMM12 218
81 #define ADD_IMM5 219
82 #define ADR_THUMB2 220
83 #define CMN_THUMB2 221
84
85 typedef struct {
86 CHAR8 *Start;
87 UINT32 OpCode;
88 UINT32 Mask;
89 UINT32 AddressMode;
90 } THUMB_INSTRUCTIONS;
91
92 THUMB_INSTRUCTIONS gOpThumb[] = {
93 // Thumb 16-bit instrucitons
94 // Op Mask Format
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 },
104
105 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },
106
107 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },
108 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },
109
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 },
114
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 },
120
121 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },
122 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },
123 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },
124
125 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },
126 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
127 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },
128
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 },
140
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 },
146
147 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },
148 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },
149 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },
150
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 },
157
158 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },
159 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },
160 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },
161
162 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },
163 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },
164 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },
165
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 },
175
176 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },
177 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },
178 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },
179 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },
180
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 }
187
188 };
189
190 THUMB_INSTRUCTIONS gOpThumb2[] = {
191 //Instruct OpCode OpCode Mask Addressig Mode
192
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
195
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>}
217
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>
222
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>
231
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>]}
237
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>
243
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>]}
249
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>]}
258
259 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
260 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8 }, // LDRD <rt>, <rt2>, <label>
261
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>]
265
266 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // LDREXD <Rt>, <Rt2>, [<Rn>]
267
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>]}
271
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>]}
275
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>]}
281
282 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}
283
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>]
287
288 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>]
289
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>{!}
294 };
295
296 CHAR8 *gShiftType[] = {
297 "LSL",
298 "LSR",
299 "ASR",
300 "ROR"
301 };
302
303 CHAR8 mThumbMregListStr[4*15 + 1];
304
305 CHAR8 *
306 ThumbMRegList (
307 UINT32 RegBitMask
308 )
309 {
310 UINTN Index, Start, End;
311 CHAR8 *Str;
312 BOOLEAN First;
313
314 Str = mThumbMregListStr;
315 *Str = '\0';
316 AsciiStrCat (Str, "{");
317
318 for (Index = 0, First = TRUE; Index <= 15; Index++) {
319 if ((RegBitMask & (1 << Index)) != 0) {
320 Start = End = Index;
321 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {
322 End = Index;
323 }
324
325 if (!First) {
326 AsciiStrCat (Str, ",");
327 } else {
328 First = FALSE;
329 }
330
331 if (Start == End) {
332 AsciiStrCat (Str, gReg[Start]);
333 } else {
334 AsciiStrCat (Str, gReg[Start]);
335 AsciiStrCat (Str, "-");
336 AsciiStrCat (Str, gReg[End]);
337 }
338 }
339 }
340 if (First) {
341 AsciiStrCat (Str, "ERROR");
342 }
343 AsciiStrCat (Str, "}");
344
345 // BugBug: Make caller pass in buffer it is cleaner
346 return mThumbMregListStr;
347 }
348
349 UINT32
350 SignExtend32 (
351 IN UINT32 Data,
352 IN UINT32 TopBit
353 )
354 {
355 if (((Data & TopBit) == 0) || (TopBit == BIT31)) {
356 return Data;
357 }
358
359 do {
360 TopBit <<= 1;
361 Data |= TopBit;
362 } while ((TopBit & BIT31) != BIT31);
363
364 return Data;
365 }
366
367 //
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
371 //
372 PCAlign4 (
373 IN UINT32 Data
374 )
375 {
376 return (Data + 4) & 0xfffffffc;
377 }
378
379 /**
380 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
381 point to next instructin.
382
383 We cheat and only decode instructions that access
384 memory. If the instruction is not found we dump the instruction in hex.
385
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.
390
391 **/
392 VOID
393 DisassembleThumbInstruction (
394 IN UINT16 **OpCodePtrPtr,
395 OUT CHAR8 *Buf,
396 OUT UINTN Size,
397 IN BOOLEAN Extended
398 )
399 {
400 UINT16 *OpCodePtr;
401 UINT16 OpCode;
402 UINT32 OpCode32;
403 UINT32 Index;
404 UINT32 Offset;
405 UINT16 Rd, Rn, Rm, Rt, Rt2;
406 BOOLEAN H1, H2, imod;
407 UINT32 PC, Target;
408 CHAR8 *Cond;
409 BOOLEAN S, J1, J2, P, U, W;
410
411 OpCodePtr = *OpCodePtrPtr;
412 OpCode = **OpCodePtrPtr;
413
414 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
415 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);
416
417 // These register names match branch form, but not others
418 Rd = OpCode & 0x7;
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;
425
426 // Increment by the minimum instruction size, Thumb2 could be bigger
427 *OpCodePtrPtr += 1;
428
429 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {
430 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {
431 if (Extended) {
432 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start);
433 } else {
434 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start);
435 }
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);
440 return;
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);
444 return;
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);
448 return;
449
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);
453 return;
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);
458 return;
459 case LOAD_STORE_FORMAT4:
460 // Rt, [SP, #imm8]
461 Target = (OpCode & 0xff) << 2;
462 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target);
463 return;
464
465 case LOAD_STORE_MULTIPLE_FORMAT1:
466 // <Rn>!, {r0-r7}
467 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff));
468 return;
469
470 case POP_FORMAT:
471 // POP {r0-r7,pc}
472 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0)));
473 return;
474
475 case PUSH_FORMAT:
476 // PUSH {r0-r7,lr}
477 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0)));
478 return;
479
480
481 case IMMED_8:
482 // A6.7 <immed_8>
483 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
484 return;
485
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));
493 return;
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));
497 return;
498
499 case BRANCH_EXCHANGE:
500 // A6.3.3 BX|BLX <Rm>
501 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]);
502 return;
503
504 case DATA_FORMAT1:
505 // A6.4.3 <Rd>, <Rn>, <Rm>
506 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
507 return;
508 case DATA_FORMAT2:
509 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
510 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
511 return;
512 case DATA_FORMAT3:
513 // A6.4.3 <Rd>|<Rn>, #imm8
514 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
515 return;
516 case DATA_FORMAT4:
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);
519 return;
520 case DATA_FORMAT5:
521 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
522 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
523 return;
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);
527 return;
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);
531 return;
532 case DATA_FORMAT7:
533 // A6.4.3 SP, SP, #<7_Bit_immed>
534 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4);
535 return;
536 case DATA_FORMAT8:
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)]);
539 return;
540
541 case CPS_FORMAT:
542 // A7.1.24
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");
544 return;
545
546 case ENDIAN_FORMAT:
547 // A7.1.24
548 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
549 return;
550
551 case DATA_CBZ:
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);
555 return;
556
557 case ADR_FORMAT:
558 // ADR <Rd>, <Label>
559 Target = (OpCode & 0xff) << 2;
560 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target);
561 return;
562 }
563 }
564 }
565
566
567 // Thumb2 are 32-bit instructions
568 *OpCodePtrPtr += 1;
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) {
576 if (Extended) {
577 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start);
578 } else {
579 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start);
580 }
581 switch (gOpThumb2[Index].AddressMode) {
582 case B_T3:
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);
593 return;
594 case B_T4:
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);
605 return;
606
607 case BL_T2:
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);
618 return;
619
620 case POP_T2:
621 // <reglist> some must be zero, handled in table
622 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));
623 return;
624
625 case POP_T3:
626 // <register>
627 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);
628 return;
629
630 case STM_FORMAT:
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));
634 return;
635
636 case LDM_REG_IMM12_SIGNED:
637 // <rt>, <label>
638 Target = OpCode32 & 0xfff;
639 if ((OpCode32 & BIT23) == 0) {
640 // U == 0 means subtrack, U == 1 means add
641 Target = -Target;
642 }
643 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target);
644 return;
645
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, "]");
651 } else {
652 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) && 3);
653 }
654 return;
655
656 case LDM_REG_IMM12:
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, "]");
661 } else {
662 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);
663 }
664 return;
665
666 case LDM_REG_IMM8:
667 ASSERT (FALSE);
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]);
673 if (P) {
674 if ((OpCode32 && 0xff) == 0) {
675 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");
676 } else {
677 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", OpCode32 & 0xff, U?"":"-" , W?"!":"");
678 }
679 } else {
680 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x]", OpCode32 & 0xff, U?"":"-");
681 }
682 return;
683
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]);
690 if (P) {
691 if ((OpCode32 && 0xff) == 0) {
692 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
693 } else {
694 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");
695 }
696 } else {
697 if ((OpCode32 && 0xff) != 0) {
698 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);
699 }
700 }
701 return;
702
703 case LDRD_REG_IMM8:
704 // LDRD <rt>, <rt2>, <label>
705 Target = (OpCode32 & 0xff) << 2;
706 if ((OpCode32 & BIT23) == 0) {
707 // U == 0 means subtrack, U == 1 means add
708 Target = -Target;
709 }
710 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);
711 return;
712
713 case LDREXB:
714 // LDREXB <Rt>, [Rn]
715 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
716 return;
717
718 case LDREXD:
719 // LDREXD <Rt>, <Rt2>, [<Rn>]
720 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
721 return;
722
723 case SRS_FORMAT:
724 // SP{!}, #<mode>
725 W = (OpCode32 & BIT21) == BIT21;
726 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);
727 return;
728
729 case RFE_FORMAT:
730 // <Rn>{!}
731 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");
732 return;
733
734 case ADD_IMM12:
735 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
736 if ((OpCode32 & BIT20) == BIT20) {
737 Buf[Offset - 3] = 'S'; // assume %-6a
738 }
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);
741 return;
742
743 case ADD_IMM5:
744 // ADC <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
745 if ((OpCode32 & BIT20) == BIT20) {
746 Buf[Offset - 3] = 'S'; // assume %-6a
747 }
748 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
749 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, %a", gReg[Rd], gReg[Rn], gReg[Rm]);
750 if (Target != 0) {
751 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
752 }
753 return;
754
755 case ADR_THUMB2:
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;
760 } else {
761 Target = PCAlign4 (PC) + Target;
762 }
763 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target);
764 return;
765
766 case CMN_THUMB2:
767 // CMN <Rn>, <Rm>, {,<shift> #<const>}
768 if ((OpCode32 & BIT20) == BIT20) {
769 Buf[Offset - 3] = 'S'; // assume %-6a
770 }
771 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
772 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a", gReg[Rn], gReg[Rm]);
773 if (Target != 0) {
774 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
775 }
776 return;
777 }
778 }
779 }
780
781 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
782 }
783
784
785
786 VOID
787 DisassembleArmInstruction (
788 IN UINT32 **OpCodePtr,
789 OUT CHAR8 *Buf,
790 OUT UINTN Size,
791 IN BOOLEAN Extended
792 );
793
794
795 /**
796 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
797 point to next instructin.
798
799 We cheat and only decode instructions that access
800 memory. If the instruction is not found we dump the instruction in hex.
801
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.
807
808 **/
809 VOID
810 DisassembleInstruction (
811 IN UINT8 **OpCodePtr,
812 IN BOOLEAN Thumb,
813 IN BOOLEAN Extended,
814 OUT CHAR8 *Buf,
815 OUT UINTN Size
816 )
817 {
818 if (Thumb) {
819 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, Extended);
820 } else {
821 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
822 }
823 }
824