]> git.proxmox.com Git - mirror_edk2.git/blob - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
74154fc2197e3637e24335ebf35a0b4f7ffe4bc6
[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 UINT32
373 PCAlign4 (
374 IN UINT32 Data
375 )
376 {
377 return (Data + 4) & 0xfffffffc;
378 }
379
380 /**
381 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
382 point to next instructin.
383
384 We cheat and only decode instructions that access
385 memory. If the instruction is not found we dump the instruction in hex.
386
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.
391
392 **/
393 VOID
394 DisassembleThumbInstruction (
395 IN UINT16 **OpCodePtrPtr,
396 OUT CHAR8 *Buf,
397 OUT UINTN Size,
398 IN BOOLEAN Extended
399 )
400 {
401 UINT16 *OpCodePtr;
402 UINT16 OpCode;
403 UINT32 OpCode32;
404 UINT32 Index;
405 UINT32 Offset;
406 UINT16 Rd, Rn, Rm, Rt, Rt2;
407 BOOLEAN H1, H2, imod;
408 UINT32 PC, Target;
409 CHAR8 *Cond;
410 BOOLEAN S, J1, J2, P, U, W;
411
412 OpCodePtr = *OpCodePtrPtr;
413 OpCode = **OpCodePtrPtr;
414
415 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.
416 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);
417
418 // These register names match branch form, but not others
419 Rd = OpCode & 0x7;
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;
426
427 // Increment by the minimum instruction size, Thumb2 could be bigger
428 *OpCodePtrPtr += 1;
429
430 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {
431 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {
432 if (Extended) {
433 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start);
434 } else {
435 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start);
436 }
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);
441 return;
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);
445 return;
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);
449 return;
450
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);
454 return;
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);
459 return;
460 case LOAD_STORE_FORMAT4:
461 // Rt, [SP, #imm8]
462 Target = (OpCode & 0xff) << 2;
463 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target);
464 return;
465
466 case LOAD_STORE_MULTIPLE_FORMAT1:
467 // <Rn>!, {r0-r7}
468 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff));
469 return;
470
471 case POP_FORMAT:
472 // POP {r0-r7,pc}
473 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0)));
474 return;
475
476 case PUSH_FORMAT:
477 // PUSH {r0-r7,lr}
478 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0)));
479 return;
480
481
482 case IMMED_8:
483 // A6.7 <immed_8>
484 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff);
485 return;
486
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));
494 return;
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));
498 return;
499
500 case BRANCH_EXCHANGE:
501 // A6.3.3 BX|BLX <Rm>
502 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]);
503 return;
504
505 case DATA_FORMAT1:
506 // A6.4.3 <Rd>, <Rn>, <Rm>
507 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm);
508 return;
509 case DATA_FORMAT2:
510 // A6.4.3 <Rd>, <Rn>, #3_bit_immed
511 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm);
512 return;
513 case DATA_FORMAT3:
514 // A6.4.3 <Rd>|<Rn>, #imm8
515 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff);
516 return;
517 case DATA_FORMAT4:
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);
520 return;
521 case DATA_FORMAT5:
522 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>
523 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn);
524 return;
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);
528 return;
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);
532 return;
533 case DATA_FORMAT7:
534 // A6.4.3 SP, SP, #<7_Bit_immed>
535 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4);
536 return;
537 case DATA_FORMAT8:
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)]);
540 return;
541
542 case CPS_FORMAT:
543 // A7.1.24
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");
545 return;
546
547 case ENDIAN_FORMAT:
548 // A7.1.24
549 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE");
550 return;
551
552 case DATA_CBZ:
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);
556 return;
557
558 case ADR_FORMAT:
559 // ADR <Rd>, <Label>
560 Target = (OpCode & 0xff) << 2;
561 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PCAlign4 (PC) + Target);
562 return;
563 }
564 }
565 }
566
567
568 // Thumb2 are 32-bit instructions
569 *OpCodePtrPtr += 1;
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) {
577 if (Extended) {
578 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start);
579 } else {
580 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start);
581 }
582 switch (gOpThumb2[Index].AddressMode) {
583 case B_T3:
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);
594 return;
595 case B_T4:
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);
606 return;
607
608 case BL_T2:
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);
619 return;
620
621 case POP_T2:
622 // <reglist> some must be zero, handled in table
623 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));
624 return;
625
626 case POP_T3:
627 // <register>
628 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);
629 return;
630
631 case STM_FORMAT:
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));
635 return;
636
637 case LDM_REG_IMM12_SIGNED:
638 // <rt>, <label>
639 Target = OpCode32 & 0xfff;
640 if ((OpCode32 & BIT23) == 0) {
641 // U == 0 means subtrack, U == 1 means add
642 Target = -Target;
643 }
644 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PCAlign4 (PC) + Target);
645 return;
646
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, "]");
652 } else {
653 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) && 3);
654 }
655 return;
656
657 case LDM_REG_IMM12:
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, "]");
662 } else {
663 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);
664 }
665 return;
666
667 case LDM_REG_IMM8:
668 ASSERT (FALSE);
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]);
674 if (P) {
675 if ((OpCode32 && 0xff) == 0) {
676 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");
677 } else {
678 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", OpCode32 & 0xff, U?"":"-" , W?"!":"");
679 }
680 } else {
681 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x]", OpCode32 & 0xff, U?"":"-");
682 }
683 return;
684
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]);
691 if (P) {
692 if ((OpCode32 && 0xff) == 0) {
693 AsciiSPrint (&Buf[Offset], Size - Offset, "]");
694 } else {
695 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");
696 }
697 } else {
698 if ((OpCode32 && 0xff) != 0) {
699 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);
700 }
701 }
702 return;
703
704 case LDRD_REG_IMM8:
705 // LDRD <rt>, <rt2>, <label>
706 Target = (OpCode32 & 0xff) << 2;
707 if ((OpCode32 & BIT23) == 0) {
708 // U == 0 means subtrack, U == 1 means add
709 Target = -Target;
710 }
711 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);
712 return;
713
714 case LDREXB:
715 // LDREXB <Rt>, [Rn]
716 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);
717 return;
718
719 case LDREXD:
720 // LDREXD <Rt>, <Rt2>, [<Rn>]
721 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);
722 return;
723
724 case SRS_FORMAT:
725 // SP{!}, #<mode>
726 W = (OpCode32 & BIT21) == BIT21;
727 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);
728 return;
729
730 case RFE_FORMAT:
731 // <Rn>{!}
732 W = (OpCode32 & BIT21) == BIT21;
733 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");
734 return;
735
736 case ADD_IMM12:
737 // ADD{S} <Rd>, <Rn>, #<const> i:imm3:imm8
738 if ((OpCode32 & BIT20) == BIT20) {
739 Buf[Offset - 3] = 'S'; // assume %-6a
740 }
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);
743 return;
744
745 case ADD_IMM5:
746 // ADC <Rd>, <Rn>, <Rm> {,LSL #<const>} imm3:imm2
747 if ((OpCode32 & BIT20) == BIT20) {
748 Buf[Offset - 3] = 'S'; // assume %-6a
749 }
750 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
751 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, %a", gReg[Rd], gReg[Rn], gReg[Rm]);
752 if (Target != 0) {
753 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
754 }
755 return;
756
757 case ADR_THUMB2:
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;
762 } else {
763 Target = PCAlign4 (PC) + Target;
764 }
765 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, 0x%08x", gReg[Rd], Target);
766 return;
767
768 case CMN_THUMB2:
769 // CMN <Rn>, <Rm>, {,<shift> #<const>}
770 if ((OpCode32 & BIT20) == BIT20) {
771 Buf[Offset - 3] = 'S'; // assume %-6a
772 }
773 Target = ((OpCode32 >> 6) & 3) | ((OpCode32 >> 10) & 0x1c0);
774 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a", gReg[Rn], gReg[Rm]);
775 if (Target != 0) {
776 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL %d", gShiftType[(OpCode >> 5) & 3], Target);
777 }
778 return;
779 }
780 }
781 }
782
783 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);
784 }
785
786
787
788 VOID
789 DisassembleArmInstruction (
790 IN UINT32 **OpCodePtr,
791 OUT CHAR8 *Buf,
792 OUT UINTN Size,
793 IN BOOLEAN Extended
794 );
795
796
797 /**
798 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
799 point to next instructin.
800
801 We cheat and only decode instructions that access
802 memory. If the instruction is not found we dump the instruction in hex.
803
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.
809
810 **/
811 VOID
812 DisassembleInstruction (
813 IN UINT8 **OpCodePtr,
814 IN BOOLEAN Thumb,
815 IN BOOLEAN Extended,
816 OUT CHAR8 *Buf,
817 OUT UINTN Size
818 )
819 {
820 if (Thumb) {
821 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, Extended);
822 } else {
823 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);
824 }
825 }
826