Move ARM disassembler into a library and out of the exception handler. Add a hook...
[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 @param Extended TRUE dump hex for instruction too.
158
159 **/
160 VOID
161 DisassembleArmInstruction (
162 IN UINT32 **OpCodePtr,
163 OUT CHAR8 *Buf,
164 OUT UINTN Size,
165 IN BOOLEAN Extended
166 )
167 {
168 UINT32 OpCode = **OpCodePtr;
169 CHAR8 *Type, *Root;
170 BOOLEAN I, P, U, B, W, L, S, H;
171 UINT32 Rn, Rd, Rm;
172 UINT32 imode, offset_8, offset_12;
173 UINT32 Index;
174 UINT32 shift_imm, shift;
175
176 I = (OpCode & BIT25) == BIT25;
177 P = (OpCode & BIT24) == BIT24;
178 U = (OpCode & BIT23) == BIT23;
179 B = (OpCode & BIT22) == BIT22; // Also called S
180 W = (OpCode & BIT21) == BIT21;
181 L = (OpCode & BIT20) == BIT20;
182 S = (OpCode & BIT6) == BIT6;
183 H = (OpCode & BIT5) == BIT5;
184 Rn = (OpCode >> 16) & 0xf;
185 Rd = (OpCode >> 12) & 0xf;
186 Rm = (OpCode & 0xf);
187
188
189 if (Extended) {
190 Index = AsciiSPrint (Buf, Size, "0x%08x ", OpCode);
191 Buf += Index;
192 Size -= Index;
193 }
194
195 // LDREX, STREX
196 if ((OpCode & 0x0fe000f0) == 0x01800090) {
197 if (L) {
198 // A4.1.27 LDREX{<cond>} <Rd>, [<Rn>]
199 AsciiSPrint (Buf, Size, "LDREX%a %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn]);
200 } else {
201 // A4.1.103 STREX{<cond>} <Rd>, <Rm>, [<Rn>]
202 AsciiSPrint (Buf, Size, "STREX%a %a, %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn], gReg[Rn]);
203 }
204 return;
205 }
206
207 // LDM/STM
208 if ((OpCode & 0x0e000000) == 0x08000000) {
209 if (L) {
210 // A4.1.20 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers>
211 // A4.1.21 LDM{<cond>}<addressing_mode> <Rn>, <registers_without_pc>^
212 // A4.1.22 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers_and_pc>^
213 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));
214 } else {
215 // A4.1.97 STM{<cond>}<addressing_mode> <Rn>{!}, <registers>
216 // A4.1.98 STM{<cond>}<addressing_mode> <Rn>, <registers>^
217 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));
218 }
219 return;
220 }
221
222 // LDR/STR Address Mode 2
223 if ( ((OpCode & 0x0c000000) == 0x04000000) || ((OpCode & 0xfd70f000 ) == 0xf550f000) ) {
224 offset_12 = OpCode & 0xfff;
225 if ((OpCode & 0xfd70f000 ) == 0xf550f000) {
226 Index = AsciiSPrint (Buf, Size, "PLD");
227 } else {
228 Index = AsciiSPrint (Buf, Size, "%a%a%a%a %a, ", L ? "LDR" : "STR", COND (OpCode), BYTE (B), (!P & W) ? "T":"", gReg[Rd]);
229 }
230 if (P) {
231 if (!I) {
232 // A5.2.2 [<Rn>, #+/-<offset_12>]
233 // A5.2.5 [<Rn>, #+/-<offset_12>]
234 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x]%a", gReg[Rn], SIGN (U), offset_12, WRITE (W));
235 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
236 // A5.2.3 [<Rn>, +/-<Rm>]
237 // A5.2.6 [<Rn>, +/-<Rm>]!
238 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a]%a", gReg[Rn], SIGN (U), WRITE (W));
239 } else {
240 // A5.2.4 [<Rn>, +/-<Rm>, LSL #<shift_imm>]
241 // A5.2.7 [<Rn>, +/-<Rm>, LSL #<shift_imm>]!
242 shift_imm = (OpCode >> 7) & 0x1f;
243 shift = (OpCode >> 5) & 0x3;
244 if (shift == 0x0) {
245 Type = "LSL";
246 } else if (shift == 0x1) {
247 Type = "LSR";
248 if (shift_imm == 0) {
249 shift_imm = 32;
250 }
251 } else if (shift == 0x12) {
252 Type = "ASR";
253 } else if (shift_imm == 0) {
254 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, RRX]%a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
255 return;
256 } else {
257 Type = "ROR";
258 }
259
260 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, #%d]%a", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm, WRITE (W));
261 }
262 } else { // !P
263 if (!I) {
264 // A5.2.8 [<Rn>], #+/-<offset_12>
265 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x", gReg[Rn], SIGN (U), offset_12);
266 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
267 // A5.2.9 [<Rn>], +/-<Rm>
268 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
269 } else {
270 // A5.2.10 [<Rn>], +/-<Rm>, LSL #<shift_imm>
271 shift_imm = (OpCode >> 7) & 0x1f;
272 shift = (OpCode >> 5) & 0x3;
273
274 if (shift == 0x0) {
275 Type = "LSL";
276 } else if (shift == 0x1) {
277 Type = "LSR";
278 if (shift_imm == 0) {
279 shift_imm = 32;
280 }
281 } else if (shift == 0x12) {
282 Type = "ASR";
283 } else if (shift_imm == 0) {
284 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, RRX", gReg[Rn], SIGN (U), gReg[Rm]);
285 // FIx me
286 return;
287 } else {
288 Type = "ROR";
289 }
290
291 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, #%d", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm);
292 }
293 }
294 return;
295 }
296
297 if ((OpCode & 0x0e000000) == 0x00000000) {
298 // LDR/STR address mode 3
299 // LDR|STR{<cond>}H|SH|SB|D <Rd>, <addressing_mode>
300 if (L) {
301 if (!S) {
302 Root = "LDR%aH %a, ";
303 } else if (!H) {
304 Root = "LDR%aSB %a, ";
305 } else {
306 Root = "LDR%aSH %a, ";
307 }
308 } else {
309 if (!S) {
310 Root = "STR%aH %a ";
311 } else if (!H) {
312 Root = "LDR%aD %a ";
313 } else {
314 Root = "STR%aD %a ";
315 }
316 }
317
318 Index = AsciiSPrint (Buf, Size, Root, COND (OpCode), gReg[Rd]);
319
320 S = (OpCode & BIT6) == BIT6;
321 H = (OpCode & BIT5) == BIT5;
322 offset_8 = ((OpCode >> 4) | (OpCode * 0xf)) & 0xff;
323 if (P & !W) {
324 // Immediate offset/index
325 if (B) {
326 // A5.3.2 [<Rn>, #+/-<offset_8>]
327 // A5.3.4 [<Rn>, #+/-<offset_8>]!
328 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%d]%a", gReg[Rn], SIGN (U), offset_8, WRITE (W));
329 } else {
330 // A5.3.3 [<Rn>, +/-<Rm>]
331 // A5.3.5 [<Rn>, +/-<Rm>]!
332 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%]a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W));
333 }
334 } else {
335 // Register offset/index
336 if (B) {
337 // A5.3.6 [<Rn>], #+/-<offset_8>
338 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%d", gReg[Rn], SIGN (U), offset_8);
339 } else {
340 // A5.3.7 [<Rn>], +/-<Rm>
341 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]);
342 }
343 }
344 return;
345 }
346
347 if ((OpCode & 0x0fb000f0) == 0x01000050) {
348 // A4.1.108 SWP SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
349 // A4.1.109 SWPB SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
350 AsciiSPrint (Buf, Size, "SWP%a%a %a, %a, [%a]", COND (OpCode), BYTE (B), gReg[Rd], gReg[Rm], gReg[Rn]);
351 return;
352 }
353
354 if ((OpCode & 0xfe5f0f00) == 0xf84d0500) {
355 // A4.1.90 SRS SRS<addressing_mode> #<mode>{!}
356 AsciiSPrint (Buf, Size, "SRS%a #0x%x%a", gLdmStack[(OpCode >> 23) & 3], OpCode & 0x1f, WRITE (W));
357 return;
358 }
359
360 if ((OpCode & 0xfe500f00) == 0xf8100500) {
361 // A4.1.59 RFE<addressing_mode> <Rn>{!}
362 AsciiSPrint (Buf, Size, "RFE%a %a", gLdmStack[(OpCode >> 23) & 3], gReg[Rn], WRITE (W));
363 return;
364 }
365
366 if ((OpCode & 0xfff000f0) == 0xe1200070) {
367 // A4.1.7 BKPT <immed_16>
368 AsciiSPrint (Buf, Size, "BKPT %x", ((OpCode >> 8) | (OpCode & 0xf)) & 0xffff);
369 return;
370 }
371
372 if ((OpCode & 0xfff10020) == 0xf1000000) {
373 // A4.1.16 CPS<effect> <iflags> {, #<mode>}
374 if (((OpCode >> 6) & 0x7) == 0) {
375 AsciiSPrint (Buf, Size, "CPS #0x%x", (OpCode & 0x2f));
376 } else {
377 imode = (OpCode >> 18) & 0x3;
378 Index = AsciiSPrint (Buf, Size, "CPS%a %a%a%a", (imode == 3) ? "ID":"IE", (OpCode & BIT8) ? "A":"", (OpCode & BIT7) ? "I":"", (OpCode & BIT6) ? "F":"");
379 if ((OpCode & BIT17) != 0) {
380 AsciiSPrint (&Buf[Index], Size - Index, ", #0x%x", OpCode & 0x1f);
381 }
382 }
383 return;
384 }
385
386 if ((OpCode & 0x0f000000) == 0x0f000000) {
387 // A4.1.107 SWI{<cond>} <immed_24>
388 AsciiSPrint (Buf, Size, "SWI%a %x", COND (OpCode), OpCode & 0x00ffffff);
389 return;
390 }
391
392 if ((OpCode & 0x0fb00000) == 0x01000000) {
393 // A4.1.38 MRS{<cond>} <Rd>, CPSR MRS{<cond>} <Rd>, SPSR
394 AsciiSPrint (Buf, Size, "MRS%a %a, %a", COND (OpCode), gReg[Rd], B ? "SPSR" : "CPSR");
395 return;
396 }
397
398
399 if ((OpCode & 0x0db00000) == 0x03200000) {
400 // A4.1.38 MSR{<cond>} CPSR_<fields>, #<immediate> MSR{<cond>} CPSR_<fields>, <Rm>
401 if (I) {
402 // MSR{<cond>} CPSR_<fields>, #<immediate>
403 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));
404 } else {
405 // MSR{<cond>} CPSR_<fields>, <Rm>
406 AsciiSPrint (Buf, Size, "MRS%a %a_%a, %a", COND (OpCode), B ? "SPSR" : "CPSR", gReg[Rd]);
407 }
408 return;
409 }
410
411 if ((OpCode & 0xff000010) == 0xfe000000) {
412 // A4.1.13 CDP{<cond>} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
413 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);
414 return;
415 }
416
417 if ((OpCode & 0x0e000000) == 0x0c000000) {
418 // A4.1.19 LDC and A4.1.96 SDC
419 if ((OpCode & 0xf0000000) == 0xf0000000) {
420 Index = AsciiSPrint (Buf, Size, "%a2 0x%x, CR%d, ", L ? "LDC":"SDC", (OpCode >> 8) & 0xf, Rd);
421 } else {
422 Index = AsciiSPrint (Buf, Size, "%a%a 0x%x, CR%d, ", L ? "LDC":"SDC", COND (OpCode), (OpCode >> 8) & 0xf, Rd);
423 }
424
425 if (!P) {
426 if (!W) {
427 // A5.5.5.5 [<Rn>], <option>
428 AsciiSPrint (&Buf[Index], Size - Index, "[%a], {0x%x}", gReg[Rn], OpCode & 0xff);
429 } else {
430 // A.5.5.4 [<Rn>], #+/-<offset_8>*4
431 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x*4", gReg[Rn], SIGN (U), OpCode & 0xff);
432 }
433 } else {
434 // A5.5.5.2 [<Rn>, #+/-<offset_8>*4 ]!
435 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x*4]%a", gReg[Rn], SIGN (U), OpCode & 0xff, WRITE (W));
436 }
437
438 }
439
440 if ((OpCode & 0x0f000010) == 0x0e000010) {
441 // A4.1.32 MRC2, MCR2
442 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);
443 return;
444 }
445
446 if ((OpCode & 0x0ff00000) == 0x0c400000) {
447 // A4.1.33 MRRC2, MCRR2
448 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);
449 return;
450 }
451
452 AsciiSPrint (Buf, Size, "Faulting OpCode 0x%08x", OpCode);
453
454 *OpCodePtr += 1;
455 return;
456 }
457