From: andrewfish Date: Mon, 1 Feb 2010 18:25:18 +0000 (+0000) Subject: Move ARM disassembler into a library. X-Git-Tag: edk2-stable201903~16434 X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=commitdiff_plain;h=097bd461c4219edb62f4595ce7ccc6ec3bb34db9;ds=sidebyside Move ARM disassembler into a library. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@9902 6f19259b-4bc3-4df7-8a09-765794883524 --- diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec index 67c729d8e1..8f5d69635d 100644 --- a/ArmPkg/ArmPkg.dec +++ b/ArmPkg/ArmPkg.dec @@ -36,7 +36,8 @@ SemihostLib|Include/Library/Semihosting.h UncachedMemoryAllocationLib|Include/Library/UncachedMemoryAllocationLib.h DefaultExceptioHandlerLib|Include/Library/DefaultExceptioHandlerLib.h - + ArmDisassemblerLib|Include/Library/ArmDisassemblerLib.h + [Guids.common] gArmTokenSpaceGuid = { 0xBB11ECFE, 0x820F, 0x4968, { 0xBB, 0xA6, 0xF7, 0x6A, 0xFE, 0x30, 0x25, 0x96 } } diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc index 12dd519572..b0d2c8f227 100644 --- a/ArmPkg/ArmPkg.dsc +++ b/ArmPkg/ArmPkg.dsc @@ -52,6 +52,7 @@ ArmLib|ArmPkg/Library/ArmLib/ArmCortexA/ArmCortexArmLib.inf CpuLib|MdePkg/Library/BaseCpuLib/BaseCpuLib.inf + ArmDisassemblerLib|ArmPkg/Library/ArmDisassemblerLib/ArmDisassemblerLib.inf [LibraryClasses.ARM] NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf diff --git a/ArmPkg/Include/Library/ArmDisassemblerLib.h b/ArmPkg/Include/Library/ArmDisassemblerLib.h new file mode 100644 index 0000000000..6ba270fea3 --- /dev/null +++ b/ArmPkg/Include/Library/ArmDisassemblerLib.h @@ -0,0 +1,39 @@ +/** @file + + Copyright (c) 2008-2010 Apple Inc. All rights reserved.
+ + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#ifndef __ARM_DISASSEBLER_LIB_H__ +#define __ARM_DISASSEBLER_LIB_H__ + +/** + Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to + point to next instructin. + + We cheat and only decode instructions that access + memory. If the instruction is not found we dump the instruction in hex. + + @param OpCodePtrPtr Pointer to pointer of ARM Thumb instruction to disassemble. + @param Thumb TRUE for Thumb(2), FALSE for ARM instruction stream + @param Buf Buffer to sprintf disassembly into. + @param Size Size of Buf in bytes. + +**/ +VOID +DisassembleInstruction ( + IN UINT8 **OpCodePtr, + IN BOOLEAN Thumb, + OUT CHAR8 *Buf, + OUT UINTN Size + ); + +#endif diff --git a/ArmPkg/Library/ArmDisassemblerLib/ArmDisassembler.c b/ArmPkg/Library/ArmDisassemblerLib/ArmDisassembler.c new file mode 100644 index 0000000000..5b43f5542e --- /dev/null +++ b/ArmPkg/Library/ArmDisassemblerLib/ArmDisassembler.c @@ -0,0 +1,448 @@ +/** @file + Default exception handler + + Copyright (c) 2008-2010, Apple Inc. All rights reserved. + + All rights reserved. This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include +#include +#include + +CHAR8 *gCondition[] = { + "EQ", + "NE", + "CS", + "CC", + "MI", + "PL", + "VS", + "VC", + "HI", + "LS", + "GE", + "LT", + "GT", + "LE", + "", + "2" +}; + +#define COND(_a) gCondition[(_a) >> 28] + +CHAR8 *gReg[] = { + "r0", + "r1", + "r2", + "r3", + "r4", + "r5", + "r6", + "r7", + "r8", + "r9", + "r10", + "r11", + "r12", + "sp", + "lr", + "pc" +}; + +CHAR8 *gLdmAdr[] = { + "DA", + "IA", + "DB", + "IB" +}; + +CHAR8 *gLdmStack[] = { + "FA", + "FD", + "EA", + "ED" +}; + +#define LDM_EXT(_reg, _off) ((_reg == 13) ? gLdmStack[(_off)] : gLdmAdr[(_off)]) + + +#define SIGN(_U) ((_U) ? "" : "-") +#define WRITE(_W) ((_W) ? "!" : "") +#define BYTE(_B) ((_B) ? "B":"") +#define USER(_B) ((_B) ? "^" : "") + +CHAR8 mMregListStr[4*15 + 1]; + +CHAR8 * +MRegList ( + UINT32 OpCode + ) +{ + UINTN Index, Start, End; + CHAR8 *Str; + BOOLEAN First; + + Str = mMregListStr; + *Str = '\0'; + AsciiStrCat (Str, "{"); + for (Index = 0, First = TRUE; Index <= 15; Index++) { + if ((OpCode & (1 << Index)) != 0) { + Start = End = Index; + for (Index++; ((OpCode & (1 << Index)) != 0) && Index <= 15; Index++) { + End = Index; + } + + if (!First) { + AsciiStrCat (Str, ","); + } else { + First = FALSE; + } + + if (Start == End) { + AsciiStrCat (Str, gReg[Start]); + AsciiStrCat (Str, ", "); + } else { + AsciiStrCat (Str, gReg[Start]); + AsciiStrCat (Str, "-"); + AsciiStrCat (Str, gReg[End]); + } + } + } + if (First) { + AsciiStrCat (Str, "ERROR"); + } + AsciiStrCat (Str, "}"); + + // BugBug: Make caller pass in buffer it is cleaner + return mMregListStr; +} + +CHAR8 * +FieldMask ( + IN UINT32 Mask + ) +{ + return ""; +} + +UINT32 +RotateRight ( + IN UINT32 Op, + IN UINT32 Shift + ) +{ + return (Op >> Shift) | (Op << (32 - Shift)); +} + + +/** + Place a dissasembly of of **OpCodePtr into buffer, and update OpCodePtr to + point to next instructin. + + We cheat and only decode instructions that access + memory. If the instruction is not found we dump the instruction in hex. + + @param OpCodePtr Pointer to pointer of ARM instruction to disassemble. + @param Buf Buffer to sprintf disassembly into. + @param Size Size of Buf in bytes. + +**/ +VOID +DisassembleArmInstruction ( + IN UINT32 **OpCodePtr, + OUT CHAR8 *Buf, + OUT UINTN Size + ) +{ + UINT32 OpCode = **OpCodePtr; + CHAR8 *Type, *Root; + BOOLEAN I, P, U, B, W, L, S, H; + UINT32 Rn, Rd, Rm; + UINT32 imode, offset_8, offset_12; + UINT32 Index; + UINT32 shift_imm, shift; + + I = (OpCode & BIT25) == BIT25; + P = (OpCode & BIT24) == BIT24; + U = (OpCode & BIT23) == BIT23; + B = (OpCode & BIT22) == BIT22; // Also called S + W = (OpCode & BIT21) == BIT21; + L = (OpCode & BIT20) == BIT20; + S = (OpCode & BIT6) == BIT6; + H = (OpCode & BIT5) == BIT5; + Rn = (OpCode >> 16) & 0xf; + Rd = (OpCode >> 12) & 0xf; + Rm = (OpCode & 0xf); + + // LDREX, STREX + if ((OpCode & 0x0fe000f0) == 0x01800090) { + if (L) { + // A4.1.27 LDREX{} , [] + AsciiSPrint (Buf, Size, "LDREX%a %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn]); + } else { + // A4.1.103 STREX{} , , [] + AsciiSPrint (Buf, Size, "STREX%a %a, %a, [%a]", COND (OpCode), gReg[Rd], gReg[Rn], gReg[Rn]); + } + return; + } + + // LDM/STM + if ((OpCode & 0x0e000000) == 0x08000000) { + if (L) { + // A4.1.20 LDM{} {!}, + // A4.1.21 LDM{} , ^ + // A4.1.22 LDM{} {!}, ^ + 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)); + } else { + // A4.1.97 STM{} {!}, + // A4.1.98 STM{} , ^ + 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)); + } + return; + } + + // LDR/STR Address Mode 2 + if ( ((OpCode & 0x0c000000) == 0x04000000) || ((OpCode & 0xfd70f000 ) == 0xf550f000) ) { + offset_12 = OpCode & 0xfff; + if ((OpCode & 0xfd70f000 ) == 0xf550f000) { + Index = AsciiSPrint (Buf, Size, "PLD"); + } else { + Index = AsciiSPrint (Buf, Size, "%a%a%a%a %a, ", L ? "LDR" : "STR", COND (OpCode), BYTE (B), (!P & W) ? "T":"", gReg[Rd]); + } + if (P) { + if (!I) { + // A5.2.2 [, #+/-] + // A5.2.5 [, #+/-] + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a0x%x]%a", gReg[Rn], SIGN (U), offset_12, WRITE (W)); + } else if ((OpCode & 0x03000ff0) == 0x03000000) { + // A5.2.3 [, +/-] + // A5.2.6 [, +/-]! + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a]%a", gReg[Rn], SIGN (U), WRITE (W)); + } else { + // A5.2.4 [, +/-, LSL #] + // A5.2.7 [, +/-, LSL #]! + shift_imm = (OpCode >> 7) & 0x1f; + shift = (OpCode >> 5) & 0x3; + if (shift == 0x0) { + Type = "LSL"; + } else if (shift == 0x1) { + Type = "LSR"; + if (shift_imm == 0) { + shift_imm = 32; + } + } else if (shift == 0x12) { + Type = "ASR"; + } else if (shift_imm == 0) { + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, RRX]%a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W)); + return; + } else { + Type = "ROR"; + } + + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%a, %a, #%d]%a", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm, WRITE (W)); + } + } else { // !P + if (!I) { + // A5.2.8 [], #+/- + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a0x%x", gReg[Rn], SIGN (U), offset_12); + } else if ((OpCode & 0x03000ff0) == 0x03000000) { + // A5.2.9 [], +/- + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]); + } else { + // A5.2.10 [], +/-, LSL # + shift_imm = (OpCode >> 7) & 0x1f; + shift = (OpCode >> 5) & 0x3; + + if (shift == 0x0) { + Type = "LSL"; + } else if (shift == 0x1) { + Type = "LSR"; + if (shift_imm == 0) { + shift_imm = 32; + } + } else if (shift == 0x12) { + Type = "ASR"; + } else if (shift_imm == 0) { + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, RRX", gReg[Rn], SIGN (U), gReg[Rm]); + // FIx me + return; + } else { + Type = "ROR"; + } + + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a, %a, #%d", gReg[Rn], SIGN (U), gReg[Rm], Type, shift_imm); + } + } + return; + } + + if ((OpCode & 0x0e000000) == 0x00000000) { + // LDR/STR address mode 3 + // LDR|STR{}H|SH|SB|D , + if (L) { + if (!S) { + Root = "LDR%aH %a, "; + } else if (!H) { + Root = "LDR%aSB %a, "; + } else { + Root = "LDR%aSH %a, "; + } + } else { + if (!S) { + Root = "STR%aH %a "; + } else if (!H) { + Root = "LDR%aD %a "; + } else { + Root = "STR%aD %a "; + } + } + + Index = AsciiSPrint (Buf, Size, Root, COND (OpCode), gReg[Rd]); + + S = (OpCode & BIT6) == BIT6; + H = (OpCode & BIT5) == BIT5; + offset_8 = ((OpCode >> 4) | (OpCode * 0xf)) & 0xff; + if (P & !W) { + // Immediate offset/index + if (B) { + // A5.3.2 [, #+/-] + // A5.3.4 [, #+/-]! + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%d]%a", gReg[Rn], SIGN (U), offset_8, WRITE (W)); + } else { + // A5.3.3 [, +/-] + // A5.3.5 [, +/-]! + AsciiSPrint (&Buf[Index], Size - Index, "[%a, #%a%]a", gReg[Rn], SIGN (U), gReg[Rm], WRITE (W)); + } + } else { + // Register offset/index + if (B) { + // A5.3.6 [], #+/- + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%d", gReg[Rn], SIGN (U), offset_8); + } else { + // A5.3.7 [], +/- + AsciiSPrint (&Buf[Index], Size - Index, "[%a], #%a%a", gReg[Rn], SIGN (U), gReg[Rm]); + } + } + return; + } + + if ((OpCode & 0x0fb000f0) == 0x01000050) { + // A4.1.108 SWP SWP{}B , , [] + // A4.1.109 SWPB SWP{}B , , [] + AsciiSPrint (Buf, Size, "SWP%a%a %a, %a, [%a]", COND (OpCode), BYTE (B), gReg[Rd], gReg[Rm], gReg[Rn]); + return; + } + + if ((OpCode & 0xfe5f0f00) == 0xf84d0500) { + // A4.1.90 SRS SRS #{!} + AsciiSPrint (Buf, Size, "SRS%a #0x%x%a", gLdmStack[(OpCode >> 23) & 3], OpCode & 0x1f, WRITE (W)); + return; + } + + if ((OpCode & 0xfe500f00) == 0xf8100500) { + // A4.1.59 RFE {!} + AsciiSPrint (Buf, Size, "RFE%a %a", gLdmStack[(OpCode >> 23) & 3], gReg[Rn], WRITE (W)); + return; + } + + if ((OpCode & 0xfff000f0) == 0xe1200070) { + // A4.1.7 BKPT + AsciiSPrint (Buf, Size, "BKPT %x", ((OpCode >> 8) | (OpCode & 0xf)) & 0xffff); + return; + } + + if ((OpCode & 0xfff10020) == 0xf1000000) { + // A4.1.16 CPS {, #} + if (((OpCode >> 6) & 0x7) == 0) { + AsciiSPrint (Buf, Size, "CPS #0x%x", (OpCode & 0x2f)); + } else { + imode = (OpCode >> 18) & 0x3; + Index = AsciiSPrint (Buf, Size, "CPS%a %a%a%a", (imode == 3) ? "ID":"IE", (OpCode & BIT8) ? "A":"", (OpCode & BIT7) ? "I":"", (OpCode & BIT6) ? "F":""); + if ((OpCode & BIT17) != 0) { + AsciiSPrint (&Buf[Index], Size - Index, ", #0x%x", OpCode & 0x1f); + } + } + return; + } + + if ((OpCode & 0x0f000000) == 0x0f000000) { + // A4.1.107 SWI{} + AsciiSPrint (Buf, Size, "SWI%a %x", COND (OpCode), OpCode & 0x00ffffff); + return; + } + + if ((OpCode & 0x0fb00000) == 0x01000000) { + // A4.1.38 MRS{} , CPSR MRS{} , SPSR + AsciiSPrint (Buf, Size, "MRS%a %a, %a", COND (OpCode), gReg[Rd], B ? "SPSR" : "CPSR"); + return; + } + + + if ((OpCode & 0x0db00000) == 0x03200000) { + // A4.1.38 MSR{} CPSR_, # MSR{} CPSR_, + if (I) { + // MSR{} CPSR_, # + 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)); + } else { + // MSR{} CPSR_, + AsciiSPrint (Buf, Size, "MRS%a %a_%a, %a", COND (OpCode), B ? "SPSR" : "CPSR", gReg[Rd]); + } + return; + } + + if ((OpCode & 0xff000010) == 0xfe000000) { + // A4.1.13 CDP{} , , , , , + 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); + return; + } + + if ((OpCode & 0x0e000000) == 0x0c000000) { + // A4.1.19 LDC and A4.1.96 SDC + if ((OpCode & 0xf0000000) == 0xf0000000) { + Index = AsciiSPrint (Buf, Size, "%a2 0x%x, CR%d, ", L ? "LDC":"SDC", (OpCode >> 8) & 0xf, Rd); + } else { + Index = AsciiSPrint (Buf, Size, "%a%a 0x%x, CR%d, ", L ? "LDC":"SDC", COND (OpCode), (OpCode >> 8) & 0xf, Rd); + } + + if (!P) { + if (!W) { + // A5.5.5.5 [],