]> git.proxmox.com Git - mirror_edk2.git/blame - ArmPkg/Library/ArmDisassemblerLib/ThumbDisassembler.c
Added Thumb2 loads and stores to Disassmebler
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ThumbDisassembler.c
CommitLineData
6f72e28d 1/** @file\r
b32fecd2 2 Thumb Dissassembler. Still a work in progress.\r
3\r
4 Wrong output is a bug, so please fix it. \r
5 Hex output means there is not yet an entry or a decode bug.\r
6 gOpThumb[] are Thumb 16-bit, and gOpThumb2[] work on the 32-bit \r
7 16-bit stream of Thumb2 instruction. Then there are big case \r
8 statements to print everything out. If you are adding instructions\r
9 try to reuse existing case entries if possible.\r
6f72e28d 10\r
11 Copyright (c) 2008-2010, Apple Inc. All rights reserved.\r
12 \r
13 All rights reserved. This program and the accompanying materials\r
14 are licensed and made available under the terms and conditions of the BSD License\r
15 which accompanies this distribution. The full text of the license may be found at\r
16 http://opensource.org/licenses/bsd-license.php\r
17\r
18 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
19 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
20\r
21**/\r
22\r
23#include <Base.h>\r
24#include <Library/BaseLib.h>\r
25#include <Library/PrintLib.h>\r
26\r
7c34497d 27extern CHAR8 *gCondition[];\r
28\r
6f72e28d 29extern CHAR8 *gReg[];\r
30\r
b32fecd2 31// Thumb address modes\r
6f72e28d 32#define LOAD_STORE_FORMAT1 1\r
33#define LOAD_STORE_FORMAT2 2\r
34#define LOAD_STORE_FORMAT3 3\r
35#define LOAD_STORE_FORMAT4 4\r
36#define LOAD_STORE_MULTIPLE_FORMAT1 5 \r
7c34497d 37#define PUSH_FORMAT 6 \r
38#define POP_FORMAT 106 \r
6f72e28d 39#define IMMED_8 7\r
40#define CONDITIONAL_BRANCH 8\r
41#define UNCONDITIONAL_BRANCH 9\r
42#define UNCONDITIONAL_BRANCH_SHORT 109\r
43#define BRANCH_EXCHANGE 10\r
44#define DATA_FORMAT1 11\r
45#define DATA_FORMAT2 12\r
46#define DATA_FORMAT3 13\r
47#define DATA_FORMAT4 14\r
48#define DATA_FORMAT5 15\r
49#define DATA_FORMAT6_SP 16\r
50#define DATA_FORMAT6_PC 116\r
51#define DATA_FORMAT7 17\r
52#define DATA_FORMAT8 19\r
53#define CPS_FORMAT 20\r
54#define ENDIAN_FORMAT 21\r
b32fecd2 55#define DATA_CBZ 22\r
56#define ADR_FORMAT 23\r
57\r
58// Thumb2 address modes\r
7c34497d 59#define B_T3 200\r
60#define B_T4 201\r
61#define BL_T2 202\r
b32fecd2 62#define POP_T2 203\r
63#define POP_T3 204\r
64#define STM_FORMAT 205\r
65#define LDM_REG_IMM12_SIGNED 206\r
66#define LDM_REG_IMM12_LSL 207\r
67#define LDM_REG_IMM8 208\r
68#define LDM_REG_IMM12 209\r
69#define LDM_REG_INDIRECT_LSL 210\r
70#define LDM_REG_IMM8_SIGNED 211\r
71#define LDRD_REG_IMM8 212\r
72#define LDREXB 213\r
73#define LDREXD 214\r
74#define SRS_FORMAT 215\r
75#define RFE_FORMAT 216\r
76#define LDRD_REG_IMM8_SIGNED 217\r
77\r
78\r
7c34497d 79\r
6f72e28d 80\r
81typedef struct {\r
82 CHAR8 *Start;\r
83 UINT32 OpCode;\r
84 UINT32 Mask;\r
85 UINT32 AddressMode;\r
86} THUMB_INSTRUCTIONS;\r
87\r
097bd461 88THUMB_INSTRUCTIONS gOpThumb[] = {\r
6f72e28d 89// Thumb 16-bit instrucitons\r
b32fecd2 90// Op Mask Format\r
6f72e28d 91 { "ADC" , 0x4140, 0xffc0, DATA_FORMAT5 },\r
b32fecd2 92 { "ADR", 0xa000, 0xf800, ADR_FORMAT }, // ADR <Rd>, <label>\r
6f72e28d 93 { "ADD" , 0x1c00, 0xfe00, DATA_FORMAT2 },\r
94 { "ADD" , 0x3000, 0xf800, DATA_FORMAT3 },\r
95 { "ADD" , 0x1800, 0xfe00, DATA_FORMAT1 },\r
96 { "ADD" , 0x4400, 0xff00, DATA_FORMAT8 }, // A8.6.9\r
97 { "ADD" , 0xa000, 0xf100, DATA_FORMAT6_PC },\r
7c34497d 98 { "ADD" , 0xa800, 0xf800, DATA_FORMAT6_SP }, \r
99 { "ADD" , 0xb000, 0xff80, DATA_FORMAT7 },\r
6f72e28d 100\r
101 { "AND" , 0x4000, 0xffc0, DATA_FORMAT5 },\r
102\r
103 { "ASR" , 0x1000, 0xf800, DATA_FORMAT4 },\r
104 { "ASR" , 0x4100, 0xffc0, DATA_FORMAT5 },\r
105\r
106 { "B" , 0xd000, 0xf000, CONDITIONAL_BRANCH },\r
7c34497d 107 { "B" , 0xe000, 0xf800, UNCONDITIONAL_BRANCH_SHORT },\r
6f72e28d 108 { "BLX" , 0x4780, 0xff80, BRANCH_EXCHANGE },\r
7c34497d 109 { "BX" , 0x4700, 0xff87, BRANCH_EXCHANGE },\r
6f72e28d 110\r
111 { "BIC" , 0x4380, 0xffc0, DATA_FORMAT5 },\r
112 { "BKPT", 0xdf00, 0xff00, IMMED_8 },\r
b32fecd2 113 { "CBZ", 0xb100, 0xfd00, DATA_CBZ },\r
114 { "CBNZ", 0xb900, 0xfd00, DATA_CBZ },\r
6f72e28d 115 { "CMN" , 0x42c0, 0xffc0, DATA_FORMAT5 },\r
116\r
7c34497d 117 { "CMP" , 0x2800, 0xf800, DATA_FORMAT3 },\r
6f72e28d 118 { "CMP" , 0x4280, 0xffc0, DATA_FORMAT5 },\r
119 { "CMP" , 0x4500, 0xff00, DATA_FORMAT8 },\r
120\r
121 { "CPS" , 0xb660, 0xffe8, CPS_FORMAT },\r
7c34497d 122 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },\r
6f72e28d 123 { "EOR" , 0x4040, 0xffc0, DATA_FORMAT5 },\r
124\r
125 { "LDMIA" , 0xc800, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },\r
126 { "LDR" , 0x6800, 0xf800, LOAD_STORE_FORMAT1 },\r
127 { "LDR" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },\r
128 { "LDR" , 0x4800, 0xf800, LOAD_STORE_FORMAT3 },\r
129 { "LDR" , 0x9800, 0xf800, LOAD_STORE_FORMAT4 },\r
130 { "LDRB" , 0x7800, 0xf800, LOAD_STORE_FORMAT1 },\r
131 { "LDRB" , 0x5c00, 0xfe00, LOAD_STORE_FORMAT2 },\r
132 { "LDRH" , 0x8800, 0xf800, LOAD_STORE_FORMAT1 },\r
133 { "LDRH" , 0x7a00, 0xfe00, LOAD_STORE_FORMAT2 },\r
134 { "LDRSB" , 0x5600, 0xfe00, LOAD_STORE_FORMAT2 },\r
135 { "LDRSH" , 0x5e00, 0xfe00, LOAD_STORE_FORMAT2 },\r
136 \r
7c34497d 137 { "MOVS", 0x0000, 0xffc0, DATA_FORMAT5 }, // LSL with imm5 == 0 is a MOVS, so this must go before LSL\r
6f72e28d 138 { "LSL" , 0x0000, 0xf800, DATA_FORMAT4 },\r
139 { "LSL" , 0x4080, 0xffc0, DATA_FORMAT5 },\r
140 { "LSR" , 0x0001, 0xf800, DATA_FORMAT4 },\r
141 { "LSR" , 0x40c0, 0xffc0, DATA_FORMAT5 },\r
142\r
7c34497d 143 { "MOVS", 0x2000, 0xf800, DATA_FORMAT3 },\r
6f72e28d 144 { "MOV" , 0x1c00, 0xffc0, DATA_FORMAT3 },\r
145 { "MOV" , 0x4600, 0xff00, DATA_FORMAT8 },\r
146\r
147 { "MUL" , 0x4340, 0xffc0, DATA_FORMAT5 },\r
148 { "MVN" , 0x41c0, 0xffc0, DATA_FORMAT5 },\r
149 { "NEG" , 0x4240, 0xffc0, DATA_FORMAT5 },\r
150 { "ORR" , 0x4180, 0xffc0, DATA_FORMAT5 },\r
7c34497d 151 { "POP" , 0xbc00, 0xfe00, POP_FORMAT },\r
152 { "PUSH", 0xb400, 0xfe00, PUSH_FORMAT },\r
153\r
6f72e28d 154 { "REV" , 0xba00, 0xffc0, DATA_FORMAT5 },\r
155 { "REV16" , 0xba40, 0xffc0, DATA_FORMAT5 },\r
156 { "REVSH" , 0xbac0, 0xffc0, DATA_FORMAT5 },\r
157\r
7c34497d 158 { "ROR" , 0x41c0, 0xffc0, DATA_FORMAT5 },\r
159 { "SBC" , 0x4180, 0xffc0, DATA_FORMAT5 },\r
160 { "SETEND" , 0xb650, 0xfff0, ENDIAN_FORMAT },\r
6f72e28d 161\r
162 { "STMIA" , 0xc000, 0xf800, LOAD_STORE_MULTIPLE_FORMAT1 },\r
163 { "STR" , 0x6000, 0xf800, LOAD_STORE_FORMAT1 },\r
164 { "STR" , 0x5000, 0xfe00, LOAD_STORE_FORMAT2 },\r
165 { "STR" , 0x4000, 0xf800, LOAD_STORE_FORMAT3 },\r
166 { "STR" , 0x9000, 0xf800, LOAD_STORE_FORMAT4 },\r
167 { "STRB" , 0x7000, 0xf800, LOAD_STORE_FORMAT1 },\r
168 { "STRB" , 0x5800, 0xfe00, LOAD_STORE_FORMAT2 },\r
169 { "STRH" , 0x8000, 0xf800, LOAD_STORE_FORMAT1 },\r
170 { "STRH" , 0x5200, 0xfe00, LOAD_STORE_FORMAT2 },\r
171\r
172 { "SUB" , 0x1e00, 0xfe00, DATA_FORMAT2 },\r
173 { "SUB" , 0x3800, 0xf800, DATA_FORMAT3 },\r
174 { "SUB" , 0x1a00, 0xfe00, DATA_FORMAT1 },\r
175 { "SUB" , 0xb080, 0xff80, DATA_FORMAT7 },\r
176\r
177 { "SWI" , 0xdf00, 0xff00, IMMED_8 },\r
178 { "SXTB", 0xb240, 0xffc0, DATA_FORMAT5 },\r
179 { "SXTH", 0xb200, 0xffc0, DATA_FORMAT5 },\r
180 { "TST" , 0x4200, 0xffc0, DATA_FORMAT5 },\r
181 { "UXTB", 0xb2c0, 0xffc0, DATA_FORMAT5 },\r
182 { "UXTH", 0xb280, 0xffc0, DATA_FORMAT5 }\r
b32fecd2 183\r
097bd461 184};\r
185\r
097bd461 186THUMB_INSTRUCTIONS gOpThumb2[] = {\r
b32fecd2 187//Instruct OpCode OpCode Mask Addressig Mode\r
188 { "B", 0xf0008000, 0xf800d000, B_T3 }, // B<c> <label>\r
189 { "B", 0xf0009000, 0xf800d000, B_T4 }, // B<c> <label>\r
190 { "BL", 0xf000d000, 0xf800d000, B_T4 }, // BL<c> <label>\r
191 { "BLX", 0xf000c000, 0xf800d000, BL_T2 }, // BLX<c> <label>\r
192\r
193 { "POP", 0xe8bd0000, 0xffff2000, POP_T2 }, // POP <registers>\r
194 { "POP", 0xf85d0b04, 0xffff0fff, POP_T3 }, // POP <register>\r
195 { "PUSH", 0xe8ad0000, 0xffffa000, POP_T2 }, // PUSH <registers>\r
196 { "PUSH", 0xf84d0d04, 0xffff0fff, POP_T3 }, // PUSH <register>\r
197 { "STM" , 0xe8800000, 0xffd0a000, STM_FORMAT }, // STM <Rn>{!},<registers>\r
198 { "STMDB", 0xe9800000, 0xffd0a000, STM_FORMAT }, // STMDB <Rn>{!},<registers>\r
199 { "LDM" , 0xe8900000, 0xffd02000, STM_FORMAT }, // LDM <Rn>{!},<registers>\r
200 { "LDMDB", 0xe9100000, 0xffd02000, STM_FORMAT }, // LDMDB <Rn>{!},<registers>\r
6f72e28d 201 \r
b32fecd2 202 { "LDR", 0xf8d00000, 0xfff00000, LDM_REG_IMM12 }, // LDR <rt>, [<rn>, {, #<imm12>]}\r
203 { "LDRB", 0xf8900000, 0xfff00000, LDM_REG_IMM12 }, // LDRB <rt>, [<rn>, {, #<imm12>]}\r
204 { "LDRH", 0xf8b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRH <rt>, [<rn>, {, #<imm12>]}\r
205 { "LDRSB", 0xf9900000, 0xfff00000, LDM_REG_IMM12 }, // LDRSB <rt>, [<rn>, {, #<imm12>]}\r
206 { "LDRSH", 0xf9b00000, 0xfff00000, LDM_REG_IMM12 }, // LDRSH <rt>, [<rn>, {, #<imm12>]}\r
207\r
208 { "LDR", 0xf85f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDR <Rt>, <label> \r
209 { "LDRB", 0xf81f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRB <Rt>, <label> \r
210 { "LDRH", 0xf83f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRH <Rt>, <label> \r
211 { "LDRSB", 0xf91f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label> \r
212 { "LDRSH", 0xf93f0000, 0xff7f0000, LDM_REG_IMM12_SIGNED }, // LDRSB <Rt>, <label> \r
6f72e28d 213 \r
b32fecd2 214 { "LDR", 0xf8500000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDR <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
215 { "LDRB", 0xf8100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
216 { "LDRH", 0xf8300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
217 { "LDRSB", 0xf9100000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
218 { "LDRSH", 0xf9300000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // LDRSH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
219\r
220 { "LDR", 0xf8500800, 0xfff00800, LDM_REG_IMM8 }, // LDR <rt>, [<rn>, {, #<imm8>]}\r
221 { "LDRBT", 0xf8100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRBT <rt>, [<rn>, {, #<imm8>]}\r
222 { "LDRHT", 0xf8300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]}\r
223 { "LDRSB", 0xf9900800, 0xfff00800, LDM_REG_IMM8 }, // LDRHT <rt>, [<rn>, {, #<imm8>]} {!} form? \r
224 { "LDRSBT",0xf9100e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRHBT <rt>, [<rn>, {, #<imm8>]} {!} form? \r
225 { "LDRSH" ,0xf9300800, 0xfff00800, LDM_REG_IMM8 }, // LDRSH <rt>, [<rn>, {, #<imm8>]} \r
226 { "LDRSHT",0xf9300e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRSHT <rt>, [<rn>, {, #<imm8>]} \r
227 { "LDRT", 0xf8500e00, 0xfff00f00, LDM_REG_IMM8 }, // LDRT <rt>, [<rn>, {, #<imm8>]} \r
228\r
229 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
230 { "LDRD", 0xe8500000, 0xfe500000, LDRD_REG_IMM8 }, // LDRD <rt>, <rt2>, <label>\r
231 \r
232 { "LDREX", 0xe8500f00, 0xfff00f00, LDM_REG_IMM8 }, // LDREX <Rt>, [Rn, {#imm8}]] \r
233 { "LDREXB", 0xe8d00f4f, 0xfff00fff, LDREXB }, // LDREXB <Rt>, [<Rn>] \r
234 { "LDREXH", 0xe8d00f5f, 0xfff00fff, LDREXB }, // LDREXH <Rt>, [<Rn>] \r
235 \r
236 { "LDREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // LDREXD <Rt>, <Rt2>, [<Rn>] \r
6f72e28d 237\r
b32fecd2 238 { "STR", 0xf8c00000, 0xfff00000, LDM_REG_IMM12 }, // STR <rt>, [<rn>, {, #<imm12>]} \r
239 { "STRB", 0xf8800000, 0xfff00000, LDM_REG_IMM12 }, // STRB <rt>, [<rn>, {, #<imm12>]}\r
240 { "STRH", 0xf8a00000, 0xfff00000, LDM_REG_IMM12 }, // STRH <rt>, [<rn>, {, #<imm12>]}\r
241 \r
242 { "STR", 0xf8400000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STR <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
243 { "STRB", 0xf8000000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRB <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
244 { "STRH", 0xf8200000, 0xfff00fc0, LDM_REG_INDIRECT_LSL }, // STRH <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
6f72e28d 245\r
b32fecd2 246 { "STR", 0xf8400800, 0xfff00800, LDM_REG_IMM8 }, // STR <rt>, [<rn>, {, #<imm8>]}\r
247 { "STRH", 0xf8200800, 0xfff00800, LDM_REG_IMM8 }, // STRH <rt>, [<rn>, {, #<imm8>]}\r
248 { "STRBT", 0xf8000e00, 0xfff00f00, LDM_REG_IMM8 }, // STRBT <rt>, [<rn>, {, #<imm8>]}\r
249 { "STRHT", 0xf8200e00, 0xfff00f00, LDM_REG_IMM8 }, // STRHT <rt>, [<rn>, {, #<imm8>]}\r
250 { "STRT", 0xf8400e00, 0xfff00f00, LDM_REG_IMM8 }, // STRT <rt>, [<rn>, {, #<imm8>]} \r
6f72e28d 251\r
b32fecd2 252 { "STRD", 0xe8400000, 0xfe500000, LDRD_REG_IMM8_SIGNED }, // STRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
6f72e28d 253\r
b32fecd2 254 { "STREX", 0xe8400f00, 0xfff00f00, LDM_REG_IMM8 }, // STREX <Rt>, [Rn, {#imm8}]] \r
255 { "STREXB", 0xe8c00f4f, 0xfff00fff, LDREXB }, // STREXB <Rd>, <Rt>, [<Rn>] \r
256 { "STREXH", 0xe8c00f5f, 0xfff00fff, LDREXB }, // STREXH <Rd>, <Rt>, [<Rn>] \r
257 \r
258 { "STREXD", 0xe8d00f4f, 0xfff00fff, LDREXD }, // STREXD <Rd>, <Rt>, <Rt2>, [<Rn>] \r
6f72e28d 259\r
b32fecd2 260 { "SRSDB", 0xe80dc000, 0xffdffff0, SRS_FORMAT }, // SRSDB<c> SP{!},#<mode>\r
261 { "SRS" , 0xe98dc000, 0xffdffff0, SRS_FORMAT }, // SRS{IA}<c> SP{!},#<mode>\r
262 { "RFEDB", 0xe810c000, 0xffd0ffff, RFE_FORMAT }, // RFEDB<c> <Rn>{!}\r
263 { "RFE" , 0xe990c000, 0xffd0ffff, RFE_FORMAT } // RFE{IA}<c> <Rn>{!}\r
7c34497d 264};\r
6f72e28d 265\r
266CHAR8 mThumbMregListStr[4*15 + 1];\r
267\r
268CHAR8 *\r
269ThumbMRegList (\r
7c34497d 270 UINT32 RegBitMask\r
6f72e28d 271 )\r
272{\r
273 UINTN Index, Start, End;\r
274 CHAR8 *Str;\r
275 BOOLEAN First;\r
276 \r
277 Str = mThumbMregListStr;\r
278 *Str = '\0';\r
279 AsciiStrCat (Str, "{");\r
280 // R0 - R7, PC\r
7c34497d 281 for (Index = 0, First = TRUE; Index <= 15; Index++) {\r
282 if ((RegBitMask & (1 << Index)) != 0) {\r
6f72e28d 283 Start = End = Index;\r
7c34497d 284 for (Index++; ((RegBitMask & (1 << Index)) != 0) && (Index <= 9); Index++) {\r
6f72e28d 285 End = Index;\r
286 }\r
287 \r
288 if (!First) {\r
289 AsciiStrCat (Str, ",");\r
290 } else {\r
291 First = FALSE;\r
292 }\r
293 \r
294 if (Start == End) {\r
7c34497d 295 AsciiStrCat (Str, gReg[Start]);\r
6f72e28d 296 } else {\r
297 AsciiStrCat (Str, gReg[Start]);\r
298 AsciiStrCat (Str, "-");\r
7c34497d 299 AsciiStrCat (Str, gReg[End]);\r
6f72e28d 300 }\r
301 }\r
302 }\r
303 if (First) {\r
304 AsciiStrCat (Str, "ERROR");\r
305 }\r
306 AsciiStrCat (Str, "}");\r
307 \r
308 // BugBug: Make caller pass in buffer it is cleaner\r
309 return mThumbMregListStr;\r
310}\r
311\r
312UINT32\r
7c34497d 313SignExtend32 (\r
314 IN UINT32 Data,\r
315 IN UINT32 TopBit\r
6f72e28d 316 )\r
317{\r
7c34497d 318 if (((Data & TopBit) == 0) || (TopBit == BIT31)) {\r
319 return Data;\r
320 }\r
321 \r
322 do {\r
323 TopBit <<= 1;\r
324 Data |= TopBit; \r
325 } while ((TopBit & BIT31) != BIT31);\r
326\r
327 return Data;\r
6f72e28d 328}\r
329\r
330/**\r
097bd461 331 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to \r
332 point to next instructin. \r
333 \r
334 We cheat and only decode instructions that access \r
6f72e28d 335 memory. If the instruction is not found we dump the instruction in hex.\r
336 \r
097bd461 337 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. \r
338 @param Buf Buffer to sprintf disassembly into.\r
339 @param Size Size of Buf in bytes. \r
f9f937d2 340 @param Extended TRUE dump hex for instruction too.\r
6f72e28d 341 \r
342**/\r
343VOID\r
344DisassembleThumbInstruction (\r
097bd461 345 IN UINT16 **OpCodePtrPtr,\r
6f72e28d 346 OUT CHAR8 *Buf,\r
f9f937d2 347 OUT UINTN Size,\r
348 IN BOOLEAN Extended\r
6f72e28d 349 )\r
350{\r
097bd461 351 UINT16 *OpCodePtr;\r
352 UINT16 OpCode;\r
7c34497d 353 UINT32 OpCode32;\r
6f72e28d 354 UINT32 Index;\r
355 UINT32 Offset;\r
b32fecd2 356 UINT16 Rd, Rn, Rm, Rt, Rt2;\r
6f72e28d 357 BOOLEAN H1, H2, imod;\r
7c34497d 358 UINT32 PC, Target;\r
359 CHAR8 *Cond;\r
b32fecd2 360 BOOLEAN S, J1, J2, P, U, W;\r
6f72e28d 361\r
097bd461 362 OpCodePtr = *OpCodePtrPtr;\r
363 OpCode = **OpCodePtrPtr;\r
364 \r
365 // Thumb2 is a stream of 16-bit instructions not a 32-bit instruction.\r
7c34497d 366 OpCode32 = (((UINT32)OpCode) << 16) | *(OpCodePtr + 1);\r
097bd461 367\r
6f72e28d 368 // These register names match branch form, but not others\r
369 Rd = OpCode & 0x7;\r
370 Rn = (OpCode >> 3) & 0x7;\r
371 Rm = (OpCode >> 6) & 0x7;\r
372 H1 = (OpCode & BIT7) != 0;\r
373 H2 = (OpCode & BIT6) != 0;\r
374 imod = (OpCode & BIT4) != 0;\r
7c34497d 375 PC = (UINT32)(UINTN)OpCodePtr;\r
6f72e28d 376\r
097bd461 377 // Increment by the minimum instruction size, Thumb2 could be bigger\r
378 *OpCodePtrPtr += 1;\r
379 \r
380 for (Index = 0; Index < sizeof (gOpThumb)/sizeof (THUMB_INSTRUCTIONS); Index++) {\r
381 if ((OpCode & gOpThumb[Index].Mask) == gOpThumb[Index].OpCode) {\r
f9f937d2 382 if (Extended) {\r
7c34497d 383 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode, gOpThumb[Index].Start); \r
f9f937d2 384 } else {\r
7c34497d 385 Offset = AsciiSPrint (Buf, Size, "%-6a", gOpThumb[Index].Start); \r
f9f937d2 386 }\r
097bd461 387 switch (gOpThumb[Index].AddressMode) {\r
6f72e28d 388 case LOAD_STORE_FORMAT1:\r
389 // A6.5.1 <Rd>, [<Rn>, #<5_bit_offset>]\r
7c34497d 390 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d #0x%x]", Rd, Rn, (OpCode >> 4) & 0x7c); \r
391 return;\r
6f72e28d 392 case LOAD_STORE_FORMAT2:\r
393 // A6.5.1 <Rd>, [<Rn>, <Rm>]\r
7c34497d 394 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [r%d, r%d]", Rd, Rn, Rm); \r
395 return;\r
6f72e28d 396 case LOAD_STORE_FORMAT3:\r
397 // A6.5.1 <Rd>, [PC, #<8_bit_offset>]\r
7c34497d 398 Target = (OpCode & 0xff) << 2;\r
b32fecd2 399 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [pc, #0x%x] ;0x%08x", (OpCode >> 8) & 7, Target, PC + 2 + Target); \r
7c34497d 400 return;\r
6f72e28d 401 case LOAD_STORE_FORMAT4:\r
7c34497d 402 // Rt, [SP, #imm8]\r
403 Target = (OpCode & 0xff) << 2;\r
b32fecd2 404 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, [sp, #0x%x]", (OpCode >> 8) & 7, Target, PC + 2 + Target); \r
7c34497d 405 return;\r
6f72e28d 406 \r
407 case LOAD_STORE_MULTIPLE_FORMAT1:\r
7c34497d 408 // <Rn>!, {r0-r7}\r
409 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d!, %a", (OpCode >> 8) & 7, ThumbMRegList (OpCode & 0xff)); \r
410 return;\r
411 \r
412 case POP_FORMAT:\r
413 // POP {r0-r7,pc}\r
414 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT15 : 0))); \r
415 return;\r
416\r
417 case PUSH_FORMAT:\r
418 // PUSH {r0-r7,lr}\r
419 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList ((OpCode & 0xff) | ((OpCode & BIT8) == BIT8 ? BIT14 : 0))); \r
420 return;\r
421\r
6f72e28d 422 \r
423 case IMMED_8:\r
424 // A6.7 <immed_8>\r
425 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%x", OpCode & 0xff); \r
7c34497d 426 return;\r
6f72e28d 427\r
428 case CONDITIONAL_BRANCH:\r
429 // A6.3.1 B<cond> <target_address>\r
7c34497d 430 // Patch in the condition code. A little hack but based on "%-6a"\r
431 Cond = gCondition[(OpCode >> 8) & 0xf];\r
432 Buf[Offset-5] = *Cond++;\r
433 Buf[Offset-4] = *Cond;\r
434 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0xff) << 1, BIT8)); \r
435 return;\r
6f72e28d 436 case UNCONDITIONAL_BRANCH_SHORT:\r
437 // A6.3.2 B <target_address>\r
7c34497d 438 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%04x", PC + 4 + SignExtend32 ((OpCode & 0x3ff) << 1, BIT11)); \r
439 return;\r
440 \r
6f72e28d 441 case BRANCH_EXCHANGE:\r
442 // A6.3.3 BX|BLX <Rm>\r
7c34497d 443 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[Rn | (H2 ? 8:0)]); \r
444 return;\r
6f72e28d 445\r
446 case DATA_FORMAT1:\r
447 // A6.4.3 <Rd>, <Rn>, <Rm>\r
448 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, r%d", Rd, Rn, Rm); \r
7c34497d 449 return;\r
6f72e28d 450 case DATA_FORMAT2:\r
451 // A6.4.3 <Rd>, <Rn>, #3_bit_immed\r
452 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rd, Rn, Rm); \r
7c34497d 453 return;\r
6f72e28d 454 case DATA_FORMAT3:\r
7c34497d 455 // A6.4.3 <Rd>|<Rn>, #imm8\r
456 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, #0x%x", (OpCode >> 8) & 7, OpCode & 0xff); \r
457 return;\r
6f72e28d 458 case DATA_FORMAT4:\r
459 // A6.4.3 <Rd>|<Rm>, #immed_5\r
460 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d, 0x%x", Rn, Rd, (OpCode >> 6) & 0x1f); \r
7c34497d 461 return;\r
6f72e28d 462 case DATA_FORMAT5:\r
463 // A6.4.3 <Rd>|<Rm>, <Rm>|<Rs>\r
464 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, r%d", Rd, Rn); \r
7c34497d 465 return;\r
6f72e28d 466 case DATA_FORMAT6_SP:\r
467 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>\r
7c34497d 468 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, sp, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); \r
469 return;\r
6f72e28d 470 case DATA_FORMAT6_PC:\r
471 // A6.4.3 <Rd>, <reg>, #<8_Bit_immed>\r
7c34497d 472 AsciiSPrint (&Buf[Offset], Size - Offset, " r%d, pc, 0x%x", (OpCode >> 8) & 7, (OpCode & 0xff) << 2); \r
473 return;\r
6f72e28d 474 case DATA_FORMAT7:\r
475 // A6.4.3 SP, SP, #<7_Bit_immed>\r
7c34497d 476 AsciiSPrint (&Buf[Offset], Size - Offset, " sp, sp, 0x%x", (OpCode & 0x7f)*4); \r
477 return;\r
6f72e28d 478 case DATA_FORMAT8:\r
479 // A6.4.3 <Rd>|<Rn>, <Rm>\r
480 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[Rd | (H1 ? 8:0)], gReg[Rn | (H2 ? 8:0)]); \r
7c34497d 481 return;\r
6f72e28d 482 \r
483 case CPS_FORMAT:\r
484 // A7.1.24\r
485 AsciiSPrint (&Buf[Offset], Size - Offset, "%a %a%a%a", imod ? "ID":"IE", ((OpCode & BIT2) == 0) ? "":"a", ((OpCode & BIT1) == 0) ? "":"i", ((OpCode & BIT0) == 0) ? "":"f"); \r
7c34497d 486 return;\r
6f72e28d 487\r
488 case ENDIAN_FORMAT:\r
489 // A7.1.24\r
490 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", (OpCode & BIT3) == 0 ? "LE":"BE"); \r
7c34497d 491 return;\r
b32fecd2 492\r
493 case DATA_CBZ:\r
494 // CB{N}Z <Rn>, <Lable>\r
495 Target = ((OpCode >> 2) & 0x3e) | (((OpCode & BIT9) == BIT9) ? BIT6 : 0);\r
496 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[Rd], PC + 4 + Target); \r
497 return;\r
498\r
499 case ADR_FORMAT:\r
500 // ADR <Rd>, <Label>\r
501 Target = (OpCode & 0xff) << 2;\r
502 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %08x", gReg[(OpCode >> 8) & 7], PC + 4 + Target); \r
503 return;\r
6f72e28d 504 }\r
505 }\r
506 }\r
7c34497d 507\r
508 \r
097bd461 509 // Thumb2 are 32-bit instructions\r
510 *OpCodePtrPtr += 1;\r
b32fecd2 511 Rt = (OpCode32 >> 12) & 0xf;\r
512 Rt2 = (OpCode32 >> 8) & 0xf;\r
513 Rm = (OpCode32 & 0xf);\r
514 Rn = (OpCode32 >> 16) & 0xf;\r
097bd461 515 for (Index = 0; Index < sizeof (gOpThumb2)/sizeof (THUMB_INSTRUCTIONS); Index++) {\r
516 if ((OpCode32 & gOpThumb2[Index].Mask) == gOpThumb2[Index].OpCode) {\r
f9f937d2 517 if (Extended) {\r
c7ed09e3 518 Offset = AsciiSPrint (Buf, Size, "0x%04x %-6a", OpCode32, gOpThumb2[Index].Start); \r
f9f937d2 519 } else {\r
c7ed09e3 520 Offset = AsciiSPrint (Buf, Size, " %-6a", gOpThumb2[Index].Start); \r
f9f937d2 521 }\r
522 switch (gOpThumb2[Index].AddressMode) {\r
7c34497d 523 case B_T3:\r
524 Cond = gCondition[(OpCode32 >> 22) & 0xf];\r
525 Buf[Offset-5] = *Cond++;\r
526 Buf[Offset-4] = *Cond;\r
527 // S:J2:J1:imm6:imm11:0\r
528 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3f000);\r
c7ed09e3 529 Target |= ((OpCode32 & BIT11) == BIT11)? BIT19 : 0; // J2\r
530 Target |= ((OpCode32 & BIT13) == BIT13)? BIT18 : 0; // J1\r
531 Target |= ((OpCode32 & BIT26) == BIT26)? BIT20 : 0; // S\r
532 Target = SignExtend32 (Target, BIT20);\r
533 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); \r
7c34497d 534 return;\r
535 case B_T4:\r
536 // S:I1:I2:imm10:imm11:0\r
537 Target = ((OpCode32 << 1) & 0xffe) + ((OpCode32 >> 4) & 0x3ff000);\r
c7ed09e3 538 S = (OpCode32 & BIT26) == BIT26;\r
539 J1 = (OpCode32 & BIT13) == BIT13;\r
540 J2 = (OpCode32 & BIT11) == BIT11;\r
541 Target |= (!(J2 ^ S) ? BIT22 : 0); // I2\r
542 Target |= (!(J1 ^ S) ? BIT23 : 0); // I1\r
543 Target |= (S ? BIT24 : 0); // S\r
544 Target = SignExtend32 (Target, BIT24);\r
545 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); \r
7c34497d 546 return;\r
547\r
548 case BL_T2:\r
c7ed09e3 549 // S:I1:I2:imm10:imm11:00\r
7c34497d 550 Target = ((OpCode32 << 2) & 0x1ffc) + ((OpCode32 >> 3) & 0x7fe000);\r
c7ed09e3 551 S = (OpCode32 & BIT26) == BIT26;\r
552 J1 = (OpCode32 & BIT13) == BIT13;\r
553 J2 = (OpCode32 & BIT11) == BIT11;\r
554 Target |= (!(J2 ^ S) ? BIT23 : 0); // I2\r
555 Target |= (!(J1 ^ S) ? BIT24 : 0); // I1\r
556 Target |= (S ? BIT25 : 0); // S\r
557 Target = SignExtend32 (Target, BIT25);\r
558 AsciiSPrint (&Buf[Offset], Size - Offset, " 0x%08x", PC + 4 + Target); \r
7c34497d 559 return;\r
b32fecd2 560\r
561 case POP_T2:\r
562 // <reglist> some must be zero, handled in table\r
563 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", ThumbMRegList (OpCode32 & 0xffff));\r
564 return;\r
565\r
566 case POP_T3:\r
567 // <register> \r
568 AsciiSPrint (&Buf[Offset], Size - Offset, " %a", gReg[(OpCode32 >> 12) & 0xf]);\r
569 return;\r
570\r
571 case STM_FORMAT:\r
572 // <Rn>{!}, <registers>\r
573 W = (OpCode32 & BIT21) == BIT21;\r
574 AsciiSPrint (&Buf[Offset], Size - Offset, " %a %a", gReg[(OpCode32 >> 16) & 0xf], W ? "!":"", ThumbMRegList (OpCode32 & 0xffff));\r
575 return;\r
576\r
577 case LDM_REG_IMM12_SIGNED:\r
578 // <rt>, <label>\r
579 Target = OpCode32 & 0xfff; \r
580 if ((OpCode32 & BIT23) == 0) {\r
581 // U == 0 means subtrack, U == 1 means add\r
582 Target = -Target;\r
583 }\r
584 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a", gReg[(OpCode32 >> 12) & 0xf], PC + 4 + Target);\r
585 return;\r
586\r
587 case LDM_REG_INDIRECT_LSL:\r
588 // <rt>, [<rn>, <rm> {, LSL #<imm2>]}\r
589 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a, %a", gReg[Rt], gReg[Rn], gReg[Rm]);\r
590 if (((OpCode32 >> 4) && 3) == 0) {\r
591 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
592 } else {\r
593 AsciiSPrint (&Buf[Offset], Size - Offset, ", LSL #%d]", (OpCode32 >> 4) && 3);\r
594 }\r
595 return;\r
596 \r
597 case LDM_REG_IMM12:\r
598 // <rt>, [<rn>, {, #<imm12>]}\r
599 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);\r
600 if ((OpCode32 && 0xfff) == 0) {\r
601 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
602 } else {\r
603 AsciiSPrint (&Buf[Offset], Size - Offset, ", #0x%x]", OpCode32 & 0xfff);\r
604 }\r
605 return;\r
606\r
607 case LDM_REG_IMM8:\r
608 // <rt>, [<rn>, {, #<imm8>}]{!}\r
609 W = (OpCode32 & BIT8) == BIT8;\r
610 U = (OpCode32 & BIT9) == BIT9;\r
611 P = (OpCode32 & BIT10) == BIT10;\r
612 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a", gReg[Rt], gReg[Rn]);\r
613 if (P) {\r
614 if ((OpCode32 && 0xff) == 0) {\r
615 AsciiSPrint (&Buf[Offset], Size - Offset, "]%a", W?"!":"");\r
616 } else {\r
617 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", OpCode32 & 0xff, U?"":"-" ,W?"!":"");\r
618 }\r
619 } else {\r
620 AsciiSPrint (&Buf[Offset], Size - Offset, "], #%a0x%x]%a", OpCode32 & 0xff, U?"":"-");\r
621 }\r
622 return;\r
623\r
624 case LDRD_REG_IMM8_SIGNED:\r
625 // LDRD <rt>, <rt2>, [<rn>, {, #<imm8>]}{!}\r
626 P = (OpCode32 & BIT24) == BIT24; // index = P\r
627 U = (OpCode32 & BIT23) == BIT23; \r
628 W = (OpCode32 & BIT21) == BIT21;\r
629 Offset += AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, [%a", gReg[Rt], gReg[Rt2], gReg[Rn]);\r
630 if (P) {\r
631 if ((OpCode32 && 0xff) == 0) {\r
632 AsciiSPrint (&Buf[Offset], Size - Offset, "]");\r
633 } else {\r
634 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x]%a", U?"":"-", (OpCode32 & 0xff) << 2, W?"!":"");\r
635 }\r
636 } else {\r
637 if ((OpCode32 && 0xff) != 0) {\r
638 AsciiSPrint (&Buf[Offset], Size - Offset, ", #%a0x%x", U?"":"-", (OpCode32 & 0xff) << 2);\r
639 }\r
640 }\r
641 return;\r
642\r
643 case LDRD_REG_IMM8: \r
644 // LDRD <rt>, <rt2>, <label> \r
645 Target = (OpCode32 & 0xff) << 2; \r
646 if ((OpCode32 & BIT23) == 0) {\r
647 // U == 0 means subtrack, U == 1 means add\r
648 Target = -Target;\r
649 }\r
650 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, %a, %a", gReg[Rt], gReg[Rt2], PC + 4 + Target);\r
651 return;\r
652\r
653 case LDREXB:\r
654 // LDREXB <Rt>, [Rn]\r
655 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, [%a]", gReg[Rt], gReg[Rn]);\r
656 return;\r
657\r
658 case LDREXD:\r
659 // LDREXD <Rt>, <Rt2>, [<Rn>]\r
660 AsciiSPrint (&Buf[Offset], Size - Offset, " %a, ,%a, [%a]", gReg[Rt], gReg[Rt2], gReg[Rn]);\r
661 return;\r
662 \r
663 case SRS_FORMAT:\r
664 // SP{!}, #<mode>\r
665 W = (OpCode32 & BIT21) == BIT21;\r
666 AsciiSPrint (&Buf[Offset], Size - Offset, " SP%a, #0x%x", W?"!":"", OpCode32 & 0x1f);\r
667 return;\r
668\r
669 case RFE_FORMAT:\r
670 // <Rn>{!}\r
671 AsciiSPrint (&Buf[Offset], Size - Offset, " %a%a, #0x%x", gReg[Rn], W?"!":"");\r
672 return;\r
673\r
f9f937d2 674 }\r
097bd461 675 }\r
676 }\r
7c34497d 677\r
678 AsciiSPrint (Buf, Size, "0x%08x", OpCode32);\r
6f72e28d 679}\r
680\r
097bd461 681\r
682\r
683VOID\r
684DisassembleArmInstruction (\r
685 IN UINT32 **OpCodePtr,\r
686 OUT CHAR8 *Buf,\r
f9f937d2 687 OUT UINTN Size,\r
688 IN BOOLEAN Extended\r
097bd461 689 );\r
690\r
691\r
692/**\r
693 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to \r
694 point to next instructin. \r
695 \r
696 We cheat and only decode instructions that access \r
697 memory. If the instruction is not found we dump the instruction in hex.\r
698 \r
699 @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. \r
700 @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream\r
f9f937d2 701 @param Extended TRUE dump hex for instruction too.\r
097bd461 702 @param Buf Buffer to sprintf disassembly into.\r
703 @param Size Size of Buf in bytes. \r
704 \r
705**/\r
706VOID\r
707DisassembleInstruction (\r
708 IN UINT8 **OpCodePtr,\r
709 IN BOOLEAN Thumb,\r
f9f937d2 710 IN BOOLEAN Extended,\r
097bd461 711 OUT CHAR8 *Buf,\r
712 OUT UINTN Size\r
713 )\r
714{\r
715 if (Thumb) {\r
f9f937d2 716 DisassembleThumbInstruction ((UINT16 **)OpCodePtr, Buf, Size, Extended);\r
097bd461 717 } else {\r
f9f937d2 718 DisassembleArmInstruction ((UINT32 **)OpCodePtr, Buf, Size, Extended);\r
097bd461 719 }\r
720}\r
6f72e28d 721 \r