TianoCore EDK2 master
Loading...
Searching...
No Matches
ArmDisassembler.c
Go to the documentation of this file.
1
11#include <Base.h>
12#include <Library/BaseLib.h>
13#include <Library/PrintLib.h>
15
16CHAR8 *gCondition[] = {
17 "EQ",
18 "NE",
19 "CS",
20 "CC",
21 "MI",
22 "PL",
23 "VS",
24 "VC",
25 "HI",
26 "LS",
27 "GE",
28 "LT",
29 "GT",
30 "LE",
31 "",
32 "2"
33};
34
35#define COND(_a) gCondition[((_a) >> 28)]
36
37CHAR8 *gReg[] = {
38 "r0",
39 "r1",
40 "r2",
41 "r3",
42 "r4",
43 "r5",
44 "r6",
45 "r7",
46 "r8",
47 "r9",
48 "r10",
49 "r11",
50 "r12",
51 "sp",
52 "lr",
53 "pc"
54};
55
56CHAR8 *gLdmAdr[] = {
57 "DA",
58 "IA",
59 "DB",
60 "IB"
61};
62
63CHAR8 *gLdmStack[] = {
64 "FA",
65 "FD",
66 "EA",
67 "ED"
68};
69
70#define LDM_EXT(_reg, _off) ((_reg == 13) ? gLdmStack[(_off)] : gLdmAdr[(_off)])
71
72#define SIGN(_U) ((_U) ? "" : "-")
73#define WRITE(_Write) ((_Write) ? "!" : "")
74#define BYTE(_B) ((_B) ? "B":"")
75#define USER(_B) ((_B) ? "^" : "")
76
77CHAR8 mMregListStr[4*15 + 1];
78
79CHAR8 *
80MRegList (
81 UINT32 OpCode
82 )
83{
84 UINTN Index, Start, End;
85 BOOLEAN First;
86
87 mMregListStr[0] = '\0';
88 AsciiStrCatS (mMregListStr, sizeof mMregListStr, "{");
89 for (Index = 0, First = TRUE; Index <= 15; Index++) {
90 if ((OpCode & (1 << Index)) != 0) {
91 Start = End = Index;
92 for (Index++; ((OpCode & (1 << Index)) != 0) && Index <= 15; Index++) {
93 End = Index;
94 }
95
96 if (!First) {
97 AsciiStrCatS (mMregListStr, sizeof mMregListStr, ",");
98 } else {
99 First = FALSE;
100 }
101
102 if (Start == End) {
103 AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[Start]);
104 AsciiStrCatS (mMregListStr, sizeof mMregListStr, ", ");
105 } else {
106 AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[Start]);
107 AsciiStrCatS (mMregListStr, sizeof mMregListStr, "-");
108 AsciiStrCatS (mMregListStr, sizeof mMregListStr, gReg[End]);
109 }
110 }
111 }
112
113 if (First) {
114 AsciiStrCatS (mMregListStr, sizeof mMregListStr, "ERROR");
115 }
116
117 AsciiStrCatS (mMregListStr, sizeof mMregListStr, "}");
118
119 // BugBug: Make caller pass in buffer it is cleaner
120 return mMregListStr;
121}
122
123CHAR8 *
124FieldMask (
125 IN UINT32 Mask
126 )
127{
128 return "";
129}
130
131UINT32
132RotateRight (
133 IN UINT32 Op,
134 IN UINT32 Shift
135 )
136{
137 return (Op >> Shift) | (Op << (32 - Shift));
138}
139
153VOID
155 IN UINT32 **OpCodePtr,
156 OUT CHAR8 *Buf,
157 OUT UINTN Size,
158 IN BOOLEAN Extended
159 )
160{
161 UINT32 OpCode;
162 CHAR8 *Type;
163 CHAR8 *Root;
164 BOOLEAN Imm, Pre, Up, WriteBack, Write, Load, Sign, Half;
165 UINT32 Rn, Rd, Rm;
166 UINT32 IMod, Offset8, Offset12;
167 UINT32 Index;
168 UINT32 ShiftImm, Shift;
169
170 OpCode = **OpCodePtr;
171
172 Imm = (OpCode & BIT25) == BIT25; // I
173 Pre = (OpCode & BIT24) == BIT24; // P
174 Up = (OpCode & BIT23) == BIT23; // U
175 WriteBack = (OpCode & BIT22) == BIT22; // B, also called S
176 Write = (OpCode & BIT21) == BIT21; // W
177 Load = (OpCode & BIT20) == BIT20; // L
178 Sign = (OpCode & BIT6) == BIT6; // S
179 Half = (OpCode & BIT5) == BIT5; // H
180 Rn = (OpCode >> 16) & 0xf;
181 Rd = (OpCode >> 12) & 0xf;
182 Rm = (OpCode & 0xf);
183
184 if (Extended) {
185 Index = AsciiSPrint (Buf, Size, "0x%08x ", OpCode);
186 Buf += Index;
187 Size -= Index;
188 }
189
190 // LDREX, STREX
191 if ((OpCode & 0x0fe000f0) == 0x01800090) {
192 if (Load) {
193 // A4.1.27 LDREX{<cond>} <Rd>, [<Rn>]
194 AsciiSPrint (Buf, Size, "LDREX%a %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn]);
195 } else {
196 // A4.1.103 STREX{<cond>} <Rd>, <Rm>, [<Rn>]
197 AsciiSPrint (Buf, Size, "STREX%a %a, %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn], gReg[Rn]);
198 }
199
200 return;
201 }
202
203 // LDM/STM
204 if ((OpCode & 0x0e000000) == 0x08000000) {
205 if (Load) {
206 // A4.1.20 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers>
207 // A4.1.21 LDM{<cond>}<addressing_mode> <Rn>, <registers_without_pc>^
208 // A4.1.22 LDM{<cond>}<addressing_mode> <Rn>{!}, <registers_and_pc>^
209 AsciiSPrint (Buf, Size, "LDM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn, (OpCode >> 23) & 3), gReg[Rn], WRITE (Write), MRegList (OpCode), USER (WriteBack));
210 } else {
211 // A4.1.97 STM{<cond>}<addressing_mode> <Rn>{!}, <registers>
212 // A4.1.98 STM{<cond>}<addressing_mode> <Rn>, <registers>^
213 AsciiSPrint (Buf, Size, "STM%a%a, %a%a, %a", COND (OpCode), LDM_EXT (Rn, (OpCode >> 23) & 3), gReg[Rn], WRITE (Write), MRegList (OpCode), USER (WriteBack));
214 }
215
216 return;
217 }
218
219 // LDR/STR Address Mode 2
220 if (((OpCode & 0x0c000000) == 0x04000000) || ((OpCode & 0xfd70f000) == 0xf550f000)) {
221 Offset12 = OpCode & 0xfff;
222 if ((OpCode & 0xfd70f000) == 0xf550f000) {
223 Index = AsciiSPrint (Buf, Size, "PLD");
224 } else {
225 Index = AsciiSPrint (Buf, Size, "%a%a%a%a %a, ", Load ? "LDR" : "STR", COND (OpCode), BYTE (WriteBack), (!(Pre) && Write) ? "T" : "", gReg[Rd]);
226 }
227
228 if (Pre) {
229 if (!Imm) {
230 // A5.2.2 [<Rn>, #+/-<offset_12>]
231 // A5.2.5 [<Rn>, #+/-<offset_12>]
232 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x]%a", gReg[Rn], SIGN (Up), Offset12, WRITE (Write));
233 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
234 // A5.2.3 [<Rn>, +/-<Rm>]
235 // A5.2.6 [<Rn>, +/-<Rm>]!
236 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a]%a", gReg[Rn], SIGN (Up), WRITE (Write));
237 } else {
238 // A5.2.4 [<Rn>, +/-<Rm>, LSL #<shift_imm>]
239 // A5.2.7 [<Rn>, +/-<Rm>, LSL #<shift_imm>]!
240 ShiftImm = (OpCode >> 7) & 0x1f;
241 Shift = (OpCode >> 5) & 0x3;
242 if (Shift == 0x0) {
243 Type = "LSL";
244 } else if (Shift == 0x1) {
245 Type = "LSR";
246 if (ShiftImm == 0) {
247 ShiftImm = 32;
248 }
249 } else if (Shift == 0x2) {
250 Type = "ASR";
251 } else if (ShiftImm == 0) {
252 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, RRX]%a", gReg[Rn], SIGN (Up), gReg[Rm], WRITE (Write));
253 return;
254 } else {
255 Type = "ROR";
256 }
257
258 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, #%d]%a", gReg[Rn], SIGN (Up), gReg[Rm], Type, ShiftImm, WRITE (Write));
259 }
260 } else {
261 // !Pre
262 if (!Imm) {
263 // A5.2.8 [<Rn>], #+/-<offset_12>
264 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x", gReg[Rn], SIGN (Up), Offset12);
265 } else if ((OpCode & 0x03000ff0) == 0x03000000) {
266 // A5.2.9 [<Rn>], +/-<Rm>
267 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (Up), gReg[Rm]);
268 } else {
269 // A5.2.10 [<Rn>], +/-<Rm>, LSL #<shift_imm>
270 ShiftImm = (OpCode >> 7) & 0x1f;
271 Shift = (OpCode >> 5) & 0x3;
272
273 if (Shift == 0x0) {
274 Type = "LSL";
275 } else if (Shift == 0x1) {
276 Type = "LSR";
277 if (ShiftImm == 0) {
278 ShiftImm = 32;
279 }
280 } else if (Shift == 0x2) {
281 Type = "ASR";
282 } else if (ShiftImm == 0) {
283 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, RRX", gReg[Rn], SIGN (Up), gReg[Rm]);
284 // FIx me
285 return;
286 } else {
287 Type = "ROR";
288 }
289
290 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, #%d", gReg[Rn], SIGN (Up), gReg[Rm], Type, ShiftImm);
291 }
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 (Load) {
301 if (!Sign) {
302 Root = "LDR%aH %a, ";
303 } else if (!Half) {
304 Root = "LDR%aSB %a, ";
305 } else {
306 Root = "LDR%aSH %a, ";
307 }
308 } else {
309 if (!Sign) {
310 Root = "STR%aH %a ";
311 } else if (!Half) {
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 Sign = (OpCode & BIT6) == BIT6;
321 Half = (OpCode & BIT5) == BIT5;
322 Offset8 = ((OpCode >> 4) | (OpCode * 0xf)) & 0xff;
323 if (Pre & !Write) {
324 // Immediate offset/index
325 if (WriteBack) {
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 (Up), Offset8, WRITE (Write));
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 (Up), gReg[Rm], WRITE (Write));
333 }
334 } else {
335 // Register offset/index
336 if (WriteBack) {
337 // A5.3.6 [<Rn>], #+/-<offset_8>
338 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%d", gReg[Rn], SIGN (Up), Offset8);
339 } else {
340 // A5.3.7 [<Rn>], +/-<Rm>
341 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (Up), gReg[Rm]);
342 }
343 }
344
345 return;
346 }
347
348 if ((OpCode & 0x0fb000f0) == 0x01000050) {
349 // A4.1.108 SWP SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
350 // A4.1.109 SWPB SWP{<cond>}B <Rd>, <Rm>, [<Rn>]
351 AsciiSPrint (Buf, Size, "SWP%a%a %a, %a, [%a]", COND (OpCode), BYTE (WriteBack), gReg[Rd], gReg[Rm], gReg[Rn]);
352 return;
353 }
354
355 if ((OpCode & 0xfe5f0f00) == 0xf84d0500) {
356 // A4.1.90 SRS SRS<addressing_mode> #<mode>{!}
357 AsciiSPrint (Buf, Size, "SRS%a #0x%x%a", gLdmStack[(OpCode >> 23) & 3], OpCode & 0x1f, WRITE (Write));
358 return;
359 }
360
361 if ((OpCode & 0xfe500f00) == 0xf8100500) {
362 // A4.1.59 RFE<addressing_mode> <Rn>{!}
363 AsciiSPrint (Buf, Size, "RFE%a %a", gLdmStack[(OpCode >> 23) & 3], gReg[Rn], WRITE (Write));
364 return;
365 }
366
367 if ((OpCode & 0xfff000f0) == 0xe1200070) {
368 // A4.1.7 BKPT <immed_16>
369 AsciiSPrint (Buf, Size, "BKPT %x", ((OpCode >> 8) | (OpCode & 0xf)) & 0xffff);
370 return;
371 }
372
373 if ((OpCode & 0xfff10020) == 0xf1000000) {
374 // A4.1.16 CPS<effect> <iflags> {, #<mode>}
375 if (((OpCode >> 6) & 0x7) == 0) {
376 AsciiSPrint (Buf, Size, "CPS #0x%x", (OpCode & 0x2f));
377 } else {
378 IMod = (OpCode >> 18) & 0x3;
379 Index = AsciiSPrint (
380 Buf,
381 Size,
382 "CPS%a %a%a%a",
383 (IMod == 3) ? "ID" : "IE",
384 ((OpCode & BIT8) != 0) ? "A" : "",
385 ((OpCode & BIT7) != 0) ? "I" : "",
386 ((OpCode & BIT6) != 0) ? "F" : ""
387 );
388 if ((OpCode & BIT17) != 0) {
389 AsciiSPrint (&Buf[Index], Size - Index, ", #0x%x", OpCode & 0x1f);
390 }
391 }
392
393 return;
394 }
395
396 if ((OpCode & 0x0f000000) == 0x0f000000) {
397 // A4.1.107 SWI{<cond>} <immed_24>
398 AsciiSPrint (Buf, Size, "SWI%a %x", COND (OpCode), OpCode & 0x00ffffff);
399 return;
400 }
401
402 if ((OpCode & 0x0fb00000) == 0x01000000) {
403 // A4.1.38 MRS{<cond>} <Rd>, CPSR MRS{<cond>} <Rd>, SPSR
404 AsciiSPrint (Buf, Size, "MRS%a %a, %a", COND (OpCode), gReg[Rd], WriteBack ? "SPSR" : "CPSR");
405 return;
406 }
407
408 if ((OpCode & 0x0db00000) == 0x01200000) {
409 // A4.1.38 MSR{<cond>} CPSR_<fields>, #<immediate> MSR{<cond>} CPSR_<fields>, <Rm>
410 if (Imm) {
411 // MSR{<cond>} CPSR_<fields>, #<immediate>
412 AsciiSPrint (Buf, Size, "MRS%a %a_%a, #0x%x", COND (OpCode), WriteBack ? "SPSR" : "CPSR", FieldMask ((OpCode >> 16) & 0xf), RotateRight (OpCode & 0xf, ((OpCode >> 8) & 0xf) *2));
413 } else {
414 // MSR{<cond>} CPSR_<fields>, <Rm>
415 AsciiSPrint (Buf, Size, "MRS%a %a_%a, %a", COND (OpCode), WriteBack ? "SPSR" : "CPSR", gReg[Rd]);
416 }
417
418 return;
419 }
420
421 if ((OpCode & 0xff000010) == 0xfe000000) {
422 // A4.1.13 CDP{<cond>} <coproc>, <opcode_1>, <CRd>, <CRn>, <CRm>, <opcode_2>
423 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);
424 return;
425 }
426
427 if ((OpCode & 0x0e000000) == 0x0c000000) {
428 // A4.1.19 LDC and A4.1.96 SDC
429 if ((OpCode & 0xf0000000) == 0xf0000000) {
430 Index = AsciiSPrint (Buf, Size, "%a2 0x%x, CR%d, ", Load ? "LDC" : "SDC", (OpCode >> 8) & 0xf, Rd);
431 } else {
432 Index = AsciiSPrint (Buf, Size, "%a%a 0x%x, CR%d, ", Load ? "LDC" : "SDC", COND (OpCode), (OpCode >> 8) & 0xf, Rd);
433 }
434
435 if (!Pre) {
436 if (!Write) {
437 // A5.5.5.5 [<Rn>], <option>
438 AsciiSPrint (&Buf[Index], Size - Index, "[%a], {0x%x}", gReg[Rn], OpCode & 0xff);
439 } else {
440 // A.5.5.4 [<Rn>], #+/-<offset_8>*4
441 AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x*4", gReg[Rn], SIGN (Up), OpCode & 0xff);
442 }
443 } else {
444 // A5.5.5.2 [<Rn>, #+/-<offset_8>*4 ]!
445 AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x*4]%a", gReg[Rn], SIGN (Up), OpCode & 0xff, WRITE (Write));
446 }
447 }
448
449 if ((OpCode & 0x0f000010) == 0x0e000010) {
450 // A4.1.32 MRC2, MCR2
451 AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, CR%d, CR%d, 0x%x", Load ? "MRC" : "MCR", COND (OpCode), (OpCode >> 8) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], Rn, Rm, (OpCode >> 5) &0x7);
452 return;
453 }
454
455 if ((OpCode & 0x0ff00000) == 0x0c400000) {
456 // A4.1.33 MRRC2, MCRR2
457 AsciiSPrint (Buf, Size, "%a%a 0x%x, 0x%x, %a, %a, CR%d", Load ? "MRRC" : "MCRR", COND (OpCode), (OpCode >> 4) & 0xf, (OpCode >> 20) & 0xf, gReg[Rd], gReg[Rn], Rm);
458 return;
459 }
460
461 AsciiSPrint (Buf, Size, "Faulting OpCode 0x%08x", OpCode);
462
463 *OpCodePtr += 1;
464 return;
465}
UINT64 UINTN
VOID DisassembleArmInstruction(IN UINT32 **OpCodePtr, OUT CHAR8 *Buf, OUT UINTN Size, IN BOOLEAN Extended)
RETURN_STATUS EFIAPI AsciiStrCatS(IN OUT CHAR8 *Destination, IN UINTN DestMax, IN CONST CHAR8 *Source)
Definition: SafeString.c:1964
UINTN EFIAPI AsciiSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition: PrintLib.c:813
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284