5b43f5542e83d2b819ba9064a2b31d75aba90645
[mirror_edk2.git] / ArmPkg / Library / ArmDisassemblerLib / ArmDisassembler.c
1 /** @file
2 Default exception handler
3
4 Copyright (c) 2008-2010, Apple Inc. All rights reserved.
5
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include <Base.h>
17 #include <Library/BaseLib.h>
18 #include <Library/PrintLib.h>
19 #include <Library/ArmDisassemblerLib.h>
20
21 CHAR8 *gCondition[] = {
22 "EQ",
23 "NE",
24 "CS",
25 "CC",
26 "MI",
27 "PL",
28 "VS",
29 "VC",
30 "HI",
31 "LS",
32 "GE",
33 "LT",
34 "GT",
35 "LE",
36 "",
37 "2"
38 };
39
40 #define COND(_a) gCondition[(_a) >> 28]
41
42 CHAR8 *gReg[] = {
43 "r0",
44 "r1",
45 "r2",
46 "r3",
47 "r4",
48 "r5",
49 "r6",
50 "r7",
51 "r8",
52 "r9",
53 "r10",
54 "r11",
55 "r12",
56 "sp",
57 "lr",
58 "pc"
59 };
60
61 CHAR8 *gLdmAdr[] = {
62 "DA",
63 "IA",
64 "DB",
65 "IB"
66 };
67
68 CHAR8 *gLdmStack[] = {
69 "FA",
70 "FD",
71 "EA",
72 "ED"
73 };
74
75 #define LDM_EXT(_reg, _off) ((_reg == 13) ? gLdmStack[(_off)] : gLdmAdr[(_off)])
76
77
78 #define SIGN(_U) ((_U) ? "" : "-")
79 #define WRITE(_W) ((_W) ? "!" : "")
80 #define BYTE(_B) ((_B) ? "B":"")
81 #define USER(_B) ((_B) ? "^" : "")
82
83 CHAR8 mMregListStr[4*15 + 1];
84
85 CHAR8 *
86 MRegList (
87 UINT32 OpCode
88 )
89 {
90 UINTN Index, Start, End;
91 CHAR8 *Str;
92 BOOLEAN First;
93
94 Str = mMregListStr;
95 *Str = '\0';
96 AsciiStrCat (Str, "{");
97 for (Index = 0, First = TRUE; Index <= 15; Index++) {
98 if ((OpCode & (1 << Index)) != 0) {
99 Start = End = Index;
100 for (Index++; ((OpCode & (1 << Index)) != 0) && Index <= 15; Index++) {
101 End = Index;
102 }
103
104 if (!First) {
105 AsciiStrCat (Str, ",");
106 } else {
107 First = FALSE;
108 }
109
110 if (Start == End) {
111 AsciiStrCat (Str, gReg[Start]);
112 AsciiStrCat (Str, ", ");
113 } else {
114 AsciiStrCat (Str, gReg[Start]);
115 AsciiStrCat (Str, "-");
116 AsciiStrCat (Str, gReg[End]);
117 }
118 }
119 }
120 if (First) {
121 AsciiStrCat (Str, "ERROR");
122 }
123 AsciiStrCat (Str, "}");
124
125 // BugBug: Make caller pass in buffer it is cleaner
126 return mMregListStr;
127 }
128
129 CHAR8 *
130 FieldMask (
131 IN UINT32 Mask
132 )
133 {
134 return "";
135 }
136
137 UINT32
138 RotateRight (
139 IN UINT32 Op,
140 IN UINT32 Shift
141 )
142 {
143 return (Op >> Shift) | (Op << (32 - Shift));
144 }
145
146
147 /**
148 Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to
149 point to next instructin.
150
151 We cheat and only decode instructions that access
152 memory. If the instruction is not found we dump the instruction in hex.
153
154 @param OpCodePtr Pointer to pointer of ARM instruction to disassemble.
155 @param Buf Buffer to sprintf disassembly into.
156 @param Size Size of Buf in bytes.
157
158 **/
159 VOID
160 DisassembleArmInstruction (
161 IN UINT32 **OpCodePtr,
162 OUT CHAR8 *Buf,
163 OUT UINTN Size
164 )
165 {
166 UINT32 OpCode = **OpCodePtr;
167 CHAR8 *Type, *Root;
168 BOOLEAN I, P, U, B, W, L, S, H;
169 UINT32 Rn, Rd, Rm;
170 UINT32 imode, offset_8, offset_12;
171 UINT32 Index;
172 UINT32 shift_imm, shift;
173
174 I = (OpCode & BIT25) == BIT25;
175 P = (OpCode & BIT24) == BIT24;
176 U = (OpCode & BIT23) == BIT23;
177 B = (OpCode & BIT22) == BIT22; // Also called S
178 W = (OpCode & BIT21) == BIT21;
179 L = (OpCode & BIT20) == BIT20;
180 S = (OpCode & BIT6) == BIT6;
181 H = (OpCode & BIT5) == BIT5;
182 Rn = (OpCode >> 16) & 0xf;
183 Rd = (OpCode >> 12) & 0xf;
184 Rm = (OpCode & 0xf);
185
186 // LDREX, STREX
187 if ((OpCode & 0x0fe000f0) == 0x01800090) {
188 if (L) {
189 // A4.1.27 LDREX{<cond>} <Rd>, [<Rn>]
190 AsciiSPrint (Buf, Size, "LDREX%a %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn]);
191 } else {
192 // A4.1.103 STREX{<cond>} <Rd>, <Rm>, [<Rn>]
193 AsciiSPrint (Buf, Size, "STREX%a %a, %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn], gReg[Rn]);
194 }
195 return;
196 }
197
198 // LDM/STM
199 if ((OpCode & 0x0e000000) == 0x08000000) {
200 if (L) {
201 // A4.1.20 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers>
202 // A4.1.21 LDM{<cond>}<addressing_mode> <Rn>, <registers_without_pc>^
203 // A4.1.22 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers_and_pc>^
204 AsciiSPrint (Buf, Size, "LDM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn ,(OpCode >> 23) & 3), gReg[Rn], WRITE (W), MRegList (OpCode), USER (B));
205 } else {
206 // A4.1.97 STM{<cond>}<addressing_mode> <Rn>{!}, <registers>
207 // A4.1.98 STM{<cond>}<addressing_mode> <Rn>, <registers>^
208 AsciiSPrint (Buf, Size, "STM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn ,(OpCode >> 23) & 3), gReg[Rn], WRITE (W), MRegList (OpCode), USER (B));
209 }
210 return;
211 }
212
213 // LDR/STR Address Mode 2
214 if ( ((OpCode & 0x0c000000) == 0x04000000) || ((OpCode & 0xfd70f000 ) == 0xf550f000) ) {
215 offset_12 = OpCode & 0xfff;
216 if ((OpCode & 0xfd70f000 ) == 0xf550f000) {
217 Index = AsciiSPrint (Buf, Size, "PLD");
218 } else {
219 Index = AsciiSPrint (Buf, Size, "%a%a%a%a %a, ", L ? "LDR" : "STR", COND (OpCode), BYTE (B), (!P & W) ? "T":"", gReg[Rd]);
220 }
221 if (P) {
222 if (!I) {
223 // A5.2.2 [<Rn>, #+/-<offset_12>]
224 // A5.2.5 [<Rn>, #+/-<offset_12>]
225 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x]%a", gReg[Rn], SIGN (U), offset_12, WRITE (W));
226 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
227 // A5.2.3 [<Rn>, +/-<Rm>]
228 // A5.2.6 [<Rn>, +/-<Rm>]!
229 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a]%a", gReg[Rn], SIGN (U), WRITE (W));
230 } else {
231 // A5.2.4 [<Rn>, +/-<Rm>, LSL #<shift_imm>]
232 // A5.2.7 [<Rn>, +/-<Rm>, LSL #<shift_imm>]!
233 shift_imm = (OpCode >> 7) & 0x1f;
234 shift = (OpCode >> 5) & 0x3;
235 if (shift == 0x0) {
236 Type = "LSL";
237 } else if (shift == 0x1) {
238 Type = "LSR";
239 if (shift_imm == 0) {
240 shift_imm = 32;
241 }
242 } else if (shift == 0x12) {
243 Type = "ASR";
244 } else if (shift_imm == 0) {
245 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, RRX]%a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
246 return;
247 } else {
248 Type = "ROR";
249 }
250
251 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, #%d]%a", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm, WRITE (W));
252 }
253 } else { // !P
254 if (!I) {
255 // A5.2.8 [<Rn>], #+/-<offset_12>
256 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x", gReg[Rn], SIGN (U), offset_12);
257 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
258 // A5.2.9 [<Rn>], +/-<Rm>
259 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
260 } else {
261 // A5.2.10 [<Rn>], +/-<Rm>, LSL #<shift_imm>
262 shift_imm = (OpCode >> 7) & 0x1f;
263 shift = (OpCode >> 5) & 0x3;
264
265 if (shift == 0x0) {
266 Type = "LSL";
267 } else if (shift == 0x1) {
268 Type = "LSR";
269 if (shift_imm == 0) {
270 shift_imm = 32;
271 }
272 } else if (shift == 0x12) {
273 Type = "ASR";
274 } else if (shift_imm == 0) {
275 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, RRX", gReg[Rn], SIGN (U), gReg[Rm]);
276 // FIx me
277 return;
278 } else {
279 Type = "ROR";
280 }
281
282 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, #%d", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm);
283 }
284 }
285 return;
286 }
287
288 if ((OpCode & 0x0e000000) == 0x00000000) {
289 // LDR/STR address mode 3
290 // LDR|STR{<cond>}H|SH|SB|D <Rd>, <addressing_mode>
291 if (L) {
292 if (!S) {
293 Root = "LDR%aH %a, ";
294 } else if (!H) {
295 Root = "LDR%aSB %a, ";
296 } else {
297 Root = "LDR%aSH %a, ";
298 }
299 } else {
300 if (!S) {
301 Root = "STR%aH %a ";
302 } else if (!H) {
303 Root = "LDR%aD %a ";
304 } else {
305 Root = "STR%aD %a ";
306 }
307 }
308
309 Index = AsciiSPrint (Buf, Size, Root, COND (OpCode), gReg[Rd]);
310
311 S = (OpCode & BIT6) == BIT6;
312 H = (OpCode & BIT5) == BIT5;
313 offset_8 = ((OpCode >> 4) | (OpCode * 0xf)) & 0xff;
314 if (P & !W) {
315 // Immediate offset/index
316 if (B) {
317 // A5.3.2 [<Rn>, #+/-<offset_8>]
318 // A5.3.4 [<Rn>, #+/-<offset_8>]!
319 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%d]%a", gReg[Rn], SIGN (U), offset_8, WRITE (W));
320 } else {
321 // A5.3.3 [<Rn>, +/-<Rm>]
322 // A5.3.5 [<Rn>, +/-<Rm>]!
323 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%]a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
324 }
325 } else {
326 // Register offset/index
327 if (B) {
328 // A5.3.6 [<Rn>], #+/-<offset_8>
329 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%d", gReg[Rn], SIGN (U), offset_8);
330 } else {
331 // A5.3.7 [<Rn>], +/-<Rm>
332 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
333 }
334 }
335 return;
336 }
337
338 if ((OpCode & 0x0fb000f0) == 0x01000050) {
339 // A4.1.108 SWP SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
340 // A4.1.109 SWPB SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
341 AsciiSPrint (Buf, Size, "SWP%a%a %a, %a, [%a]", COND (OpCode), BYTE (B), gReg[Rd], gReg[Rm], gReg[Rn]);
342 return;
343 }
344
345 if ((OpCode & 0xfe5f0f00) == 0xf84d0500) {
346 // A4.1.90 SRS SRS<addressing_mode> #<mode>{!}
347 AsciiSPrint (Buf, Size, "SRS%a #0x%x%a", gLdmStack[(OpCode >> 23) & 3], OpCode & 0x1f, WRITE (W));
348 return;
349 }
350
351 if ((OpCode & 0xfe500f00) == 0xf8100500) {
352 // A4.1.59 RFE<addressing_mode> <Rn>{!}
353 AsciiSPrint (Buf, Size, "RFE%a %a", gLdmStack[(OpCode >> 23) & 3], gReg[Rn], WRITE (W));
354 return;
355 }
356
357 if ((OpCode & 0xfff000f0) == 0xe1200070) {
358 // A4.1.7 BKPT <immed_16>
359 AsciiSPrint (Buf, Size, "BKPT %x", ((OpCode >> 8) | (OpCode & 0xf)) & 0xffff);
360 return;
361 }
362
363 if ((OpCode & 0xfff10020) == 0xf1000000) {
364 // A4.1.16 CPS<effect> <iflags> {, #<mode>}
365 if (((OpCode >> 6) & 0x7) == 0) {
366 AsciiSPrint (Buf, Size, "CPS #0x%x", (OpCode & 0x2f));
367 } else {
368 imode = (OpCode >> 18) & 0x3;
369 Index = AsciiSPrint (Buf, Size, "CPS%a %a%a%a", (imode == 3) ? "ID":"IE", (OpCode & BIT8) ? "A":"", (OpCode & BIT7) ? "I":"", (OpCode & BIT6) ? "F":"");
370 if ((OpCode & BIT17) != 0) {
371 AsciiSPrint (&Buf[Index], Size - Index, ", #0x%x", OpCode & 0x1f);
372 }
373 }
374 return;
375 }
376
377 if ((OpCode & 0x0f000000) == 0x0f000000) {
378 // A4.1.107 SWI{<cond>} <immed_24>
379 AsciiSPrint (Buf, Size, "SWI%a %x", COND (OpCode), OpCode & 0x00ffffff);
380 return;
381 }
382
383 if ((OpCode & 0x0fb00000) == 0x01000000) {
384 // A4.1.38 MRS{<cond>} <Rd>, CPSR MRS{<cond>} <Rd>, SPSR
385 AsciiSPrint (Buf, Size, "MRS%a %a, %a", COND (OpCode), gReg[Rd], B ? "SPSR" : "CPSR");
386 return;
387 }
388
389
390 if ((OpCode & 0x0db00000) == 0x03200000) {
391 // A4.1.38 MSR{<cond>} CPSR_<fields>, #<immediate> MSR{<cond>} CPSR_<fields>, <Rm>
392 if (I) {
393 // MSR{<cond>} CPSR_<fields>, #<immediate>
394 AsciiSPrint (Buf, Size, "MRS%a %a_%a, #0x%x", COND (OpCode), B ? "SPSR" : "CPSR", FieldMask ((OpCode >> 16) & 0xf), RotateRight (OpCode & 0xf, ((OpCode >> 8) & 0xf) *2));
395 } else {
396 // MSR{<cond>} CPSR_<fields>, <Rm>
397 AsciiSPrint (Buf, Size, "MRS%a %a_%a, %a", COND (OpCode), B ? "SPSR" : "CPSR", gReg[Rd]);
398 }
399 return;
400 }
401
402 if ((OpCode & 0xff000010) == 0xfe000000) {
403 // A4.1.13 CDP{<cond>} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
404 AsciiSPrint (Buf, Size, "CDP%a 0x%x, 0x%x, CR%d, CR%d, CR%d, 0x%x", COND (OpCode), (OpCode >> 8) & 0xf, (OpCode >> 20) & 0xf, Rn, Rd, Rm, (OpCode >> 5) &0x7);
405 return;
406 }
407
408 if ((OpCode & 0x0e000000) == 0x0c000000) {
409 // A4.1.19 LDC and A4.1.96 SDC
410 if ((OpCode & 0xf0000000) == 0xf0000000) {
411 Index = AsciiSPrint (Buf, Size, "%a2 0x%x, CR%d, ", L ? "LDC":"SDC", (OpCode >> 8) & 0xf, Rd);
412 } else {
413 Index = AsciiSPrint (Buf, Size, "%a%a 0x%x, CR%d, ", L ? "LDC":"SDC", COND (OpCode), (OpCode >> 8) & 0xf, Rd);
414 }
415
416 if (!P) {
417 if (!W) {
418 // A5.5.5.5 [<Rn>], <option>
419 AsciiSPrint (&Buf[Index], Size - Index, "[%a], {0x%x}", gReg[Rn], OpCode & 0xff);
420 } else {
421 // A.5.5.4 [<Rn>], #+/-<offset_8>*4
422 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x*4", gReg[Rn], SIGN (U), OpCode & 0xff);
423 }
424 } else {
425 // A5.5.5.2 [<Rn>, #+/-<offset_8>*4 ]!
426 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x*4]%a", gReg[Rn], SIGN (U), OpCode & 0xff, WRITE (W));
427 }
428
429 }
430
431 if ((OpCode & 0x0f000010) == 0x0e000010) {
432 // A4.1.32 MRC2, MCR2
433 AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, CR%d, CR%d, 0x%x", L ? "MRC":"MCR", COND (OpCode), (OpCode >> 8) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], Rn, Rm, (OpCode >> 5) &0x7);
434 return;
435 }
436
437 if ((OpCode & 0x0ff00000) == 0x0c400000) {
438 // A4.1.33 MRRC2, MCRR2
439 AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, %a, CR%d", L ? "MRRC":"MCRR", COND (OpCode), (OpCode >> 4) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], gReg[Rn], Rm);
440 return;
441 }
442
443 AsciiSPrint (Buf, Size, "Faulting OpCode 0x%08x", OpCode);
444
445 *OpCodePtr += 1;
446 return;
447 }
448