| /** @file |
| Private include file for GDB stub |
| |
| Copyright (c) 2008-2009 Apple Inc. All rights reserved.<BR> |
| |
| 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 __GDB_STUB_INTERNAL__ |
| #define __GDB_STUB_INTERNAL__ |
| |
| #include <Uefi.h> |
| #include <Library/BaseLib.h> |
| #include <Library/BaseMemoryLib.h> |
| #include <Library/MemoryAllocationLib.h> |
| #include <Library/DebugLib.h> |
| #include <Library/UefiLib.h> |
| #include <Library/UefiBootServicesTableLib.h> |
| #include <Library/PcdLib.h> |
| #include <Library/GdbSerialLib.h> |
| #include <Library/PrintLib.h> |
| |
| #include <Protocol/DebugSupport.h> |
| #include <Protocol/SerialIo.h> |
| #include <Protocol/LoadedImage.h> |
| #include <Protocol/LoadedImage.h> |
| #include <Guid/DebugImageInfoTable.h> |
| #include <IndustryStandard/PeImage.h> |
| |
| extern CONST CHAR8 mHexToStr[]; |
| |
| // maximum size of input and output buffers |
| // This value came from the show remote command of the gdb we tested against |
| #define MAX_BUF_SIZE 2000 |
| |
| // maximum size of address buffer |
| #define MAX_ADDR_SIZE 32 |
| |
| // maximum size of register number buffer |
| #define MAX_REG_NUM_BUF_SIZE 32 |
| |
| // maximum size of length buffer |
| #define MAX_LENGTH_SIZE 32 |
| |
| // maximum size of T signal members |
| #define MAX_T_SIGNAL_SIZE 64 |
| |
| // the mask used to clear all the cache |
| #define TF_BIT 0x00000100 |
| |
| |
| // |
| // GDB Signal definitions - generic names for interrupts |
| // |
| #define GDB_SIGILL 4 // Illegal instruction |
| #define GDB_SIGTRAP 5 // Trace Trap (Breakpoint and SingleStep) |
| #define GDB_SIGEMT 7 // Emulator Trap |
| #define GDB_SIGFPE 8 // Floating point exception |
| #define GDB_SIGSEGV 11 // Setgment violation, page fault |
| |
| |
| // |
| // GDB File I/O Error values, zero means no error |
| // Includes all general GDB Unix like error values |
| // |
| #define GDB_EBADMEMADDRBUFSIZE 11 // the buffer that stores memory Address to be read from/written to is not the right size |
| #define GDB_EBADMEMLENGBUFSIZE 12 // the buffer that stores Length is not the right size |
| #define GDB_EBADMEMLENGTH 13 // Length, the given number of bytes to read or write, is not the right size |
| #define GDB_EBADMEMDATA 14 // one of the bytes or nibbles of the memory is leess than 0 |
| #define GDB_EBADMEMDATASIZE 15 // the memory data, 'XX..', is too short or too long |
| #define GDB_EBADBUFSIZE 21 // the buffer created is not the correct size |
| #define GDB_EINVALIDARG 31 // argument is invalid |
| #define GDB_ENOSPACE 41 // |
| #define GDB_EINVALIDBRKPOINTTYPE 51 // the breakpoint type is not recognized |
| #define GDB_EINVALIDREGNUM 61 // given register number is not valid: either <0 or >=Number of Registers |
| #define GDB_EUNKNOWN 255 // unknown |
| |
| |
| // |
| // These devices are open by GDB so we can just read and write to them |
| // |
| #define GDB_STDIN 0x00 |
| #define GDB_STDOUT 0x01 |
| #define GDB_STDERR 0x02 |
| |
| // |
| //Define Register size for different architectures |
| // |
| #if defined (MDE_CPU_IA32) |
| #define REG_SIZE 32 |
| #elif defined (MDE_CPU_X64) |
| #define REG_SIZE 64 |
| #elif defined (MDE_CPU_ARM) |
| #define REG_SIZE 32 |
| #endif |
| |
| #define GDB_SERIAL_DEV_SIGNATURE SIGNATURE_32 ('g', 'd', 'b', 's') |
| |
| typedef struct { |
| VENDOR_DEVICE_PATH VendorDevice; |
| UINT32 Index; // Suport more than one |
| EFI_DEVICE_PATH_PROTOCOL End; |
| } GDB_SERIAL_DEVICE_PATH; |
| |
| // |
| // Name: SERIAL_DEV |
| // Purpose: To provide device specific information |
| // Fields: |
| // Signature UINTN: The identity of the serial device |
| // SerialIo SERIAL_IO_PROTOCOL: Serial I/O protocol interface |
| // SerialMode SERIAL_IO_MODE: |
| // DevicePath EFI_DEVICE_PATH_PROTOCOL *: Device path of the serial device |
| // |
| typedef struct { |
| UINTN Signature; |
| EFI_HANDLE Handle; |
| EFI_SERIAL_IO_PROTOCOL SerialIo; |
| EFI_SERIAL_IO_MODE SerialMode; |
| GDB_SERIAL_DEVICE_PATH DevicePath; |
| INTN InFileDescriptor; |
| INTN OutFileDescriptor; |
| } GDB_SERIAL_DEV; |
| |
| |
| #define GDB_SERIAL_DEV_FROM_THIS(a) CR (a, GDB_SERIAL_DEV, SerialIo, GDB_SERIAL_DEV_SIGNATURE) |
| |
| |
| typedef struct { |
| EFI_EXCEPTION_TYPE Exception; |
| UINT8 SignalNo; |
| } EFI_EXCEPTION_TYPE_ENTRY; |
| |
| |
| #if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) |
| |
| // |
| // Byte packed structure for DR6 |
| // 32-bits on IA-32 |
| // 64-bits on X64. The upper 32-bits on X64 are reserved |
| // |
| typedef union { |
| struct { |
| UINT32 B0:1; // Breakpoint condition detected |
| UINT32 B1:1; // Breakpoint condition detected |
| UINT32 B2:1; // Breakpoint condition detected |
| UINT32 B3:1; // Breakpoint condition detected |
| UINT32 Reserved_1:9; // Reserved |
| UINT32 BD:1; // Debug register access detected |
| UINT32 BS:1; // Single step |
| UINT32 BT:1; // Task switch |
| UINT32 Reserved_2:16; // Reserved |
| } Bits; |
| UINTN UintN; |
| } IA32_DR6; |
| |
| // |
| // Byte packed structure for DR7 |
| // 32-bits on IA-32 |
| // 64-bits on X64. The upper 32-bits on X64 are reserved |
| // |
| typedef union { |
| struct { |
| UINT32 L0:1; // Local breakpoint enable |
| UINT32 G0:1; // Global breakpoint enable |
| UINT32 L1:1; // Local breakpoint enable |
| UINT32 G1:1; // Global breakpoint enable |
| UINT32 L2:1; // Local breakpoint enable |
| UINT32 G2:1; // Global breakpoint enable |
| UINT32 L3:1; // Local breakpoint enable |
| UINT32 G3:1; // Global breakpoint enable |
| UINT32 LE:1; // Local exact breakpoint enable |
| UINT32 GE:1; // Global exact breakpoint enable |
| UINT32 Reserved_1:3; // Reserved |
| UINT32 GD:1; // Global detect enable |
| UINT32 Reserved_2:2; // Reserved |
| UINT32 RW0:2; // Read/Write field |
| UINT32 LEN0:2; // Length field |
| UINT32 RW1:2; // Read/Write field |
| UINT32 LEN1:2; // Length field |
| UINT32 RW2:2; // Read/Write field |
| UINT32 LEN2:2; // Length field |
| UINT32 RW3:2; // Read/Write field |
| UINT32 LEN3:2; // Length field |
| } Bits; |
| UINTN UintN; |
| } IA32_DR7; |
| |
| #endif /* if defined (MDE_CPU_IA32) || defined (MDE_CPU_X64) */ |
| |
| typedef enum { |
| InstructionExecution, //Hardware breakpoint |
| DataWrite, //watch |
| DataRead, //rwatch |
| DataReadWrite, //awatch |
| SoftwareBreakpoint, //Software breakpoint |
| NotSupported |
| } BREAK_TYPE; |
| |
| // |
| // Array of exception types that need to be hooked by the debugger |
| // |
| extern EFI_EXCEPTION_TYPE_ENTRY gExceptionType[]; |
| |
| // |
| // Set TRUE if F Reply package signals a ctrl-c. We can not process the Ctrl-c |
| // here we need to wait for the periodic callback to do this. |
| // |
| extern BOOLEAN gCtrlCBreakFlag; |
| |
| // |
| // If the periodic callback is called while we are processing an F packet we need |
| // to let the callback know to not read from the serail stream as it could steal |
| // characters from the F reponse packet |
| // |
| extern BOOLEAN gProcessingFPacket; |
| |
| |
| // The offsets of registers SystemContext. |
| // The fields in the array are in the gdb ordering. |
| // |
| extern UINTN gRegisterOffsets[]; |
| |
| /** |
| Return the number of entries in the gExceptionType[] |
| |
| @retval UINTN, the number of entries in the gExceptionType[] array. |
| **/ |
| UINTN |
| MaxEfiException ( |
| VOID |
| ); |
| |
| |
| /** |
| Return the number of entries in the gRegisters[] |
| |
| @retval UINTN, the number of entries (registers) in the gRegisters[] array. |
| **/ |
| UINTN |
| MaxRegisterCount ( |
| VOID |
| ); |
| |
| |
| /** |
| Check to see if the ISA is supported. |
| ISA = Instruction Set Architecture |
| |
| @retval TRUE if Isa is supported, |
| FALSE otherwise. |
| **/ |
| BOOLEAN |
| CheckIsa ( |
| IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa |
| ); |
| |
| |
| /** |
| Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints |
| |
| @param SystemContext Register content at time of the exception |
| @param GdbExceptionType GDB exception type |
| **/ |
| |
| VOID |
| GdbSendTSignal ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINT8 GdbExceptionType |
| ); |
| |
| |
| /** |
| Translates the EFI mapping to GDB mapping |
| |
| @param EFIExceptionType EFI Exception that is being processed |
| @retval UINTN that corresponds to EFIExceptionType's GDB exception type number |
| **/ |
| UINT8 |
| ConvertEFItoGDBtype ( |
| IN EFI_EXCEPTION_TYPE EFIExceptionType |
| ); |
| |
| |
| /** |
| Empties the given buffer |
| @param *Buf pointer to the first element in buffer to be emptied |
| **/ |
| VOID |
| EmptyBuffer ( |
| IN CHAR8 *Buf |
| ); |
| |
| |
| /** |
| Converts an 8-bit Hex Char into a INTN. |
| |
| @param Char - the hex character to be converted into UINTN |
| @retval a INTN, from 0 to 15, that corressponds to Char |
| -1 if Char is not a hex character |
| **/ |
| INTN |
| HexCharToInt ( |
| IN CHAR8 Char |
| ); |
| |
| |
| /** 'E NN' |
| Send an error with the given error number after converting to hex. |
| The error number is put into the buffer in hex. '255' is the biggest errno we can send. |
| ex: 162 will be sent as A2. |
| |
| @param errno the error number that will be sent |
| **/ |
| VOID |
| EFIAPI |
| SendError ( |
| IN UINT8 ErrorNum |
| ); |
| |
| |
| /** |
| Send 'OK' when the function is done executing successfully. |
| **/ |
| VOID |
| SendSuccess ( |
| VOID |
| ); |
| |
| |
| /** |
| Send empty packet to specify that particular command/functionality is not supported. |
| **/ |
| VOID |
| SendNotSupported ( |
| VOID |
| ); |
| |
| /** ‘p n’ |
| 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 This is the input buffer received from gdb server |
| **/ |
| VOID |
| ReadNthRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *InBuffer |
| ); |
| |
| |
| /** ‘g’ |
| Reads the general registers into an output buffer and sends it as a packet |
| @param SystemContext Register content at time of the exception |
| **/ |
| VOID |
| ReadGeneralRegisters ( |
| IN EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| |
| /** ‘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 This is the input buffer received from gdb server |
| **/ |
| VOID |
| WriteNthRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *InBuffer |
| ); |
| |
| |
| /** ‘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 |
| WriteGeneralRegisters ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *InBuffer |
| ); |
| |
| |
| /** ‘m addr,length ’ |
| Find the Length of the area to read and the start addres. Finally, pass them to |
| another function, TransferFromMemToOutBufAndSend, that will read from that memory space and |
| send it as a packet. |
| |
| @param *PacketData Pointer to Payload data for the packet |
| **/ |
| VOID |
| ReadFromMemory ( |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** ‘M addr,length :XX...’ |
| Find the Length of the area in bytes to write and the start addres. Finally, pass them to |
| another function, TransferFromInBufToMem, that will write to that memory space the info in |
| the input buffer. |
| |
| @param PacketData Pointer to Payload data for the packet |
| **/ |
| VOID |
| WriteToMemory ( |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** ‘c [addr ]’ |
| Continue. addr is Address to resume. If addr is omitted, resume at current |
| Address. |
| |
| @param SystemContext Register content at time of the exception |
| @param *PacketData Pointer to PacketData |
| **/ |
| |
| VOID |
| ContinueAtAddress ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** ‘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 |
| @param PacketData Pointer to Payload data for the packet |
| **/ |
| VOID |
| SingleStep ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *PacketData |
| ); |
| |
| /** |
| Insert Single Step in the SystemContext |
| |
| @param SystemContext Register content at time of the exception |
| **/ |
| VOID |
| AddSingleStep ( |
| IN EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| /** |
| Remove Single Step in the SystemContext |
| |
| @param SystemContext Register content at time of the exception |
| **/ |
| VOID |
| RemoveSingleStep ( |
| IN EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| |
| /** |
| ‘Z1, [addr], [length]’ |
| ‘Z2, [addr], [length]’ |
| ‘Z3, [addr], [length]’ |
| ‘Z4, [addr], [length]’ |
| |
| Insert hardware breakpoint/watchpoint at address addr of size length |
| |
| @param SystemContext Register content at time of the exception |
| @param *PacketData Pointer to the Payload data for the packet |
| |
| **/ |
| VOID |
| EFIAPI |
| InsertBreakPoint( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** |
| ‘z1, [addr], [length]’ |
| ‘z2, [addr], [length]’ |
| ‘z3, [addr], [length]’ |
| ‘z4, [addr], [length]’ |
| |
| Remove hardware breakpoint/watchpoint at address addr of size length |
| |
| @param SystemContext Register content at time of the exception |
| @param *PacketData Pointer to the Payload data for the packet |
| |
| **/ |
| VOID |
| EFIAPI |
| RemoveBreakPoint( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** |
| Exception Hanldler for GDB. It will be called for all exceptions |
| registered via the gExceptionType[] array. |
| |
| @param ExceptionType Exception that is being processed |
| @param SystemContext Register content at time of the exception |
| |
| **/ |
| VOID |
| EFIAPI |
| GdbExceptionHandler ( |
| IN EFI_EXCEPTION_TYPE ExceptionType, |
| IN OUT EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| |
| /** |
| Periodic callback for GDB. This function is used to catch a ctrl-c or other |
| break in type command from GDB. |
| |
| @param SystemContext Register content at time of the call |
| |
| **/ |
| VOID |
| EFIAPI |
| GdbPeriodicCallBack ( |
| IN OUT EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| |
| /** |
| Make two serail consoles: 1) StdIn and StdOut via GDB. 2) StdErr via GDB. |
| |
| These console show up on the remote system running GDB |
| |
| **/ |
| |
| VOID |
| GdbInitializeSerialConsole ( |
| VOID |
| ); |
| |
| |
| /** |
| Send a GDB Remote Serial Protocol Packet |
| |
| $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', |
| the packet teminating character '#' and the two digit checksum. |
| |
| If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up |
| in an infinit loop. This is so if you unplug the debugger code just keeps running |
| |
| @param PacketData Payload data for the packet |
| |
| @retval Number of bytes of packet data sent. |
| |
| **/ |
| UINTN |
| SendPacket ( |
| IN CHAR8 *PacketData |
| ); |
| |
| |
| /** |
| Receive a GDB Remote Serial Protocol Packet |
| |
| $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$', |
| the packet teminating character '#' and the two digit checksum. |
| |
| If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed. |
| (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.) |
| |
| If an ack '+' is not sent resend the packet |
| |
| @param PacketData Payload data for the packet |
| |
| @retval Number of bytes of packet data received. |
| |
| **/ |
| UINTN |
| ReceivePacket ( |
| OUT CHAR8 *PacketData, |
| IN UINTN PacketDataSize |
| ); |
| |
| |
| /** |
| Read data from a FileDescriptor. On success number of bytes read is returned. Zero indicates |
| the end of a file. On error -1 is returned. If count is zero, GdbRead returns zero. |
| |
| @param FileDescriptor Device to talk to. |
| @param Buffer Buffer to hold Count bytes that were read |
| @param Count Number of bytes to transfer. |
| |
| @retval -1 Error |
| @retval {other} Number of bytes read. |
| |
| **/ |
| INTN |
| GdbRead ( |
| IN INTN FileDescriptor, |
| OUT VOID *Buffer, |
| IN UINTN Count |
| ); |
| |
| |
| /** |
| Write data to a FileDescriptor. On success number of bytes written is returned. Zero indicates |
| nothing was written. On error -1 is returned. |
| |
| @param FileDescriptor Device to talk to. |
| @param Buffer Buffer to hold Count bytes that are to be written |
| @param Count Number of bytes to transfer. |
| |
| @retval -1 Error |
| @retval {other} Number of bytes written. |
| |
| **/ |
| INTN |
| GdbWrite ( |
| IN INTN FileDescriptor, |
| OUT CONST VOID *Buffer, |
| IN UINTN Count |
| ); |
| |
| UINTN * |
| FindPointerToRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN RegNumber |
| ); |
| |
| CHAR8 * |
| BasicReadRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN RegNumber, |
| IN CHAR8 *OutBufPtr |
| ); |
| |
| VOID |
| TransferFromInBufToMem ( |
| IN UINTN Length, |
| IN UINT8 *Address, |
| IN CHAR8 *NewData |
| ); |
| |
| VOID |
| TransferFromMemToOutBufAndSend ( |
| IN UINTN Length, |
| IN UINT8 *Address |
| ); |
| |
| CHAR8 * |
| BasicWriteRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN RegNumber, |
| IN CHAR8 *InBufPtr |
| ); |
| |
| VOID |
| PrintReg ( |
| EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| UINTN |
| ParseBreakpointPacket ( |
| IN CHAR8 *PacketData, |
| OUT UINTN *Type, |
| OUT UINTN *Address, |
| OUT UINTN *Length |
| ); |
| |
| UINTN |
| GetBreakpointDataAddress ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN BreakpointNumber |
| ); |
| |
| UINTN |
| GetBreakpointDetected ( |
| IN EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| BREAK_TYPE |
| GetBreakpointType ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN BreakpointNumber |
| ); |
| |
| UINTN |
| ConvertLengthData ( |
| IN UINTN Length |
| ); |
| |
| EFI_STATUS |
| FindNextFreeDebugRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| OUT UINTN *Register |
| ); |
| |
| EFI_STATUS |
| EnableDebugRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN Register, |
| IN UINTN Address, |
| IN UINTN Length, |
| IN UINTN Type |
| ); |
| |
| EFI_STATUS |
| FindMatchingDebugRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN Address, |
| IN UINTN Length, |
| IN UINTN Type, |
| OUT UINTN *Register |
| ); |
| |
| EFI_STATUS |
| DisableDebugRegister ( |
| IN EFI_SYSTEM_CONTEXT SystemContext, |
| IN UINTN Register |
| ); |
| |
| VOID |
| InitializeProcessor ( |
| VOID |
| ); |
| |
| BOOLEAN |
| ValidateAddress ( |
| IN VOID *Address |
| ); |
| |
| BOOLEAN |
| ValidateException ( |
| IN EFI_EXCEPTION_TYPE ExceptionType, |
| IN OUT EFI_SYSTEM_CONTEXT SystemContext |
| ); |
| |
| #endif |