X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=EmbeddedPkg%2FLibrary%2FGdbDebugAgent%2FGdbDebugAgent.c;fp=EmbeddedPkg%2FLibrary%2FGdbDebugAgent%2FGdbDebugAgent.c;h=0000000000000000000000000000000000000000;hp=80aa4765c0ef768c48d28c96e4415c863caee088;hb=3bdc111178e11a9a9a3e77cad3f8d61122557d46;hpb=5f0b035f107d51a75de836345fd4b403d066a209 diff --git a/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c b/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c deleted file mode 100644 index 80aa4765c0..0000000000 --- a/EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c +++ /dev/null @@ -1,815 +0,0 @@ -/** @file - Debug Agent library implementition with empty functions. - - Copyright (c) 2010, Intel Corporation. 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 "GdbDebugAgent.h" - - -UINTN gMaxProcessorIndex = 0; - -// -// Buffers for basic gdb communication -// -CHAR8 gInBuffer[MAX_BUF_SIZE]; -CHAR8 gOutBuffer[MAX_BUF_SIZE]; - - -// -// Globals for returning XML from qXfer:libraries:read packet -// -UINTN gPacketqXferLibraryOffset = 0; -UINTN gEfiDebugImageTableEntry = 0; -CHAR8 gXferLibraryBuffer[2000]; - -GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; - - -// add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360 -CHAR8 *qXferHack = ""; - -UINTN -gXferObjectReadResponse ( - IN CHAR8 Type, - IN CHAR8 *Str - ) -{ - CHAR8 *OutBufPtr; // pointer to the output buffer - CHAR8 Char; - UINTN Count; - - // responce starts with 'm' or 'l' if it is the end - OutBufPtr = gOutBuffer; - *OutBufPtr++ = Type; - Count = 1; - - // Binary data encoding - OutBufPtr = gOutBuffer; - while (*Str != '\0') { - Char = *Str++; - if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) { - // escape character - *OutBufPtr++ = 0x7d; - - Char ^= 0x20; - } - *OutBufPtr++ = Char; - Count++; - } - - *OutBufPtr = '\0' ; // the end of the buffer - SendPacket (gOutBuffer); - - return Count; -} - -/** - Process "qXfer:object:read:annex:offset,length" request. - - Returns an XML document that contains loaded libraries. In our case it is - infomration in the EFI Debug Inmage Table converted into an XML document. - - GDB will call with an arbitrary length (it can't know the real length and - will reply with chunks of XML that are easy for us to deal with. Gdb will - keep calling until we say we are done. XML doc looks like: - - - - - - - - Since we can not allocate memory in interupt context this module has - assumptions about how it will get called: - 1) Length will generally be max remote packet size (big enough) - 2) First Offset of an XML document read needs to be 0 - 3) This code will return back small chunks of the XML document on every read. - Each subseqent call will ask for the next available part of the document. - - Note: The only variable size element in the XML is: - " \n" and it is - based on the file path and name of the symbol file. If the symbol file name - is bigger than the max gdb remote packet size we could update this code - to respond back in chunks. - - @param Offset offset into special data area - @param Length number of bytes to read starting at Offset - - **/ -VOID -QxferLibrary ( - IN UINTN Offset, - IN UINTN Length - ) -{ - gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "\n"); - gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', qXferHack); - gXferObjectReadResponse ('l', "\n"); - gPacketqXferLibraryOffset = 0; -} - -/** - Transfer length bytes of input buffer, starting at Address, to memory. - - @param length the number of the bytes to be transferred/written - @param *address the start address of the transferring/writing the memory - @param *new_data the new data to be written to memory - **/ - -VOID -TransferFromInBufToMem ( - IN UINTN Length, - IN unsigned char *Address, - IN CHAR8 *NewData - ) -{ - CHAR8 c1; - CHAR8 c2; - - while (Length-- > 0) { - c1 = (CHAR8)HexCharToInt (*NewData++); - c2 = (CHAR8)HexCharToInt (*NewData++); - - if ((c1 < 0) || (c2 < 0)) { - SendError (GDB_EBADMEMDATA); - return; - } - *Address++ = (UINT8)((c1 << 4) + c2); - } - - SendSuccess(); -} - - -/** - Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer - as a packet. - - @param Length the number of the bytes to be transferred/read - @param *address pointer to the start address of the transferring/reading the memory - **/ - -VOID -TransferFromMemToOutBufAndSend ( - IN UINTN Length, - IN unsigned char *Address - ) -{ - // there are Length bytes and every byte is represented as 2 hex chars - CHAR8 OutBuffer[MAX_BUF_SIZE]; - CHAR8 *OutBufPtr; // pointer to the output buffer - CHAR8 Char; - - OutBufPtr = OutBuffer; - while (Length > 0) { - - Char = mHexToStr[*Address >> 4]; - if ((Char >= 'A') && (Char <= 'F')) { - Char = Char - 'A' + 'a'; - } - *OutBufPtr++ = Char; - - Char = mHexToStr[*Address & 0x0f]; - if ((Char >= 'A') && (Char <= 'F')) { - Char = Char - 'A' + 'a'; - } - *OutBufPtr++ = Char; - - Address++; - Length--; - } - - *OutBufPtr = '\0' ; // the end of the buffer - SendPacket (OutBuffer); -} - - - -/** - 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 - ) -{ - UINT8 CheckSum; - UINTN Timeout; - CHAR8 *Ptr; - CHAR8 TestChar; - UINTN Count; - - Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount); - - Count = 0; - do { - - Ptr = PacketData; - - if (Timeout-- == 0) { - // Only try a finite number of times so we don't get stuck in the loop - return Count; - } - - // Packet prefix - GdbPutChar ('$'); - - for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) { - GdbPutChar (*Ptr); - CheckSum = CheckSum + *Ptr; - } - - // Packet terminating character and checksum - GdbPutChar ('#'); - GdbPutChar (mHexToStr[CheckSum >> 4]); - GdbPutChar (mHexToStr[CheckSum & 0x0F]); - - TestChar = GdbGetChar (); - } while (TestChar != '+'); - - return Count; -} - -/** - 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 processed. - (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 - ) -{ - UINT8 CheckSum; - UINTN Index; - CHAR8 Char; - CHAR8 SumString[3]; - CHAR8 TestChar; - - ZeroMem (PacketData, PacketDataSize); - - for (;;) { - // wait for the start of a packet - TestChar = GdbGetChar (); - while (TestChar != '$') { - TestChar = GdbGetChar (); - }; - - retry: - for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) { - Char = GdbGetChar (); - if (Char == '$') { - goto retry; - } - if (Char == '#') { - break; - } - - PacketData[Index] = Char; - CheckSum = CheckSum + Char; - } - PacketData[Index] = '\0'; - - if (Index == PacketDataSize) { - continue; - } - - SumString[0] = GdbGetChar (); - SumString[1] = GdbGetChar (); - SumString[2] = '\0'; - - if (AsciiStrHexToUintn (SumString) == CheckSum) { - // Ack: Success - GdbPutChar ('+'); - - // Null terminate the callers string - PacketData[Index] = '\0'; - return Index; - } else { - // Ack: Failure - GdbPutChar ('-'); - } - } - - //return 0; -} - - -/** - Empties the given buffer - @param Buf pointer to the first element in buffer to be emptied - **/ -VOID -EmptyBuffer ( - IN CHAR8 *Buf - ) -{ - *Buf = '\0'; -} - - -/** - 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 - ) -{ - if ((Char >= 'A') && (Char <= 'F')) { - return Char - 'A' + 10; - } else if ((Char >= 'a') && (Char <= 'f')) { - return Char - 'a' + 10; - } else if ((Char >= '0') && (Char <= '9')) { - return Char - '0'; - } else { // if not a hex value, return a negative value - return -1; - } -} - - // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end -CHAR8 *gError = "E__"; - -/** '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 - ) -{ - // - // Replace _, or old data, with current errno - // - gError[1] = mHexToStr [ErrorNum >> 4]; - gError[2] = mHexToStr [ErrorNum & 0x0f]; - - SendPacket (gError); // send buffer -} - - - -/** - Send 'OK' when the function is done executing successfully. - **/ -VOID -EFIAPI -SendSuccess ( - VOID - ) -{ - SendPacket ("OK"); // send buffer -} - - -/** - Send empty packet to specify that particular command/functionality is not supported. - **/ -VOID -EFIAPI -SendNotSupported ( - VOID - ) -{ - SendPacket (""); -} - - - - - -/** - 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 - ) -{ - UINTN i; - - for (i=0; i < MaxEfiException() ; i++) { - if (gExceptionType[i].Exception == EFIExceptionType) { - return gExceptionType[i].SignalNo; - } - } - return GDB_SIGTRAP; // this is a GDB trap -} - - -/** "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. - **/ - -VOID -EFIAPI -ReadFromMemory ( - CHAR8 *PacketData - ) -{ - UINTN Address; - UINTN Length; - CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars - CHAR8 *AddrBufPtr; // pointer to the address buffer - CHAR8 *InBufPtr; /// pointer to the input buffer - - AddrBufPtr = AddressBuffer; - InBufPtr = &PacketData[1]; - while (*InBufPtr != ',') { - *AddrBufPtr++ = *InBufPtr++; - } - *AddrBufPtr = '\0'; - - InBufPtr++; // this skips ',' in the buffer - - /* Error checking */ - if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) { - SendError (GDB_EBADMEMADDRBUFSIZE); - return; - } - - // 2 = 'm' + ',' - if (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - 2 >= MAX_LENGTH_SIZE) { - SendError (GDB_EBADMEMLENGTH); - return; - } - - Address = AsciiStrHexToUintn (AddressBuffer); - Length = AsciiStrHexToUintn (InBufPtr); - - TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address); -} - - -/** "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. - **/ -VOID -EFIAPI -WriteToMemory ( - IN CHAR8 *PacketData - ) -{ - UINTN Address; - UINTN Length; - UINTN MessageLength; - CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars - CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars - CHAR8 *AddrBufPtr; // pointer to the Address buffer - CHAR8 *LengthBufPtr; // pointer to the Length buffer - CHAR8 *InBufPtr; /// pointer to the input buffer - - AddrBufPtr = AddressBuffer; - LengthBufPtr = LengthBuffer; - InBufPtr = &PacketData[1]; - - while (*InBufPtr != ',') { - *AddrBufPtr++ = *InBufPtr++; - } - *AddrBufPtr = '\0'; - - InBufPtr++; // this skips ',' in the buffer - - while (*InBufPtr != ':') { - *LengthBufPtr++ = *InBufPtr++; - } - *LengthBufPtr = '\0'; - - InBufPtr++; // this skips ':' in the buffer - - Address = AsciiStrHexToUintn (AddressBuffer); - Length = AsciiStrHexToUintn (LengthBuffer); - - /* Error checking */ - - //Check if Address is not too long. - if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) { - SendError (GDB_EBADMEMADDRBUFSIZE); - return; - } - - //Check if message length is not too long - if (AsciiStrLen(LengthBuffer) >= MAX_LENGTH_SIZE) { - SendError (GDB_EBADMEMLENGBUFSIZE); - return; - } - - // Check if Message is not too long/short. - // 3 = 'M' + ',' + ':' - MessageLength = (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - AsciiStrLen(LengthBuffer) - 3); - if (MessageLength != (2*Length)) { - //Message too long/short. New data is not the right size. - SendError (GDB_EBADMEMDATASIZE); - return; - } - TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr); -} - -/** - Parses breakpoint packet data and captures Breakpoint type, Address and length. - In case of an error, function returns particular error code. Returning 0 meaning - no error. - - @param PacketData Pointer to the payload data for the packet. - @param Type Breakpoint type - @param Address Breakpoint address - @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte) - - @retval 1 Success - @retval {other} Particular error code - -**/ -UINTN -ParseBreakpointPacket ( - IN CHAR8 *PacketData, - OUT UINTN *Type, - OUT UINTN *Address, - OUT UINTN *Length - ) -{ - CHAR8 AddressBuffer[MAX_ADDR_SIZE]; - CHAR8 *AddressBufferPtr; - CHAR8 *PacketDataPtr; - - PacketDataPtr = &PacketData[1]; - AddressBufferPtr = AddressBuffer; - - *Type = AsciiStrHexToUintn (PacketDataPtr); - - //Breakpoint/watchpoint type should be between 0 to 4 - if (*Type > 4) { - return 22; //EINVAL: Invalid argument. - } - - //Skip ',' in the buffer. - while (*PacketDataPtr++ != ','); - - //Parse Address information - while (*PacketDataPtr != ',') { - *AddressBufferPtr++ = *PacketDataPtr++; - } - *AddressBufferPtr = '\0'; - - //Check if Address is not too long. - if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) { - return 40; //EMSGSIZE: Message size too long. - } - - *Address = AsciiStrHexToUintn (AddressBuffer); - - PacketDataPtr++; //This skips , in the buffer - - //Parse Length information - *Length = AsciiStrHexToUintn (PacketDataPtr); - - //Length should be 1, 2 or 4 bytes - if (*Length > 4) { - return 22; //EINVAL: Invalid argument - } - - return 0; //0 = No error -} - - - -/** - 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 - ) -{ - CHAR8 TSignalBuffer[128]; - CHAR8 *TSignalPtr; - - TSignalPtr = &TSignalBuffer[0]; - - //Construct TSignal packet - *TSignalPtr++ = 'T'; - - // - // replace _, or previous value, with Exception type - // - *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4]; - *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f]; - - ProcessorSendTSignal (SystemContext, GdbExceptionType, TSignalPtr, sizeof (TSignalBuffer) - 2); - - SendPacket (TSignalBuffer); -} - -VOID -GdbFWrite ( - IN UINTN Fd, - IN CHAR8 *Data, - IN UINTN DataSize - ) -{ - CHAR8 Buffer[128]; - - AsciiSPrint (Buffer, sizeof (Buffer), "Fwrite,%x,%x,%x", Fd, Data, DataSize); - SendPacket (Buffer); - - for( ; ; ) { - ReceivePacket (gInBuffer, MAX_BUF_SIZE); - - switch (gInBuffer[0]) { - case 'm': - ReadFromMemory (gInBuffer); - break; - - case 'M': - WriteToMemory (gInBuffer); - break; - - case 'F': - return; - } - } -} - - -VOID -GdbFPutString ( - IN CHAR8 *String - ) -{ - UINTN Len = AsciiStrSize (String); - - GdbFWrite (2, String, Len); -} - - -/** - 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 - ) -{ - UINT8 GdbExceptionType; - CHAR8 *Ptr; - - if (ProcessorControlC (ExceptionType, SystemContext)) { - // We tried to process a control C handler and there is nothing to do - return; - } - - GdbExceptionType = ConvertEFItoGDBtype (ExceptionType); - GdbSendTSignal (SystemContext, GdbExceptionType); - - for( ; ; ) { - ReceivePacket (gInBuffer, MAX_BUF_SIZE); - - switch (gInBuffer[0]) { - case '?': - GdbSendTSignal (SystemContext, GdbExceptionType); - break; - - case 'c': - ContinueAtAddress (SystemContext, gInBuffer); - return; - - case 'D': - // gdb wants to disconnect so return "OK" packet since. - SendSuccess (); - return; - - case 'g': - ReadGeneralRegisters (SystemContext); - break; - - case 'G': - WriteGeneralRegisters (SystemContext, gInBuffer); - break; - - case 'H': - //Return "OK" packet since we don't have more than one thread. - SendSuccess (); - break; - - case 'm': - ReadFromMemory (gInBuffer); - break; - - case 'M': - WriteToMemory (gInBuffer); - break; - - case 'P': - WriteNthRegister (SystemContext, gInBuffer); - break; - - // - // Still debugging this code. Not used in Darwin - // - case 'q': - // General Query Packets - if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) { - // return what we currently support, we don't parse what gdb suports - AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE); - SendPacket (gOutBuffer); - } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) { - // ‘qXfer:libraries:read::offset,length - // gInBuffer[22] is offset string, ++Ptr is length string’ - for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++); - - // Not sure if multi-radix support is required. Currently only support decimal - QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr)); - } else if (AsciiStrnCmp (gInBuffer, "qOffsets", 8) == 0) { - AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000"); - SendPacket (gOutBuffer); - } else if (AsciiStrnCmp (gInBuffer, "qAttached", 9) == 0) { - // remote server attached to an existing process - SendPacket ("1"); - } else { - //Send empty packet - SendNotSupported (); - } - break; - - case 's': - SingleStep (SystemContext, gInBuffer); - return; - - case 'z': - RemoveBreakPoint (SystemContext, gInBuffer); - break; - - case 'Z': - InsertBreakPoint (SystemContext, gInBuffer); - break; - - default: - //Send empty packet - SendNotSupported (); - break; - } - } -} - - - - -