]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EmbeddedPkg/GdbStub/GdbStub.c
ARM Packages: Replace tabs by spaces for indentation
[mirror_edk2.git] / EmbeddedPkg / GdbStub / GdbStub.c
index 742de505cad5127544320d3d5e7005b43c0f1c81..213038ad08c93f04a8a46472c8d1b8fb453db526 100644 (file)
-/** @file
-  UEFI driver that implements a GDB stub
-  
-  Note: Any code in the path of the Serial IO output can not call DEBUG as will
-  will blow out the stack. Serial IO calls DEBUG, debug calls Serail IO, ...
-  
-
-  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
-  
-  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 <GdbStubInternal.h>
-#include <Protocol/DebugPort.h>
-
-
-UINTN     gMaxProcessorIndex = 0;
-
-//
-// Buffers for basic gdb communication
-//
-CHAR8 gInBuffer[MAX_BUF_SIZE];
-CHAR8 gOutBuffer[MAX_BUF_SIZE];
-
-// Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default 
-// this value to FALSE. Since gdb can reconnect its self a global default is not good enough
-BOOLEAN   gSymbolTableUpdate = FALSE;
-EFI_EVENT gEvent;
-VOID      *gGdbSymbolEventHandlerRegistration = NULL;
-
-//
-// Globals for returning XML from qXfer:libraries:read packet
-//
-UINTN                             gPacketqXferLibraryOffset = 0;
-UINTN                             gEfiDebugImageTableEntry = 0;
-EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;
-EFI_DEBUG_IMAGE_INFO              *gDebugTable = NULL;
-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'};
-
-
-VOID
-EFIAPI
-GdbSymbolEventHandler (
-  IN  EFI_EVENT       Event,
-  IN  VOID            *Context
-  )
-{
-}
-
-
-/**
-  The user Entry Point for Application. The user code starts with this function
-  as the real entry point for the image goes into a library that calls this 
-  function.
-
-  @param[in] ImageHandle    The firmware allocated handle for the EFI image.  
-  @param[in] SystemTable    A pointer to the EFI System Table.
-  
-  @retval EFI_SUCCESS       The entry point is executed successfully.
-  @retval other             Some error occurs when executing this entry point.
-
-**/
-EFI_STATUS
-EFIAPI
-GdbStubEntry (
-  IN EFI_HANDLE        ImageHandle,
-  IN EFI_SYSTEM_TABLE  *SystemTable
-  )
-
-{
-  EFI_STATUS                  Status;  
-  EFI_DEBUG_SUPPORT_PROTOCOL  *DebugSupport;
-  UINTN                       HandleCount;
-  EFI_HANDLE                  *Handles;
-  UINTN                       Index;
-  UINTN                       Processor;
-  BOOLEAN                     IsaSupported;
-   
-  Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);
-  if (EFI_ERROR (Status)) {
-    gDebugImageTableHeader = NULL;
-  }
-
-  Status = gBS->LocateHandleBuffer (
-                  ByProtocol,
-                  &gEfiDebugSupportProtocolGuid,
-                  NULL,
-                  &HandleCount,
-                  &Handles
-                  );
-  if (EFI_ERROR (Status)) {
-    DEBUG ((EFI_D_ERROR, "Debug Support Protocol not found\n"));
-
-    return Status;
-  }
-  
-  DebugSupport = NULL;
-  IsaSupported = FALSE;
-  do {
-    HandleCount--;
-    Status = gBS->HandleProtocol (
-                    Handles[HandleCount],
-                    &gEfiDebugSupportProtocolGuid,
-                    (VOID **) &DebugSupport
-                    );
-    if (!EFI_ERROR (Status)) {
-      if (CheckIsa (DebugSupport->Isa)) {
-        // We found what we are looking for so break out of the loop
-        IsaSupported = TRUE;
-        break;
-      }
-    }
-  } while (HandleCount > 0);
-  FreePool (Handles);
-  
-  if (!IsaSupported) {
-    DEBUG ((EFI_D_ERROR, "Debug Support Protocol does not support our ISA\n"));
-
-    return EFI_NOT_FOUND;
-  }
-  
-  Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex);
-  ASSERT_EFI_ERROR (Status);
-  
-  DEBUG ((EFI_D_INFO, "Debug Support Protocol ISA %x\n", DebugSupport->Isa));
-  DEBUG ((EFI_D_INFO, "Debug Support Protocol Processor Index %d\n", gMaxProcessorIndex));
-  
-  // Call processor-specific init routine
-  InitializeProcessor();
-
-  for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) {
-    
-    for (Index = 0; Index < MaxEfiException (); Index++) {
-      Status = DebugSupport->RegisterExceptionCallback (DebugSupport, Processor,  GdbExceptionHandler, gExceptionType[Index].Exception);
-      ASSERT_EFI_ERROR (Status);
-    }
-    //
-    // Current edk2 DebugPort is not interrupt context safe so we can not use it
-    //
-    Status = DebugSupport->RegisterPeriodicCallback (DebugSupport, Processor, GdbPeriodicCallBack);
-    ASSERT_EFI_ERROR (Status);
-  }
-  //
-  // This even fires every time an image is added. This allows the stub to know when gdb needs
-  // to update the symbol table. 
-  //
-  Status = gBS->CreateEvent (
-                  EVT_NOTIFY_SIGNAL,
-                  TPL_CALLBACK,
-                  GdbSymbolEventHandler,
-                  NULL,
-                  &gEvent
-                  );
-  ASSERT_EFI_ERROR (Status);
-
-  //
-  // Register for protocol notifactions on this event
-  //
-  Status = gBS->RegisterProtocolNotify (
-                  &gEfiLoadedImageProtocolGuid,
-                  gEvent,
-                  &gGdbSymbolEventHandlerRegistration
-                  );
-  ASSERT_EFI_ERROR (Status);
-
- if (PcdGetBool (PcdGdbSerial)) {
-   GdbInitializeSerialConsole ();
- }
-   
-  return EFI_SUCCESS;
-}
-
-
-
-/**
- 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)) {
-      Print ((CHAR16 *)L"Bad message from write to memory..\n");
-      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;
-
-  if (ValidateAddress(Address) == FALSE) {
-    SendError(14);
-    return;
-  }
-
-  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 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
- )
-{
-  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 ("");
-}
-
-
-
-/**
- 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;
-  UINTN BreakpointDetected;
-  BREAK_TYPE BreakType;
-  UINTN DataAddress;
-  CHAR8 *WatchStrPtr = NULL;
-  UINTN RegSize;
-
-  TSignalPtr = &TSignalBuffer[0];
-
-  //Construct TSignal packet
-  *TSignalPtr++ = 'T';
-
-  //
-  // replace _, or previous value, with Exception type
-  //
-  *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4]; 
-  *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];
-  
-  if (GdbExceptionType == GDB_SIGTRAP) {
-    if (gSymbolTableUpdate) {
-      //
-      // We can only send back on reason code. So if the flag is set it means the breakpoint is from our event handler
-      //
-      WatchStrPtr = "library:;";
-      while (*WatchStrPtr != '\0') {
-        *TSignalPtr++ = *WatchStrPtr++;
-      }
-      gSymbolTableUpdate = FALSE;
-    } else {
-
-
-      //
-      // possible n:r pairs
-      // 
-
-      //Retrieve the breakpoint number
-      BreakpointDetected = GetBreakpointDetected (SystemContext);
-
-      //Figure out if the exception is happend due to watch, rwatch or awatch.
-      BreakType = GetBreakpointType (SystemContext, BreakpointDetected); 
-
-      //INFO: rwatch is not supported due to the way IA32 debug registers work
-      if ((BreakType == DataWrite) || (BreakType == DataRead) || (BreakType == DataReadWrite)) {
-        
-        //Construct n:r pair
-        DataAddress = GetBreakpointDataAddress (SystemContext, BreakpointDetected);
-
-        //Assign appropriate buffer to print particular watchpoint type
-        if (BreakType == DataWrite) {
-          WatchStrPtr = "watch";
-        } else if (BreakType == DataRead) {
-          WatchStrPtr = "rwatch";
-        } else if (BreakType == DataReadWrite) {
-          WatchStrPtr = "awatch";
-        }
-
-        while (*WatchStrPtr != '\0') {
-          *TSignalPtr++ = *WatchStrPtr++;
-        }
-
-        *TSignalPtr++ = ':';
-        
-        //Set up series of bytes in big-endian byte order. "awatch" won't work with little-endian byte order.
-        RegSize = REG_SIZE;
-        while (RegSize > 0) {
-          RegSize = RegSize-4;
-          *TSignalPtr++ = mHexToStr[(UINT8)(DataAddress >> RegSize) & 0xf];
-        }
-
-        //Always end n:r pair with ';'
-        *TSignalPtr++ = ';';
-      }
-    }
-  }
-
-  *TSignalPtr = '\0';
-
-  SendPacket (TSignalBuffer); 
-}
-
-
-/**
- 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) {
-    Print((CHAR16 *)L"Address is too long\n");
-    SendError (GDB_EBADMEMADDRBUFSIZE); 
-    return;
-  }
-  
-  // 2 = 'm' + ','
-  if (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {
-    Print((CHAR16 *)L"Length is too long\n");
-    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) {
-    Print ((CHAR16 *)L"Address too long..\n");
-    SendError (GDB_EBADMEMADDRBUFSIZE); 
-    return;
-  }
-  
-  //Check if message length is not too long
-  if (AsciiStrLen(LengthBuffer) >= MAX_LENGTH_SIZE) {
-    Print ((CHAR16 *)L"Length too long..\n");
-    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) {
-    Print ((CHAR16 *)L"Type is invalid\n");
-    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) {
-    Print ((CHAR16 *)L"Address too long..\n");
-    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) {
-    Print ((CHAR16 *)L"Length is invalid\n");
-    return 22; //EINVAL: Invalid argument
-  }
-
-  return 0; //0 = No error
-}
-
-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;
-}
-
-
-/**
-  Note: This should be a library function.  In the Apple case you have to add 
-  the size of the PE/COFF header into the starting address to make things work 
-  right as there is no way to pad the Mach-O for the size of the PE/COFF header.
-  
-  
-  Returns a pointer to the PDB file name for a PE/COFF image that has been
-  loaded into system memory with the PE/COFF Loader Library functions.
-
-  Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If
-  the PE/COFF image specified by Pe32Data is not a valid, then NULL is
-  returned.  If the PE/COFF image specified by Pe32Data does not contain a
-  debug directory entry, then NULL is returned.  If the debug directory entry
-  in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
-  then NULL is returned.
-  If Pe32Data is NULL, then ASSERT().
-
-  @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
-                     memory.
-  @param  DebugBase  Address that the debugger would use as the base of the image
-
-  @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
-          if it cannot be retrieved. DebugBase is only valid if PDB file name is
-          valid. 
-
-**/
-VOID *
-EFIAPI
-PeCoffLoaderGetDebuggerInfo (
-  IN VOID     *Pe32Data,
-  OUT VOID    **DebugBase
-  )
-{
-  EFI_IMAGE_DOS_HEADER                  *DosHdr;
-  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
-  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
-  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
-  UINTN                                 DirCount;
-  VOID                                  *CodeViewEntryPointer;
-  INTN                                  TEImageAdjust;
-  UINT32                                NumberOfRvaAndSizes;
-  UINT16                                Magic;
-  UINTN                                 SizeOfHeaders;
-
-  ASSERT (Pe32Data   != NULL);
-
-  TEImageAdjust       = 0;
-  DirectoryEntry      = NULL;
-  DebugEntry          = NULL;
-  NumberOfRvaAndSizes = 0;
-  SizeOfHeaders       = 0;
-
-  DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
-  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
-    //
-    // DOS image header is present, so read the PE header after the DOS image header.
-    //
-    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
-  } else {
-    //
-    // DOS image header is not present, so PE header is at the image base.
-    //
-    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
-  }
-
-  if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
-    if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
-      DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
-      TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
-      DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
-                    Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +
-                    TEImageAdjust);
-    }
-    SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
-    
-    // __APPLE__ check this math...
-    *DebugBase = ((CHAR8 *)Pe32Data) -  TEImageAdjust;
-  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
-    
-    *DebugBase = Pe32Data;
-    
-    
-    //
-    // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
-    //       It is due to backward-compatibility, for some system might
-    //       generate PE32+ image with PE32 Magic.
-    //
-    switch (Hdr.Pe32->FileHeader.Machine) {
-    case EFI_IMAGE_MACHINE_IA32:
-      //
-      // Assume PE32 image with IA32 Machine field.
-      //
-      Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
-      break;
-    case EFI_IMAGE_MACHINE_X64:
-    case EFI_IMAGE_MACHINE_IA64:
-      //
-      // Assume PE32+ image with X64 or IPF Machine field
-      //
-      Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
-      break;
-    default:
-      //
-      // For unknow Machine field, use Magic in optional Header
-      //
-      Magic = Hdr.Pe32->OptionalHeader.Magic;
-    }
-
-    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
-      //
-      // Use PE32 offset get Debug Directory Entry
-      //
-      SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
-      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
-      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
-      DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
-    } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
-      //
-      // Use PE32+ offset get Debug Directory Entry
-      //
-      SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
-      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
-      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
-      DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
-    }
-
-    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
-      DirectoryEntry = NULL;
-      DebugEntry = NULL;
-    }
-  } else {
-    return NULL;
-  }
-
-  if (DebugEntry == NULL || DirectoryEntry == NULL) {
-    return NULL;
-  }
-
-  for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
-    if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
-      if (DebugEntry->SizeOfData > 0) {
-        CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);
-        switch (* (UINT32 *) CodeViewEntryPointer) {
-        case CODEVIEW_SIGNATURE_NB10:
-          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
-        case CODEVIEW_SIGNATURE_RSDS:
-          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
-        case CODEVIEW_SIGNATURE_MTOC:
-          *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders);
-          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
-        default:
-          break;
-        }
-      }
-    }
-  }
-
-  (void)SizeOfHeaders;
-  return NULL;
-}
-
-
-
-/** 
-  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:
-  
-  <library-list>
-    <library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>
-    <library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>
-    <library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>
-  </library-list>
-  
-  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 availble part of the document.
-     
-  Note: The only variable size element in the XML is:
-  "  <library name=\"%s\"><segment address=\"%p\"/></library>\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
-  )
-{
-  VOID                              *LoadAddress;
-  CHAR8                             *Pdb;
-  UINTN                             Size;
-
-  if (Offset != gPacketqXferLibraryOffset) {
-    SendError (GDB_EINVALIDARG);
-    Print (L"\nqXferLibrary (%d, %d) != %d\n", Offset, Length, gPacketqXferLibraryOffset);
-    
-    // Force a retry from the beginning 
-    gPacketqXferLibraryOffset = 0;
-    return;
-  }
-
-  if (Offset == 0) {
-    gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");
-    
-    // The owner of the table may have had to ralloc it so grab a fresh copy every time
-    // we assume qXferLibrary will get called over and over again until the entire XML table is 
-    // returned in a tight loop. Since we are in the debugger the table should not get updated
-    gDebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;
-    gEfiDebugImageTableEntry = 0;
-    return;
-  }
-  
-  if (gDebugTable != NULL) {
-    for (; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) {
-      if (gDebugTable->NormalImage != NULL) {
-        if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) && 
-            (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
-          Pdb = PeCoffLoaderGetDebuggerInfo (
-                 gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase, 
-                 &LoadAddress
-                 );
-          if (Pdb != NULL) {
-            Size = AsciiSPrint (
-                    gXferLibraryBuffer, 
-                    sizeof (gXferLibraryBuffer), 
-                    "  <library name=\"%a\"><segment address=\"0x%p\"/></library>\n", 
-                    Pdb,
-                    LoadAddress
-                    );
-            if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) {
-              gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer);
-              
-              // Update loop variables so we are in the right place when we get back
-              gEfiDebugImageTableEntry++;
-              gDebugTable++;
-              return;
-            } else {
-              // We could handle <library> entires larger than sizeof (gXferLibraryBuffer) here if 
-              // needed by breaking up into N packets
-              // "<library name=\"%s
-              // the rest of the string (as many packets as required
-              // \"><segment address=\"%d\"/></library> (fixed size)
-              //
-              // But right now we just skip any entry that is too big
-            }
-          }           
-        }
-      }  
-    }
-  }
-  
-  
-  gXferObjectReadResponse ('l', "</library-list>\n");
-  gPacketqXferLibraryOffset = 0;
-  return;
-}
-
-
-/**
- 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 (ValidateException(ExceptionType, SystemContext) == FALSE) {
-    return;
-  }
-
-  RemoveSingleStep (SystemContext);
-  
-  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 '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));
-        } if (AsciiStrnCmp (gInBuffer, "qOffsets", 10) == 0) {
-          AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");
-          SendPacket (gOutBuffer);
-        } 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;
-    }
-  }
-}
-
-
-/**
- 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 
-  )
-{
-  //
-  // gCtrlCBreakFlag may have been set from a previous F response package 
-  // and we set the global as we need to process it at a point where we 
-  // can update the system context. If we are in the middle of processing
-  // a F Packet it is not safe to read the GDB serial stream so we need
-  // to skip it on this check
-  //
-  if (!gCtrlCBreakFlag && !gProcessingFPacket) {
-    //
-    // Ctrl-C was not pending so grab any pending characters and see if they 
-    // are a Ctrl-c (0x03). If so set the Ctrl-C global. 
-    //
-    while (TRUE) {
-      if (!GdbIsCharAvailable ()) {
-        //
-        // No characters are pending so exit the loop
-        //
-        break;
-      }
-      
-      if (GdbGetChar () == 0x03) {
-        gCtrlCBreakFlag = TRUE;
-        //
-        // We have a ctrl-c so exit the loop
-        //
-        break;
-      }
-    }
-  }
-  
-  if (gCtrlCBreakFlag) {
-    //
-    // Update the context to force a single step trap when we exit the GDB
-    // stub. This will trasfer control to GdbExceptionHandler () and let
-    // us break into the program. We don't want to break into the GDB stub.
-    //
-    AddSingleStep (SystemContext);
-    gCtrlCBreakFlag = FALSE;
-  }
-}
+/** @file\r
+  UEFI driver that implements a GDB stub\r
+\r
+  Note: Any code in the path of the Serial IO output can not call DEBUG as will\r
+  will blow out the stack. Serial IO calls DEBUG, debug calls Serail IO, ...\r
+\r
+\r
+  Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <GdbStubInternal.h>\r
+#include <Protocol/DebugPort.h>\r
+\r
+\r
+UINTN     gMaxProcessorIndex = 0;\r
+\r
+//\r
+// Buffers for basic gdb communication\r
+//\r
+CHAR8 gInBuffer[MAX_BUF_SIZE];\r
+CHAR8 gOutBuffer[MAX_BUF_SIZE];\r
+\r
+// Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default\r
+// this value to FALSE. Since gdb can reconnect its self a global default is not good enough\r
+BOOLEAN   gSymbolTableUpdate = FALSE;\r
+EFI_EVENT gEvent;\r
+VOID      *gGdbSymbolEventHandlerRegistration = NULL;\r
+\r
+//\r
+// Globals for returning XML from qXfer:libraries:read packet\r
+//\r
+UINTN                             gPacketqXferLibraryOffset = 0;\r
+UINTN                             gEfiDebugImageTableEntry = 0;\r
+EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;\r
+EFI_DEBUG_IMAGE_INFO              *gDebugTable = NULL;\r
+CHAR8                             gXferLibraryBuffer[2000];\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
+\r
+\r
+VOID\r
+EFIAPI\r
+GdbSymbolEventHandler (\r
+  IN  EFI_EVENT       Event,\r
+  IN  VOID            *Context\r
+  )\r
+{\r
+}\r
+\r
+\r
+/**\r
+  The user Entry Point for Application. The user code starts with this function\r
+  as the real entry point for the image goes into a library that calls this\r
+  function.\r
+\r
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.\r
+  @param[in] SystemTable    A pointer to the EFI System Table.\r
+\r
+  @retval EFI_SUCCESS       The entry point is executed successfully.\r
+  @retval other             Some error occurs when executing this entry point.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GdbStubEntry (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_DEBUG_SUPPORT_PROTOCOL  *DebugSupport;\r
+  UINTN                       HandleCount;\r
+  EFI_HANDLE                  *Handles;\r
+  UINTN                       Index;\r
+  UINTN                       Processor;\r
+  BOOLEAN                     IsaSupported;\r
+\r
+  Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);\r
+  if (EFI_ERROR (Status)) {\r
+    gDebugImageTableHeader = NULL;\r
+  }\r
+\r
+  Status = gBS->LocateHandleBuffer (\r
+                  ByProtocol,\r
+                  &gEfiDebugSupportProtocolGuid,\r
+                  NULL,\r
+                  &HandleCount,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Debug Support Protocol not found\n"));\r
+\r
+    return Status;\r
+  }\r
+\r
+  DebugSupport = NULL;\r
+  IsaSupported = FALSE;\r
+  do {\r
+    HandleCount--;\r
+    Status = gBS->HandleProtocol (\r
+                    Handles[HandleCount],\r
+                    &gEfiDebugSupportProtocolGuid,\r
+                    (VOID **) &DebugSupport\r
+                    );\r
+    if (!EFI_ERROR (Status)) {\r
+      if (CheckIsa (DebugSupport->Isa)) {\r
+        // We found what we are looking for so break out of the loop\r
+        IsaSupported = TRUE;\r
+        break;\r
+      }\r
+    }\r
+  } while (HandleCount > 0);\r
+  FreePool (Handles);\r
+\r
+  if (!IsaSupported) {\r
+    DEBUG ((EFI_D_ERROR, "Debug Support Protocol does not support our ISA\n"));\r
+\r
+    return EFI_NOT_FOUND;\r
+  }\r
+\r
+  Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  DEBUG ((EFI_D_INFO, "Debug Support Protocol ISA %x\n", DebugSupport->Isa));\r
+  DEBUG ((EFI_D_INFO, "Debug Support Protocol Processor Index %d\n", gMaxProcessorIndex));\r
+\r
+  // Call processor-specific init routine\r
+  InitializeProcessor ();\r
+\r
+  for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) {\r
+    for (Index = 0; Index < MaxEfiException (); Index++) {\r
+      Status = DebugSupport->RegisterExceptionCallback (DebugSupport, Processor,  GdbExceptionHandler, gExceptionType[Index].Exception);\r
+      ASSERT_EFI_ERROR (Status);\r
+    }\r
+    //\r
+    // Current edk2 DebugPort is not interrupt context safe so we can not use it\r
+    //\r
+    Status = DebugSupport->RegisterPeriodicCallback (DebugSupport, Processor, GdbPeriodicCallBack);\r
+    ASSERT_EFI_ERROR (Status);\r
+  }\r
+\r
+  //\r
+  // This even fires every time an image is added. This allows the stub to know when gdb needs\r
+  // to update the symbol table.\r
+  //\r
+  Status = gBS->CreateEvent (\r
+                  EVT_NOTIFY_SIGNAL,\r
+                  TPL_CALLBACK,\r
+                  GdbSymbolEventHandler,\r
+                  NULL,\r
+                  &gEvent\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Register for protocol notifications on this event\r
+  //\r
+  Status = gBS->RegisterProtocolNotify (\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  gEvent,\r
+                  &gGdbSymbolEventHandlerRegistration\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+\r
+ if (PcdGetBool (PcdGdbSerial)) {\r
+   GdbInitializeSerialConsole ();\r
+ }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Transfer length bytes of input buffer, starting at Address, to memory.\r
+\r
+ @param     length                  the number of the bytes to be transferred/written\r
+ @param     *address                the start address of the transferring/writing the memory\r
+ @param     *new_data               the new data to be written to memory\r
+ **/\r
+\r
+VOID\r
+TransferFromInBufToMem (\r
+  IN    UINTN                       Length,\r
+  IN    unsigned char               *Address,\r
+  IN    CHAR8                       *NewData\r
+  )\r
+{\r
+  CHAR8 c1;\r
+  CHAR8 c2;\r
+\r
+  while (Length-- > 0) {\r
+    c1 = (CHAR8)HexCharToInt (*NewData++);\r
+    c2 = (CHAR8)HexCharToInt (*NewData++);\r
+\r
+    if ((c1 < 0) || (c2 < 0)) {\r
+      Print ((CHAR16 *)L"Bad message from write to memory..\n");\r
+      SendError (GDB_EBADMEMDATA);\r
+      return;\r
+    }\r
+    *Address++ = (UINT8)((c1 << 4) + c2);\r
+  }\r
+\r
+  SendSuccess();\r
+}\r
+\r
+\r
+/**\r
+ Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer\r
+ as a packet.\r
+\r
+ @param     Length                  the number of the bytes to be transferred/read\r
+ @param     *address                pointer to the start address of the transferring/reading the memory\r
+ **/\r
+\r
+VOID\r
+TransferFromMemToOutBufAndSend (\r
+  IN    UINTN                       Length,\r
+  IN    unsigned char               *Address\r
+  )\r
+{\r
+  // there are Length bytes and every byte is represented as 2 hex chars\r
+  CHAR8   OutBuffer[MAX_BUF_SIZE];\r
+  CHAR8   *OutBufPtr;             // pointer to the output buffer\r
+  CHAR8   Char;\r
+\r
+  if (ValidateAddress(Address) == FALSE) {\r
+    SendError(14);\r
+    return;\r
+  }\r
+\r
+  OutBufPtr = OutBuffer;\r
+  while (Length > 0) {\r
+\r
+    Char = mHexToStr[*Address >> 4];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+\r
+    Char = mHexToStr[*Address & 0x0f];\r
+    if ((Char >= 'A') && (Char <= 'F')) {\r
+      Char = Char - 'A' + 'a';\r
+    }\r
+    *OutBufPtr++ = Char;\r
+\r
+    Address++;\r
+    Length--;\r
+  }\r
+\r
+  *OutBufPtr = '\0' ;  // the end of the buffer\r
+  SendPacket (OutBuffer);\r
+}\r
+\r
+\r
+\r
+/**\r
+  Send a GDB Remote Serial Protocol Packet\r
+\r
+  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',\r
+  the packet teminating character '#' and the two digit checksum.\r
+\r
+  If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up\r
+  in an infinit loop. This is so if you unplug the debugger code just keeps running\r
+\r
+  @param PacketData   Payload data for the packet\r
+\r
+\r
+  @retval             Number of bytes of packet data sent.\r
+\r
+**/\r
+UINTN\r
+SendPacket (\r
+  IN  CHAR8 *PacketData\r
+  )\r
+{\r
+  UINT8 CheckSum;\r
+  UINTN Timeout;\r
+  CHAR8 *Ptr;\r
+  CHAR8 TestChar;\r
+  UINTN Count;\r
+\r
+  Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);\r
+\r
+  Count = 0;\r
+  do {\r
+\r
+    Ptr = PacketData;\r
+\r
+    if (Timeout-- == 0) {\r
+      // Only try a finite number of times so we don't get stuck in the loop\r
+      return Count;\r
+    }\r
+\r
+    // Packet prefix\r
+    GdbPutChar ('$');\r
+\r
+    for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {\r
+      GdbPutChar (*Ptr);\r
+      CheckSum = CheckSum + *Ptr;\r
+    }\r
+\r
+    // Packet terminating character and checksum\r
+    GdbPutChar ('#');\r
+    GdbPutChar (mHexToStr[CheckSum >> 4]);\r
+    GdbPutChar (mHexToStr[CheckSum & 0x0F]);\r
+\r
+    TestChar =  GdbGetChar ();\r
+  } while (TestChar != '+');\r
+\r
+  return Count;\r
+}\r
+\r
+/**\r
+  Receive a GDB Remote Serial Protocol Packet\r
+\r
+  $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',\r
+  the packet teminating character '#' and the two digit checksum.\r
+\r
+  If host re-starts sending a packet without ending the previous packet, only the last valid packet is proccessed.\r
+  (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)\r
+\r
+  If an ack '+' is not sent resend the packet\r
+\r
+  @param PacketData   Payload data for the packet\r
+\r
+  @retval             Number of bytes of packet data received.\r
+\r
+**/\r
+UINTN\r
+ReceivePacket (\r
+  OUT  CHAR8 *PacketData,\r
+  IN   UINTN PacketDataSize\r
+ )\r
+{\r
+  UINT8 CheckSum;\r
+  UINTN Index;\r
+  CHAR8 Char;\r
+  CHAR8 SumString[3];\r
+  CHAR8 TestChar;\r
+\r
+  ZeroMem (PacketData, PacketDataSize);\r
+\r
+  for (;;) {\r
+      // wait for the start of a packet\r
+    TestChar = GdbGetChar ();\r
+    while (TestChar != '$') {\r
+      TestChar = GdbGetChar ();\r
+    };\r
+\r
+  retry:\r
+    for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {\r
+      Char = GdbGetChar ();\r
+      if (Char == '$') {\r
+        goto retry;\r
+      }\r
+      if (Char == '#') {\r
+        break;\r
+      }\r
+\r
+      PacketData[Index] = Char;\r
+      CheckSum = CheckSum + Char;\r
+    }\r
+    PacketData[Index] = '\0';\r
+\r
+    if (Index == PacketDataSize) {\r
+      continue;\r
+    }\r
+\r
+    SumString[0] = GdbGetChar ();\r
+    SumString[1] = GdbGetChar ();\r
+    SumString[2] = '\0';\r
+\r
+    if (AsciiStrHexToUintn (SumString) == CheckSum) {\r
+      // Ack: Success\r
+      GdbPutChar ('+');\r
+\r
+      // Null terminate the callers string\r
+      PacketData[Index] = '\0';\r
+      return Index;\r
+    } else {\r
+      // Ack: Failure\r
+      GdbPutChar ('-');\r
+    }\r
+  }\r
+\r
+  //return 0;\r
+}\r
+\r
+\r
+/**\r
+ Empties the given buffer\r
+ @param   Buf          pointer to the first element in buffer to be emptied\r
+ **/\r
+VOID\r
+EmptyBuffer (\r
+  IN  CHAR8           *Buf\r
+  )\r
+{\r
+  *Buf = '\0';\r
+}\r
+\r
+\r
+/**\r
+ Converts an 8-bit Hex Char into a INTN.\r
+\r
+ @param   Char the hex character to be converted into UINTN\r
+ @retval  a INTN, from 0 to 15, that corressponds to Char\r
+ -1 if Char is not a hex character\r
+ **/\r
+INTN\r
+HexCharToInt (\r
+  IN  CHAR8           Char\r
+  )\r
+{\r
+  if ((Char >= 'A') && (Char <= 'F')) {\r
+    return Char - 'A' + 10;\r
+  } else if ((Char >= 'a') && (Char <= 'f')) {\r
+    return Char - 'a' + 10;\r
+  } else if ((Char >= '0') && (Char <= '9')) {\r
+    return Char - '0';\r
+  } else { // if not a hex value, return a negative value\r
+    return -1;\r
+  }\r
+}\r
+\r
+  // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end\r
+CHAR8 *gError = "E__";\r
+\r
+/** 'E NN'\r
+ Send an error with the given error number after converting to hex.\r
+ The error number is put into the buffer in hex. '255' is the biggest errno we can send.\r
+ ex: 162 will be sent as A2.\r
+\r
+ @param   errno           the error number that will be sent\r
+ **/\r
+VOID\r
+EFIAPI\r
+SendError (\r
+  IN  UINT8              ErrorNum\r
+  )\r
+{\r
+  //\r
+  // Replace _, or old data, with current errno\r
+  //\r
+  gError[1] = mHexToStr [ErrorNum >> 4];\r
+  gError[2] = mHexToStr [ErrorNum & 0x0f];\r
+\r
+  SendPacket (gError); // send buffer\r
+}\r
+\r
+\r
+\r
+/**\r
+ Send 'OK' when the function is done executing successfully.\r
+ **/\r
+VOID\r
+EFIAPI\r
+SendSuccess (\r
+  VOID\r
+  )\r
+{\r
+  SendPacket ("OK"); // send buffer\r
+}\r
+\r
+\r
+/**\r
+ Send empty packet to specify that particular command/functionality is not supported.\r
+ **/\r
+VOID\r
+EFIAPI\r
+SendNotSupported (\r
+  VOID\r
+  )\r
+{\r
+  SendPacket ("");\r
+}\r
+\r
+\r
+/**\r
+ Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints\r
+\r
+ @param  SystemContext        Register content at time of the exception\r
+ @param  GdbExceptionType     GDB exception type\r
+ **/\r
+VOID\r
+GdbSendTSignal (\r
+  IN  EFI_SYSTEM_CONTEXT  SystemContext,\r
+  IN  UINT8               GdbExceptionType\r
+  )\r
+{\r
+  CHAR8 TSignalBuffer[128];\r
+  CHAR8 *TSignalPtr;\r
+  UINTN BreakpointDetected;\r
+  BREAK_TYPE BreakType;\r
+  UINTN DataAddress;\r
+  CHAR8 *WatchStrPtr = NULL;\r
+  UINTN RegSize;\r
+\r
+  TSignalPtr = &TSignalBuffer[0];\r
+\r
+  //Construct TSignal packet\r
+  *TSignalPtr++ = 'T';\r
+\r
+  //\r
+  // replace _, or previous value, with Exception type\r
+  //\r
+  *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4];\r
+  *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];\r
+\r
+  if (GdbExceptionType == GDB_SIGTRAP) {\r
+    if (gSymbolTableUpdate) {\r
+      //\r
+      // We can only send back on reason code. So if the flag is set it means the breakpoint is from our event handler\r
+      //\r
+      WatchStrPtr = "library:;";\r
+      while (*WatchStrPtr != '\0') {\r
+        *TSignalPtr++ = *WatchStrPtr++;\r
+      }\r
+      gSymbolTableUpdate = FALSE;\r
+    } else {\r
+\r
+\r
+      //\r
+      // possible n:r pairs\r
+      //\r
+\r
+      //Retrieve the breakpoint number\r
+      BreakpointDetected = GetBreakpointDetected (SystemContext);\r
+\r
+      //Figure out if the exception is happend due to watch, rwatch or awatch.\r
+      BreakType = GetBreakpointType (SystemContext, BreakpointDetected);\r
+\r
+      //INFO: rwatch is not supported due to the way IA32 debug registers work\r
+      if ((BreakType == DataWrite) || (BreakType == DataRead) || (BreakType == DataReadWrite)) {\r
+\r
+        //Construct n:r pair\r
+        DataAddress = GetBreakpointDataAddress (SystemContext, BreakpointDetected);\r
+\r
+        //Assign appropriate buffer to print particular watchpoint type\r
+        if (BreakType == DataWrite) {\r
+          WatchStrPtr = "watch";\r
+        } else if (BreakType == DataRead) {\r
+          WatchStrPtr = "rwatch";\r
+        } else if (BreakType == DataReadWrite) {\r
+          WatchStrPtr = "awatch";\r
+        }\r
+\r
+        while (*WatchStrPtr != '\0') {\r
+          *TSignalPtr++ = *WatchStrPtr++;\r
+        }\r
+\r
+        *TSignalPtr++ = ':';\r
+\r
+        //Set up series of bytes in big-endian byte order. "awatch" won't work with little-endian byte order.\r
+        RegSize = REG_SIZE;\r
+        while (RegSize > 0) {\r
+          RegSize = RegSize-4;\r
+          *TSignalPtr++ = mHexToStr[(UINT8)(DataAddress >> RegSize) & 0xf];\r
+        }\r
+\r
+        //Always end n:r pair with ';'\r
+        *TSignalPtr++ = ';';\r
+      }\r
+    }\r
+  }\r
+\r
+  *TSignalPtr = '\0';\r
+\r
+  SendPacket (TSignalBuffer);\r
+}\r
+\r
+\r
+/**\r
+ Translates the EFI mapping to GDB mapping\r
+\r
+ @param   EFIExceptionType    EFI Exception that is being processed\r
+ @retval  UINTN that corresponds to EFIExceptionType's GDB exception type number\r
+ **/\r
+UINT8\r
+ConvertEFItoGDBtype (\r
+  IN  EFI_EXCEPTION_TYPE      EFIExceptionType\r
+  )\r
+{\r
+  UINTN Index;\r
+\r
+  for (Index = 0; Index < MaxEfiException () ; Index++) {\r
+    if (gExceptionType[Index].Exception == EFIExceptionType) {\r
+      return gExceptionType[Index].SignalNo;\r
+    }\r
+  }\r
+  return GDB_SIGTRAP; // this is a GDB trap\r
+}\r
+\r
+\r
+/** "m addr,length"\r
+ Find the Length of the area to read and the start addres. Finally, pass them to\r
+ another function, TransferFromMemToOutBufAndSend, that will read from that memory space and\r
+ send it as a packet.\r
+ **/\r
+\r
+VOID\r
+EFIAPI\r
+ReadFromMemory (\r
+  CHAR8 *PacketData\r
+  )\r
+{\r
+  UINTN Address;\r
+  UINTN Length;\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars\r
+  CHAR8 *AddrBufPtr; // pointer to the address buffer\r
+  CHAR8 *InBufPtr; /// pointer to the input buffer\r
+\r
+  AddrBufPtr = AddressBuffer;\r
+  InBufPtr = &PacketData[1];\r
+  while (*InBufPtr != ',') {\r
+    *AddrBufPtr++ = *InBufPtr++;\r
+  }\r
+  *AddrBufPtr = '\0';\r
+\r
+  InBufPtr++; // this skips ',' in the buffer\r
+\r
+  /* Error checking */\r
+  if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    Print((CHAR16 *)L"Address is too long\n");\r
+    SendError (GDB_EBADMEMADDRBUFSIZE);\r
+    return;\r
+  }\r
+\r
+  // 2 = 'm' + ','\r
+  if (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {\r
+    Print((CHAR16 *)L"Length is too long\n");\r
+    SendError (GDB_EBADMEMLENGTH);\r
+    return;\r
+  }\r
+\r
+  Address = AsciiStrHexToUintn (AddressBuffer);\r
+  Length = AsciiStrHexToUintn (InBufPtr);\r
+\r
+  TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);\r
+}\r
+\r
+\r
+/** "M addr,length :XX..."\r
+ Find the Length of the area in bytes to write and the start addres. Finally, pass them to\r
+ another function, TransferFromInBufToMem, that will write to that memory space the info in\r
+ the input buffer.\r
+ **/\r
+VOID\r
+EFIAPI\r
+WriteToMemory (\r
+  IN CHAR8 *PacketData\r
+  )\r
+{\r
+  UINTN Address;\r
+  UINTN Length;\r
+  UINTN MessageLength;\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars\r
+  CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars\r
+  CHAR8 *AddrBufPtr; // pointer to the Address buffer\r
+  CHAR8 *LengthBufPtr; // pointer to the Length buffer\r
+  CHAR8 *InBufPtr; /// pointer to the input buffer\r
+\r
+  AddrBufPtr = AddressBuffer;\r
+  LengthBufPtr = LengthBuffer;\r
+  InBufPtr = &PacketData[1];\r
+\r
+  while (*InBufPtr != ',') {\r
+    *AddrBufPtr++ = *InBufPtr++;\r
+  }\r
+  *AddrBufPtr = '\0';\r
+\r
+  InBufPtr++; // this skips ',' in the buffer\r
+\r
+  while (*InBufPtr != ':') {\r
+    *LengthBufPtr++ = *InBufPtr++;\r
+  }\r
+  *LengthBufPtr = '\0';\r
+\r
+  InBufPtr++; // this skips ':' in the buffer\r
+\r
+  Address = AsciiStrHexToUintn (AddressBuffer);\r
+  Length = AsciiStrHexToUintn (LengthBuffer);\r
+\r
+  /* Error checking */\r
+\r
+  //Check if Address is not too long.\r
+  if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    Print ((CHAR16 *)L"Address too long..\n");\r
+    SendError (GDB_EBADMEMADDRBUFSIZE);\r
+    return;\r
+  }\r
+\r
+  //Check if message length is not too long\r
+  if (AsciiStrLen (LengthBuffer) >= MAX_LENGTH_SIZE) {\r
+    Print ((CHAR16 *)L"Length too long..\n");\r
+    SendError (GDB_EBADMEMLENGBUFSIZE);\r
+    return;\r
+  }\r
+\r
+  // Check if Message is not too long/short.\r
+  // 3 = 'M' + ',' + ':'\r
+  MessageLength = (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - AsciiStrLen (LengthBuffer) - 3);\r
+  if (MessageLength != (2*Length)) {\r
+    //Message too long/short. New data is not the right size.\r
+    SendError (GDB_EBADMEMDATASIZE);\r
+    return;\r
+  }\r
+  TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);\r
+}\r
+\r
+/**\r
+  Parses breakpoint packet data and captures Breakpoint type, Address and length.\r
+  In case of an error, function returns particular error code. Returning 0 meaning\r
+  no error.\r
+\r
+  @param  PacketData  Pointer to the payload data for the packet.\r
+  @param  Type        Breakpoint type\r
+  @param  Address     Breakpoint address\r
+  @param  Length      Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)\r
+\r
+  @retval 1           Success\r
+  @retval {other}     Particular error code\r
+\r
+**/\r
+UINTN\r
+ParseBreakpointPacket (\r
+  IN  CHAR8 *PacketData,\r
+  OUT UINTN *Type,\r
+  OUT UINTN *Address,\r
+  OUT UINTN *Length\r
+  )\r
+{\r
+  CHAR8 AddressBuffer[MAX_ADDR_SIZE];\r
+  CHAR8 *AddressBufferPtr;\r
+  CHAR8 *PacketDataPtr;\r
+\r
+  PacketDataPtr = &PacketData[1];\r
+  AddressBufferPtr = AddressBuffer;\r
+\r
+  *Type = AsciiStrHexToUintn (PacketDataPtr);\r
+\r
+  //Breakpoint/watchpoint type should be between 0 to 4\r
+  if (*Type > 4) {\r
+    Print ((CHAR16 *)L"Type is invalid\n");\r
+    return 22; //EINVAL: Invalid argument.\r
+  }\r
+\r
+  //Skip ',' in the buffer.\r
+  while (*PacketDataPtr++ != ',');\r
+\r
+  //Parse Address information\r
+  while (*PacketDataPtr != ',') {\r
+    *AddressBufferPtr++ = *PacketDataPtr++;\r
+  }\r
+  *AddressBufferPtr = '\0';\r
+\r
+  //Check if Address is not too long.\r
+  if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
+    Print ((CHAR16 *)L"Address too long..\n");\r
+    return 40; //EMSGSIZE: Message size too long.\r
+  }\r
+\r
+  *Address = AsciiStrHexToUintn (AddressBuffer);\r
+\r
+  PacketDataPtr++; //This skips , in the buffer\r
+\r
+  //Parse Length information\r
+  *Length = AsciiStrHexToUintn (PacketDataPtr);\r
+\r
+  //Length should be 1, 2 or 4 bytes\r
+  if (*Length > 4) {\r
+    Print ((CHAR16 *)L"Length is invalid\n");\r
+    return 22; //EINVAL: Invalid argument\r
+  }\r
+\r
+  return 0; //0 = No error\r
+}\r
+\r
+UINTN\r
+gXferObjectReadResponse (\r
+  IN  CHAR8         Type,\r
+  IN  CHAR8         *Str\r
+  )\r
+{\r
+  CHAR8   *OutBufPtr;             // pointer to the output buffer\r
+  CHAR8   Char;\r
+  UINTN   Count;\r
+\r
+  // Response starts with 'm' or 'l' if it is the end\r
+  OutBufPtr = gOutBuffer;\r
+  *OutBufPtr++ = Type;\r
+  Count = 1;\r
+\r
+  // Binary data encoding\r
+  OutBufPtr = gOutBuffer;\r
+  while (*Str != '\0') {\r
+    Char = *Str++;\r
+    if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {\r
+      // escape character\r
+      *OutBufPtr++ = 0x7d;\r
+\r
+      Char ^= 0x20;\r
+    }\r
+    *OutBufPtr++ = Char;\r
+    Count++;\r
+  }\r
+\r
+  *OutBufPtr = '\0' ;  // the end of the buffer\r
+  SendPacket (gOutBuffer);\r
+\r
+  return Count;\r
+}\r
+\r
+\r
+/**\r
+  Note: This should be a library function.  In the Apple case you have to add\r
+  the size of the PE/COFF header into the starting address to make things work\r
+  right as there is no way to pad the Mach-O for the size of the PE/COFF header.\r
+\r
+\r
+  Returns a pointer to the PDB file name for a PE/COFF image that has been\r
+  loaded into system memory with the PE/COFF Loader Library functions.\r
+\r
+  Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If\r
+  the PE/COFF image specified by Pe32Data is not a valid, then NULL is\r
+  returned.  If the PE/COFF image specified by Pe32Data does not contain a\r
+  debug directory entry, then NULL is returned.  If the debug directory entry\r
+  in the PE/COFF image specified by Pe32Data does not contain a PDB file name,\r
+  then NULL is returned.\r
+  If Pe32Data is NULL, then ASSERT().\r
+\r
+  @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system\r
+                     memory.\r
+  @param  DebugBase  Address that the debugger would use as the base of the image\r
+\r
+  @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL\r
+          if it cannot be retrieved. DebugBase is only valid if PDB file name is\r
+          valid.\r
+\r
+**/\r
+VOID *\r
+EFIAPI\r
+PeCoffLoaderGetDebuggerInfo (\r
+  IN VOID     *Pe32Data,\r
+  OUT VOID    **DebugBase\r
+  )\r
+{\r
+  EFI_IMAGE_DOS_HEADER                  *DosHdr;\r
+  EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;\r
+  EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;\r
+  EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;\r
+  UINTN                                 DirCount;\r
+  VOID                                  *CodeViewEntryPointer;\r
+  INTN                                  TEImageAdjust;\r
+  UINT32                                NumberOfRvaAndSizes;\r
+  UINT16                                Magic;\r
+  UINTN                                 SizeOfHeaders;\r
+\r
+  ASSERT (Pe32Data   != NULL);\r
+\r
+  TEImageAdjust       = 0;\r
+  DirectoryEntry      = NULL;\r
+  DebugEntry          = NULL;\r
+  NumberOfRvaAndSizes = 0;\r
+  SizeOfHeaders       = 0;\r
+\r
+  DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;\r
+  if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r
+    //\r
+    // DOS image header is present, so read the PE header after the DOS image header.\r
+    //\r
+    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));\r
+  } else {\r
+    //\r
+    // DOS image header is not present, so PE header is at the image base.\r
+    //\r
+    Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;\r
+  }\r
+\r
+  if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {\r
+    if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {\r
+      DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];\r
+      TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;\r
+      DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +\r
+                    Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +\r
+                    TEImageAdjust);\r
+    }\r
+    SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;\r
+\r
+    // __APPLE__ check this math...\r
+    *DebugBase = ((CHAR8 *)Pe32Data) -  TEImageAdjust;\r
+  } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
+\r
+    *DebugBase = Pe32Data;\r
+\r
+\r
+    //\r
+    // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.\r
+    //       It is due to backward-compatibility, for some system might\r
+    //       generate PE32+ image with PE32 Magic.\r
+    //\r
+    switch (Hdr.Pe32->FileHeader.Machine) {\r
+    case EFI_IMAGE_MACHINE_IA32:\r
+      //\r
+      // Assume PE32 image with IA32 Machine field.\r
+      //\r
+      Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;\r
+      break;\r
+    case EFI_IMAGE_MACHINE_X64:\r
+    case EFI_IMAGE_MACHINE_IA64:\r
+      //\r
+      // Assume PE32+ image with X64 or IPF Machine field\r
+      //\r
+      Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+      break;\r
+    default:\r
+      //\r
+      // For unknow Machine field, use Magic in optional Header\r
+      //\r
+      Magic = Hdr.Pe32->OptionalHeader.Magic;\r
+    }\r
+\r
+    if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+      //\r
+      // Use PE32 offset get Debug Directory Entry\r
+      //\r
+      SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;\r
+      NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r
+      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+      DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
+    } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r
+      //\r
+      // Use PE32+ offset get Debug Directory Entry\r
+      //\r
+      SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;\r
+      NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r
+      DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);\r
+      DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);\r
+    }\r
+\r
+    if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {\r
+      DirectoryEntry = NULL;\r
+      DebugEntry = NULL;\r
+    }\r
+  } else {\r
+    return NULL;\r
+  }\r
+\r
+  if (DebugEntry == NULL || DirectoryEntry == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {\r
+    if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {\r
+      if (DebugEntry->SizeOfData > 0) {\r
+        CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);\r
+        switch (* (UINT32 *) CodeViewEntryPointer) {\r
+        case CODEVIEW_SIGNATURE_NB10:\r
+          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));\r
+        case CODEVIEW_SIGNATURE_RSDS:\r
+          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));\r
+        case CODEVIEW_SIGNATURE_MTOC:\r
+          *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders);\r
+          return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));\r
+        default:\r
+          break;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  (void)SizeOfHeaders;\r
+  return NULL;\r
+}\r
+\r
+\r
+/**\r
+  Process "qXfer:object:read:annex:offset,length" request.\r
+\r
+  Returns an XML document that contains loaded libraries. In our case it is\r
+  information in the EFI Debug Image Table converted into an XML document.\r
+\r
+  GDB will call with an arbitrary length (it can't know the real length and\r
+  will reply with chunks of XML that are easy for us to deal with. Gdb will\r
+  keep calling until we say we are done. XML doc looks like:\r
+\r
+  <library-list>\r
+    <library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>\r
+    <library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>\r
+    <library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>\r
+  </library-list>\r
+\r
+  Since we can not allocate memory in interrupt context this module has\r
+  assumptions about how it will get called:\r
+  1) Length will generally be max remote packet size (big enough)\r
+  2) First Offset of an XML document read needs to be 0\r
+  3) This code will return back small chunks of the XML document on every read.\r
+     Each subsequent call will ask for the next available part of the document.\r
+\r
+  Note: The only variable size element in the XML is:\r
+  "  <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is\r
+  based on the file path and name of the symbol file. If the symbol file name\r
+  is bigger than the max gdb remote packet size we could update this code\r
+  to respond back in chunks.\r
+\r
+ @param Offset  offset into special data area\r
+ @param Length  number of bytes to read starting at Offset\r
+\r
+ **/\r
+VOID\r
+QxferLibrary (\r
+  IN  UINTN   Offset,\r
+  IN  UINTN   Length\r
+  )\r
+{\r
+  VOID                              *LoadAddress;\r
+  CHAR8                             *Pdb;\r
+  UINTN                             Size;\r
+\r
+  if (Offset != gPacketqXferLibraryOffset) {\r
+    SendError (GDB_EINVALIDARG);\r
+    Print (L"\nqXferLibrary (%d, %d) != %d\n", Offset, Length, gPacketqXferLibraryOffset);\r
+\r
+    // Force a retry from the beginning\r
+    gPacketqXferLibraryOffset = 0;\r
+\r
+    return;\r
+  }\r
+\r
+  if (Offset == 0) {\r
+    gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");\r
+\r
+    // The owner of the table may have had to ralloc it so grab a fresh copy every time\r
+    // we assume qXferLibrary will get called over and over again until the entire XML table is\r
+    // returned in a tight loop. Since we are in the debugger the table should not get updated\r
+    gDebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;\r
+    gEfiDebugImageTableEntry = 0;\r
+    return;\r
+  }\r
+\r
+  if (gDebugTable != NULL) {\r
+    for (; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) {\r
+      if (gDebugTable->NormalImage != NULL) {\r
+        if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&\r
+            (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {\r
+          Pdb = PeCoffLoaderGetDebuggerInfo (\r
+                 gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase,\r
+                 &LoadAddress\r
+                 );\r
+          if (Pdb != NULL) {\r
+            Size = AsciiSPrint (\r
+                    gXferLibraryBuffer,\r
+                    sizeof (gXferLibraryBuffer),\r
+                    "  <library name=\"%a\"><segment address=\"0x%p\"/></library>\n",\r
+                    Pdb,\r
+                    LoadAddress\r
+                    );\r
+            if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) {\r
+              gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer);\r
+\r
+              // Update loop variables so we are in the right place when we get back\r
+              gEfiDebugImageTableEntry++;\r
+              gDebugTable++;\r
+              return;\r
+            } else {\r
+              // We could handle <library> entires larger than sizeof (gXferLibraryBuffer) here if\r
+              // needed by breaking up into N packets\r
+              // "<library name=\"%s\r
+              // the rest of the string (as many packets as required\r
+              // \"><segment address=\"%d\"/></library> (fixed size)\r
+              //\r
+              // But right now we just skip any entry that is too big\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+\r
+  gXferObjectReadResponse ('l', "</library-list>\n");\r
+  gPacketqXferLibraryOffset = 0;\r
+  return;\r
+}\r
+\r
+\r
+/**\r
+ Exception Hanldler for GDB. It will be called for all exceptions\r
+ registered via the gExceptionType[] array.\r
+\r
+ @param ExceptionType     Exception that is being processed\r
+ @param SystemContext     Register content at time of the exception\r
+ **/\r
+VOID\r
+EFIAPI\r
+GdbExceptionHandler (\r
+  IN  EFI_EXCEPTION_TYPE        ExceptionType,\r
+  IN OUT EFI_SYSTEM_CONTEXT     SystemContext\r
+  )\r
+{\r
+  UINT8   GdbExceptionType;\r
+  CHAR8   *Ptr;\r
+\r
+\r
+  if (ValidateException (ExceptionType, SystemContext) == FALSE) {\r
+    return;\r
+  }\r
+\r
+  RemoveSingleStep (SystemContext);\r
+\r
+  GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);\r
+  GdbSendTSignal (SystemContext, GdbExceptionType);\r
+\r
+  for( ; ; ) {\r
+    ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
+\r
+    switch (gInBuffer[0]) {\r
+      case '?':\r
+        GdbSendTSignal (SystemContext, GdbExceptionType);\r
+        break;\r
+\r
+      case 'c':\r
+        ContinueAtAddress (SystemContext, gInBuffer);\r
+        return;\r
+\r
+      case 'g':\r
+        ReadGeneralRegisters (SystemContext);\r
+        break;\r
+\r
+      case 'G':\r
+        WriteGeneralRegisters (SystemContext, gInBuffer);\r
+        break;\r
+\r
+      case 'H':\r
+        //Return "OK" packet since we don't have more than one thread.\r
+        SendSuccess ();\r
+        break;\r
+\r
+      case 'm':\r
+        ReadFromMemory (gInBuffer);\r
+        break;\r
+\r
+      case 'M':\r
+        WriteToMemory (gInBuffer);\r
+        break;\r
+\r
+      case 'P':\r
+        WriteNthRegister (SystemContext, gInBuffer);\r
+        break;\r
+\r
+      //\r
+      // Still debugging this code. Not used in Darwin\r
+      //\r
+      case 'q':\r
+        // General Query Packets\r
+        if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {\r
+          // return what we currently support, we don't parse what gdb suports\r
+          AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);\r
+          SendPacket (gOutBuffer);\r
+        } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {\r
+          // ‘qXfer:libraries:read::offset,length\r
+          // gInBuffer[22] is offset string, ++Ptr is length string’\r
+          for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++);\r
+\r
+          // Not sure if multi-radix support is required. Currently only support decimal\r
+          QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr));\r
+        } if (AsciiStrnCmp (gInBuffer, "qOffsets", 10) == 0) {\r
+          AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");\r
+          SendPacket (gOutBuffer);\r
+        } else {\r
+          //Send empty packet\r
+          SendNotSupported ();\r
+        }\r
+        break;\r
+\r
+      case 's':\r
+        SingleStep (SystemContext, gInBuffer);\r
+        return;\r
+\r
+      case 'z':\r
+        RemoveBreakPoint (SystemContext, gInBuffer);\r
+        break;\r
+\r
+      case 'Z':\r
+        InsertBreakPoint (SystemContext, gInBuffer);\r
+        break;\r
+\r
+      default:\r
+        //Send empty packet\r
+        SendNotSupported ();\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ Periodic callback for GDB. This function is used to catch a ctrl-c or other\r
+ break in type command from GDB.\r
+\r
+ @param SystemContext     Register content at time of the call\r
+ **/\r
+VOID\r
+EFIAPI\r
+GdbPeriodicCallBack (\r
+  IN OUT EFI_SYSTEM_CONTEXT     SystemContext\r
+  )\r
+{\r
+  //\r
+  // gCtrlCBreakFlag may have been set from a previous F response package\r
+  // and we set the global as we need to process it at a point where we\r
+  // can update the system context. If we are in the middle of processing\r
+  // a F Packet it is not safe to read the GDB serial stream so we need\r
+  // to skip it on this check\r
+  //\r
+  if (!gCtrlCBreakFlag && !gProcessingFPacket) {\r
+    //\r
+    // Ctrl-C was not pending so grab any pending characters and see if they\r
+    // are a Ctrl-c (0x03). If so set the Ctrl-C global.\r
+    //\r
+    while (TRUE) {\r
+      if (!GdbIsCharAvailable ()) {\r
+        //\r
+        // No characters are pending so exit the loop\r
+        //\r
+        break;\r
+      }\r
+\r
+      if (GdbGetChar () == 0x03) {\r
+        gCtrlCBreakFlag = TRUE;\r
+        //\r
+        // We have a ctrl-c so exit the loop\r
+        //\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (gCtrlCBreakFlag) {\r
+    //\r
+    // Update the context to force a single step trap when we exit the GDB\r
+    // stub. This will transfer control to GdbExceptionHandler () and let\r
+    // us break into the program. We don't want to break into the GDB stub.\r
+    //\r
+    AddSingleStep (SystemContext);\r
+    gCtrlCBreakFlag = FALSE;\r
+  }\r
+}\r