123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692 |
- /** @file
- Processor specific parts of the GDB stub
- Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
- **/
- #include <GdbStubInternal.h>
- #include <Library/CacheMaintenanceLib.h>
- #include <Library/PrintLib.h>
- //
- // Array of exception types that need to be hooked by the debugger
- // (efi, gdb) //efi number
- //
- EFI_EXCEPTION_TYPE_ENTRY gExceptionType[] = {
- { EXCEPT_ARM_SOFTWARE_INTERRUPT, GDB_SIGTRAP }
- // { EXCEPT_ARM_UNDEFINED_INSTRUCTION, GDB_SIGTRAP },
- // { EXCEPT_ARM_PREFETCH_ABORT, GDB_SIGTRAP },
- // { EXCEPT_ARM_DATA_ABORT, GDB_SIGEMT },
- // { EXCEPT_ARM_RESERVED, GDB_SIGILL }
- };
- // Shut up some annoying RVCT warnings
- #ifdef __CC_ARM
- #pragma diag_suppress 1296
- #endif
- UINTN gRegisterOffsets[] = {
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R0),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R1),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R2),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R3),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R4),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R5),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R6),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R7),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R8),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R9),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R10),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R11),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, R12),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, SP),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, LR),
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, PC),
- 0x00000F01, // f0
- 0x00000F02,
- 0x00000F03,
- 0x00000F11, // f1
- 0x00000F12,
- 0x00000F13,
- 0x00000F21, // f2
- 0x00000F22,
- 0x00000F23,
- 0x00000F31, // f3
- 0x00000F32,
- 0x00000F33,
- 0x00000F41, // f4
- 0x00000F42,
- 0x00000F43,
- 0x00000F51, // f5
- 0x00000F52,
- 0x00000F53,
- 0x00000F61, // f6
- 0x00000F62,
- 0x00000F63,
- 0x00000F71, // f7
- 0x00000F72,
- 0x00000F73,
- 0x00000FFF, // fps
- OFFSET_OF (EFI_SYSTEM_CONTEXT_ARM, CPSR)
- };
- // restore warnings for RVCT
- #ifdef __CC_ARM
- #pragma diag_default 1296
- #endif
- /**
- Return the number of entries in the gExceptionType[]
- @retval UINTN, the number of entries in the gExceptionType[] array.
- **/
- UINTN
- MaxEfiException (
- VOID
- )
- {
- return sizeof (gExceptionType) / sizeof (EFI_EXCEPTION_TYPE_ENTRY);
- }
- /**
- Return the number of entries in the gRegisters[]
- @retval UINTN, the number of entries (registers) in the gRegisters[] array.
- **/
- UINTN
- MaxRegisterCount (
- VOID
- )
- {
- return sizeof (gRegisterOffsets) / sizeof (UINTN);
- }
- /**
- Check to see if the ISA is supported.
- ISA = Instruction Set Architecture
- @retval TRUE if Isa is supported
- **/
- BOOLEAN
- CheckIsa (
- IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa
- )
- {
- if (Isa == IsaArm) {
- return TRUE;
- } else {
- return FALSE;
- }
- }
- /**
- This takes in the register number and the System Context, and returns a pointer to the RegNumber-th register in gdb ordering
- It is, by default, set to find the register pointer of the ARM member
- @param SystemContext Register content at time of the exception
- @param RegNumber The register to which we want to find a pointer
- @retval the pointer to the RegNumber-th pointer
- **/
- UINTN *
- FindPointerToRegister (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN UINTN RegNumber
- )
- {
- UINT8 *TempPtr;
- ASSERT (gRegisterOffsets[RegNumber] < 0xF00);
- TempPtr = ((UINT8 *)SystemContext.SystemContextArm) + gRegisterOffsets[RegNumber];
- return (UINT32 *)TempPtr;
- }
- /**
- Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
- @param SystemContext Register content at time of the exception
- @param RegNumber the number of the register that we want to read
- @param OutBufPtr pointer to the output buffer's end. the new data will be added from this point on.
- @retval the pointer to the next character of the output buffer that is available to be written on.
- **/
- CHAR8 *
- BasicReadRegister (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN UINTN RegNumber,
- IN CHAR8 *OutBufPtr
- )
- {
- UINTN RegSize;
- CHAR8 Char;
- if (gRegisterOffsets[RegNumber] > 0xF00) {
- AsciiSPrint (OutBufPtr, 9, "00000000");
- OutBufPtr += 8;
- return OutBufPtr;
- }
- RegSize = 0;
- while (RegSize < 32) {
- Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> (RegSize+4)) & 0xf)];
- if ((Char >= 'A') && (Char <= 'F')) {
- Char = Char - 'A' + 'a';
- }
- *OutBufPtr++ = Char;
- Char = mHexToStr[(UINT8)((*FindPointerToRegister (SystemContext, RegNumber) >> RegSize) & 0xf)];
- if ((Char >= 'A') && (Char <= 'F')) {
- Char = Char - 'A' + 'a';
- }
- *OutBufPtr++ = Char;
- RegSize = RegSize + 8;
- }
- return OutBufPtr;
- }
- /**
- Reads the n-th register's value into an output buffer and sends it as a packet
- @param SystemContext Register content at time of the exception
- @param InBuffer Pointer to the input buffer received from gdb server
- **/
- VOID
- ReadNthRegister (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *InBuffer
- )
- {
- UINTN RegNumber;
- CHAR8 OutBuffer[9]; // 1 reg=8 hex chars, and the end '\0' (escape seq)
- CHAR8 *OutBufPtr; // pointer to the output buffer
- RegNumber = AsciiStrHexToUintn (&InBuffer[1]);
- if (RegNumber >= MaxRegisterCount ()) {
- SendError (GDB_EINVALIDREGNUM);
- return;
- }
- OutBufPtr = OutBuffer;
- OutBufPtr = BasicReadRegister (SystemContext, RegNumber, OutBufPtr);
- *OutBufPtr = '\0'; // the end of the buffer
- SendPacket (OutBuffer);
- }
- /**
- Reads the general registers into an output buffer and sends it as a packet
- @param SystemContext Register content at time of the exception
- **/
- VOID
- EFIAPI
- ReadGeneralRegisters (
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- UINTN Index;
- CHAR8 *OutBuffer;
- CHAR8 *OutBufPtr;
- UINTN RegisterCount = MaxRegisterCount ();
- // It is not safe to allocate pool here....
- OutBuffer = AllocatePool ((RegisterCount * 8) + 1); // 8 bytes per register in string format plus a null to terminate
- OutBufPtr = OutBuffer;
- for (Index = 0; Index < RegisterCount; Index++) {
- OutBufPtr = BasicReadRegister (SystemContext, Index, OutBufPtr);
- }
- *OutBufPtr = '\0';
- SendPacket (OutBuffer);
- FreePool (OutBuffer);
- }
- /**
- Adds the RegNumber-th register's value to the output buffer, starting at the given OutBufPtr
- @param SystemContext Register content at time of the exception
- @param RegNumber the number of the register that we want to write
- @param InBufPtr pointer to the output buffer. the new data will be extracted from the input buffer from this point on.
- @retval the pointer to the next character of the input buffer that can be used
- **/
- CHAR8
- *
- BasicWriteRegister (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN UINTN RegNumber,
- IN CHAR8 *InBufPtr
- )
- {
- UINTN RegSize;
- UINTN TempValue; // the value transferred from a hex char
- UINT32 NewValue; // the new value of the RegNumber-th Register
- if (gRegisterOffsets[RegNumber] > 0xF00) {
- return InBufPtr + 8;
- }
- NewValue = 0;
- RegSize = 0;
- while (RegSize < 32) {
- TempValue = HexCharToInt (*InBufPtr++);
- if ((INTN)TempValue < 0) {
- SendError (GDB_EBADMEMDATA);
- return NULL;
- }
- NewValue += (TempValue << (RegSize+4));
- TempValue = HexCharToInt (*InBufPtr++);
- if ((INTN)TempValue < 0) {
- SendError (GDB_EBADMEMDATA);
- return NULL;
- }
- NewValue += (TempValue << RegSize);
- RegSize = RegSize + 8;
- }
- *(FindPointerToRegister (SystemContext, RegNumber)) = NewValue;
- return InBufPtr;
- }
- /** ‘P n...=r...’
- Writes the new value of n-th register received into the input buffer to the n-th register
- @param SystemContext Register content at time of the exception
- @param InBuffer Pointer to the input buffer received from gdb server
- **/
- VOID
- WriteNthRegister (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *InBuffer
- )
- {
- UINTN RegNumber;
- CHAR8 RegNumBuffer[MAX_REG_NUM_BUF_SIZE]; // put the 'n..' part of the message into this array
- CHAR8 *RegNumBufPtr;
- CHAR8 *InBufPtr; // pointer to the input buffer
- // find the register number to write
- InBufPtr = &InBuffer[1];
- RegNumBufPtr = RegNumBuffer;
- while (*InBufPtr != '=') {
- *RegNumBufPtr++ = *InBufPtr++;
- }
- *RegNumBufPtr = '\0';
- RegNumber = AsciiStrHexToUintn (RegNumBuffer);
- // check if this is a valid Register Number
- if (RegNumber >= MaxRegisterCount ()) {
- SendError (GDB_EINVALIDREGNUM);
- return;
- }
- InBufPtr++; // skips the '=' character
- BasicWriteRegister (SystemContext, RegNumber, InBufPtr);
- SendSuccess ();
- }
- /** ‘G XX...’
- Writes the new values received into the input buffer to the general registers
- @param SystemContext Register content at time of the exception
- @param InBuffer Pointer to the input buffer received from gdb server
- **/
- VOID
- EFIAPI
- WriteGeneralRegisters (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *InBuffer
- )
- {
- UINTN i;
- CHAR8 *InBufPtr; /// pointer to the input buffer
- UINTN MinLength;
- UINTN RegisterCount = MaxRegisterCount ();
- MinLength = (RegisterCount * 8) + 1; // 'G' plus the registers in ASCII format
- if (AsciiStrLen (InBuffer) < MinLength) {
- // Bad message. Message is not the right length
- SendError (GDB_EBADBUFSIZE);
- return;
- }
- InBufPtr = &InBuffer[1];
- // Read the new values for the registers from the input buffer to an array, NewValueArray.
- // The values in the array are in the gdb ordering
- for (i = 0; i < RegisterCount; i++) {
- InBufPtr = BasicWriteRegister (SystemContext, i, InBufPtr);
- }
- SendSuccess ();
- }
- // What about Thumb?
- // Use SWI 0xdbdbdb as the debug instruction
- #define GDB_ARM_BKPT 0xefdbdbdb
- BOOLEAN mSingleStepActive = FALSE;
- UINT32 mSingleStepPC;
- UINT32 mSingleStepData;
- UINTN mSingleStepDataSize;
- typedef struct {
- LIST_ENTRY Link;
- UINT64 Signature;
- UINT32 Address;
- UINT32 Instruction;
- } ARM_SOFTWARE_BREAKPOINT;
- #define ARM_SOFTWARE_BREAKPOINT_SIGNATURE SIGNATURE_64('A', 'R', 'M', 'B', 'R', 'K', 'P', 'T')
- #define ARM_SOFTWARE_BREAKPOINT_FROM_LINK(a) CR(a, ARM_SOFTWARE_BREAKPOINT, Link, ARM_SOFTWARE_BREAKPOINT_SIGNATURE)
- LIST_ENTRY BreakpointList;
- /**
- Insert Single Step in the SystemContext
- @param SystemContext Register content at time of the exception
- **/
- VOID
- AddSingleStep (
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- if (mSingleStepActive) {
- // Currently don't support nesting
- return;
- }
- mSingleStepActive = TRUE;
- mSingleStepPC = SystemContext.SystemContextArm->PC;
- mSingleStepDataSize = sizeof (UINT32);
- mSingleStepData = (*(UINT32 *)mSingleStepPC);
- *(UINT32 *)mSingleStepPC = GDB_ARM_BKPT;
- if (*(UINT32 *)mSingleStepPC != GDB_ARM_BKPT) {
- // For some reason our breakpoint did not take
- mSingleStepActive = FALSE;
- }
- InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
- // DEBUG((DEBUG_ERROR, "AddSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, mSingleStepData, *(UINT32 *)mSingleStepPC));
- }
- /**
- Remove Single Step in the SystemContext
- @param SystemContext Register content at time of the exception
- **/
- VOID
- RemoveSingleStep (
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- if (!mSingleStepActive) {
- return;
- }
- if (mSingleStepDataSize == sizeof (UINT16)) {
- *(UINT16 *)mSingleStepPC = (UINT16)mSingleStepData;
- } else {
- // DEBUG((DEBUG_ERROR, "RemoveSingleStep at 0x%08x (was: 0x%08x is:0x%08x)\n", SystemContext.SystemContextArm->PC, *(UINT32 *)mSingleStepPC, mSingleStepData));
- *(UINT32 *)mSingleStepPC = mSingleStepData;
- }
- InvalidateInstructionCacheRange ((VOID *)mSingleStepPC, mSingleStepDataSize);
- mSingleStepActive = FALSE;
- }
- /**
- Continue. addr is Address to resume. If addr is omitted, resume at current
- Address.
- @param SystemContext Register content at time of the exception
- **/
- VOID
- EFIAPI
- ContinueAtAddress (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *PacketData
- )
- {
- if (PacketData[1] != '\0') {
- SystemContext.SystemContextArm->PC = AsciiStrHexToUintn (&PacketData[1]);
- }
- }
- /** ‘s [addr ]’
- Single step. addr is the Address at which to resume. If addr is omitted, resume
- at same Address.
- @param SystemContext Register content at time of the exception
- **/
- VOID
- EFIAPI
- SingleStep (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *PacketData
- )
- {
- SendNotSupported ();
- }
- UINTN
- GetBreakpointDataAddress (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN UINTN BreakpointNumber
- )
- {
- return 0;
- }
- UINTN
- GetBreakpointDetected (
- IN EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- return 0;
- }
- BREAK_TYPE
- GetBreakpointType (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN UINTN BreakpointNumber
- )
- {
- return NotSupported;
- }
- ARM_SOFTWARE_BREAKPOINT *
- SearchBreakpointList (
- IN UINT32 Address
- )
- {
- LIST_ENTRY *Current;
- ARM_SOFTWARE_BREAKPOINT *Breakpoint;
- Current = GetFirstNode (&BreakpointList);
- while (!IsNull (&BreakpointList, Current)) {
- Breakpoint = ARM_SOFTWARE_BREAKPOINT_FROM_LINK (Current);
- if (Address == Breakpoint->Address) {
- return Breakpoint;
- }
- Current = GetNextNode (&BreakpointList, Current);
- }
- return NULL;
- }
- VOID
- SetBreakpoint (
- IN UINT32 Address
- )
- {
- ARM_SOFTWARE_BREAKPOINT *Breakpoint;
- Breakpoint = SearchBreakpointList (Address);
- if (Breakpoint != NULL) {
- return;
- }
- // create and fill breakpoint structure
- Breakpoint = AllocatePool (sizeof (ARM_SOFTWARE_BREAKPOINT));
- Breakpoint->Signature = ARM_SOFTWARE_BREAKPOINT_SIGNATURE;
- Breakpoint->Address = Address;
- Breakpoint->Instruction = *(UINT32 *)Address;
- // Add it to the list
- InsertTailList (&BreakpointList, &Breakpoint->Link);
- // Insert the software breakpoint
- *(UINT32 *)Address = GDB_ARM_BKPT;
- InvalidateInstructionCacheRange ((VOID *)Address, 4);
- // DEBUG((DEBUG_ERROR, "SetBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, Breakpoint->Instruction, *(UINT32 *)Address));
- }
- VOID
- ClearBreakpoint (
- IN UINT32 Address
- )
- {
- ARM_SOFTWARE_BREAKPOINT *Breakpoint;
- Breakpoint = SearchBreakpointList (Address);
- if (Breakpoint == NULL) {
- return;
- }
- // Add it to the list
- RemoveEntryList (&Breakpoint->Link);
- // Restore the original instruction
- *(UINT32 *)Address = Breakpoint->Instruction;
- InvalidateInstructionCacheRange ((VOID *)Address, 4);
- // DEBUG((DEBUG_ERROR, "ClearBreakpoint at 0x%08x (was: 0x%08x is:0x%08x)\n", Address, GDB_ARM_BKPT, *(UINT32 *)Address));
- FreePool (Breakpoint);
- }
- VOID
- EFIAPI
- InsertBreakPoint (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *PacketData
- )
- {
- UINTN Type;
- UINTN Address;
- UINTN Length;
- UINTN ErrorCode;
- ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
- if (ErrorCode > 0) {
- SendError ((UINT8)ErrorCode);
- return;
- }
- switch (Type) {
- case 0: // Software breakpoint
- break;
- default:
- DEBUG ((DEBUG_ERROR, "Insert breakpoint default: %x\n", Type));
- SendError (GDB_EINVALIDBRKPOINTTYPE);
- return;
- }
- SetBreakpoint (Address);
- SendSuccess ();
- }
- VOID
- EFIAPI
- RemoveBreakPoint (
- IN EFI_SYSTEM_CONTEXT SystemContext,
- IN CHAR8 *PacketData
- )
- {
- UINTN Type;
- UINTN Address;
- UINTN Length;
- UINTN ErrorCode;
- // Parse breakpoint packet data
- ErrorCode = ParseBreakpointPacket (PacketData, &Type, &Address, &Length);
- if (ErrorCode > 0) {
- SendError ((UINT8)ErrorCode);
- return;
- }
- switch (Type) {
- case 0: // Software breakpoint
- break;
- default:
- SendError (GDB_EINVALIDBRKPOINTTYPE);
- return;
- }
- ClearBreakpoint (Address);
- SendSuccess ();
- }
- VOID
- InitializeProcessor (
- VOID
- )
- {
- // Initialize breakpoint list
- InitializeListHead (&BreakpointList);
- }
- BOOLEAN
- ValidateAddress (
- IN VOID *Address
- )
- {
- if ((UINT32)Address < 0x80000000) {
- return FALSE;
- } else {
- return TRUE;
- }
- }
- BOOLEAN
- ValidateException (
- IN EFI_EXCEPTION_TYPE ExceptionType,
- IN OUT EFI_SYSTEM_CONTEXT SystemContext
- )
- {
- UINT32 ExceptionAddress;
- UINT32 Instruction;
- // Is it a debugger SWI?
- ExceptionAddress = SystemContext.SystemContextArm->PC -= 4;
- Instruction = *(UINT32 *)ExceptionAddress;
- if (Instruction != GDB_ARM_BKPT) {
- return FALSE;
- }
- // Special for SWI-based exception handling. SWI sets up the context
- // to return to the instruction following the SWI instruction - NOT what we want
- // for a debugger!
- SystemContext.SystemContextArm->PC = ExceptionAddress;
- return TRUE;
- }
|