• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   UEFI driver that implements a GDB stub
3 
4   Note: Any code in the path of the Serial IO output can not call DEBUG as will
5   will blow out the stack. Serial IO calls DEBUG, debug calls Serail IO, ...
6 
7 
8   Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>
9 
10   This program and the accompanying materials
11   are licensed and made available under the terms and conditions of the BSD License
12   which accompanies this distribution.  The full text of the license may be found at
13   http://opensource.org/licenses/bsd-license.php
14 
15   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
16   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 
18 **/
19 
20 #include <GdbStubInternal.h>
21 #include <Protocol/DebugPort.h>
22 
23 
24 UINTN     gMaxProcessorIndex = 0;
25 
26 //
27 // Buffers for basic gdb communication
28 //
29 CHAR8 gInBuffer[MAX_BUF_SIZE];
30 CHAR8 gOutBuffer[MAX_BUF_SIZE];
31 
32 // Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default
33 // this value to FALSE. Since gdb can reconnect its self a global default is not good enough
34 BOOLEAN   gSymbolTableUpdate = FALSE;
35 EFI_EVENT gEvent;
36 VOID      *gGdbSymbolEventHandlerRegistration = NULL;
37 
38 //
39 // Globals for returning XML from qXfer:libraries:read packet
40 //
41 UINTN                             gPacketqXferLibraryOffset = 0;
42 UINTN                             gEfiDebugImageTableEntry = 0;
43 EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;
44 EFI_DEBUG_IMAGE_INFO              *gDebugTable = NULL;
45 CHAR8                             gXferLibraryBuffer[2000];
46 
47 GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
48 
49 
50 VOID
51 EFIAPI
GdbSymbolEventHandler(IN EFI_EVENT Event,IN VOID * Context)52 GdbSymbolEventHandler (
53   IN  EFI_EVENT       Event,
54   IN  VOID            *Context
55   )
56 {
57 }
58 
59 
60 /**
61   The user Entry Point for Application. The user code starts with this function
62   as the real entry point for the image goes into a library that calls this
63   function.
64 
65   @param[in] ImageHandle    The firmware allocated handle for the EFI image.
66   @param[in] SystemTable    A pointer to the EFI System Table.
67 
68   @retval EFI_SUCCESS       The entry point is executed successfully.
69   @retval other             Some error occurs when executing this entry point.
70 
71 **/
72 EFI_STATUS
73 EFIAPI
GdbStubEntry(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)74 GdbStubEntry (
75   IN EFI_HANDLE        ImageHandle,
76   IN EFI_SYSTEM_TABLE  *SystemTable
77   )
78 {
79   EFI_STATUS                  Status;
80   EFI_DEBUG_SUPPORT_PROTOCOL  *DebugSupport;
81   UINTN                       HandleCount;
82   EFI_HANDLE                  *Handles;
83   UINTN                       Index;
84   UINTN                       Processor;
85   BOOLEAN                     IsaSupported;
86 
87   Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);
88   if (EFI_ERROR (Status)) {
89     gDebugImageTableHeader = NULL;
90   }
91 
92   Status = gBS->LocateHandleBuffer (
93                   ByProtocol,
94                   &gEfiDebugSupportProtocolGuid,
95                   NULL,
96                   &HandleCount,
97                   &Handles
98                   );
99   if (EFI_ERROR (Status)) {
100     DEBUG ((EFI_D_ERROR, "Debug Support Protocol not found\n"));
101 
102     return Status;
103   }
104 
105   DebugSupport = NULL;
106   IsaSupported = FALSE;
107   do {
108     HandleCount--;
109     Status = gBS->HandleProtocol (
110                     Handles[HandleCount],
111                     &gEfiDebugSupportProtocolGuid,
112                     (VOID **) &DebugSupport
113                     );
114     if (!EFI_ERROR (Status)) {
115       if (CheckIsa (DebugSupport->Isa)) {
116         // We found what we are looking for so break out of the loop
117         IsaSupported = TRUE;
118         break;
119       }
120     }
121   } while (HandleCount > 0);
122   FreePool (Handles);
123 
124   if (!IsaSupported) {
125     DEBUG ((EFI_D_ERROR, "Debug Support Protocol does not support our ISA\n"));
126 
127     return EFI_NOT_FOUND;
128   }
129 
130   Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex);
131   ASSERT_EFI_ERROR (Status);
132 
133   DEBUG ((EFI_D_INFO, "Debug Support Protocol ISA %x\n", DebugSupport->Isa));
134   DEBUG ((EFI_D_INFO, "Debug Support Protocol Processor Index %d\n", gMaxProcessorIndex));
135 
136   // Call processor-specific init routine
137   InitializeProcessor ();
138 
139   for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) {
140     for (Index = 0; Index < MaxEfiException (); Index++) {
141       Status = DebugSupport->RegisterExceptionCallback (DebugSupport, Processor,  GdbExceptionHandler, gExceptionType[Index].Exception);
142       ASSERT_EFI_ERROR (Status);
143     }
144     //
145     // Current edk2 DebugPort is not interrupt context safe so we can not use it
146     //
147     Status = DebugSupport->RegisterPeriodicCallback (DebugSupport, Processor, GdbPeriodicCallBack);
148     ASSERT_EFI_ERROR (Status);
149   }
150 
151   //
152   // This even fires every time an image is added. This allows the stub to know when gdb needs
153   // to update the symbol table.
154   //
155   Status = gBS->CreateEvent (
156                   EVT_NOTIFY_SIGNAL,
157                   TPL_CALLBACK,
158                   GdbSymbolEventHandler,
159                   NULL,
160                   &gEvent
161                   );
162   ASSERT_EFI_ERROR (Status);
163 
164   //
165   // Register for protocol notifications on this event
166   //
167   Status = gBS->RegisterProtocolNotify (
168                   &gEfiLoadedImageProtocolGuid,
169                   gEvent,
170                   &gGdbSymbolEventHandlerRegistration
171                   );
172   ASSERT_EFI_ERROR (Status);
173 
174 
175  if (PcdGetBool (PcdGdbSerial)) {
176    GdbInitializeSerialConsole ();
177  }
178 
179   return EFI_SUCCESS;
180 }
181 
182 /**
183  Transfer length bytes of input buffer, starting at Address, to memory.
184 
185  @param     length                  the number of the bytes to be transferred/written
186  @param     *address                the start address of the transferring/writing the memory
187  @param     *new_data               the new data to be written to memory
188  **/
189 
190 VOID
TransferFromInBufToMem(IN UINTN Length,IN unsigned char * Address,IN CHAR8 * NewData)191 TransferFromInBufToMem (
192   IN    UINTN                       Length,
193   IN    unsigned char               *Address,
194   IN    CHAR8                       *NewData
195   )
196 {
197   CHAR8 c1;
198   CHAR8 c2;
199 
200   while (Length-- > 0) {
201     c1 = (CHAR8)HexCharToInt (*NewData++);
202     c2 = (CHAR8)HexCharToInt (*NewData++);
203 
204     if ((c1 < 0) || (c2 < 0)) {
205       Print ((CHAR16 *)L"Bad message from write to memory..\n");
206       SendError (GDB_EBADMEMDATA);
207       return;
208     }
209     *Address++ = (UINT8)((c1 << 4) + c2);
210   }
211 
212   SendSuccess();
213 }
214 
215 
216 /**
217  Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer
218  as a packet.
219 
220  @param     Length                  the number of the bytes to be transferred/read
221  @param     *address                pointer to the start address of the transferring/reading the memory
222  **/
223 
224 VOID
TransferFromMemToOutBufAndSend(IN UINTN Length,IN unsigned char * Address)225 TransferFromMemToOutBufAndSend (
226   IN    UINTN                       Length,
227   IN    unsigned char               *Address
228   )
229 {
230   // there are Length bytes and every byte is represented as 2 hex chars
231   CHAR8   OutBuffer[MAX_BUF_SIZE];
232   CHAR8   *OutBufPtr;             // pointer to the output buffer
233   CHAR8   Char;
234 
235   if (ValidateAddress(Address) == FALSE) {
236     SendError(14);
237     return;
238   }
239 
240   OutBufPtr = OutBuffer;
241   while (Length > 0) {
242 
243     Char = mHexToStr[*Address >> 4];
244     if ((Char >= 'A') && (Char <= 'F')) {
245       Char = Char - 'A' + 'a';
246     }
247     *OutBufPtr++ = Char;
248 
249     Char = mHexToStr[*Address & 0x0f];
250     if ((Char >= 'A') && (Char <= 'F')) {
251       Char = Char - 'A' + 'a';
252     }
253     *OutBufPtr++ = Char;
254 
255     Address++;
256     Length--;
257   }
258 
259   *OutBufPtr = '\0' ;  // the end of the buffer
260   SendPacket (OutBuffer);
261 }
262 
263 
264 
265 /**
266   Send a GDB Remote Serial Protocol Packet
267 
268   $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
269   the packet teminating character '#' and the two digit checksum.
270 
271   If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up
272   in an infinit loop. This is so if you unplug the debugger code just keeps running
273 
274   @param PacketData   Payload data for the packet
275 
276 
277   @retval             Number of bytes of packet data sent.
278 
279 **/
280 UINTN
SendPacket(IN CHAR8 * PacketData)281 SendPacket (
282   IN  CHAR8 *PacketData
283   )
284 {
285   UINT8 CheckSum;
286   UINTN Timeout;
287   CHAR8 *Ptr;
288   CHAR8 TestChar;
289   UINTN Count;
290 
291   Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);
292 
293   Count = 0;
294   do {
295 
296     Ptr = PacketData;
297 
298     if (Timeout-- == 0) {
299       // Only try a finite number of times so we don't get stuck in the loop
300       return Count;
301     }
302 
303     // Packet prefix
304     GdbPutChar ('$');
305 
306     for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {
307       GdbPutChar (*Ptr);
308       CheckSum = CheckSum + *Ptr;
309     }
310 
311     // Packet terminating character and checksum
312     GdbPutChar ('#');
313     GdbPutChar (mHexToStr[CheckSum >> 4]);
314     GdbPutChar (mHexToStr[CheckSum & 0x0F]);
315 
316     TestChar =  GdbGetChar ();
317   } while (TestChar != '+');
318 
319   return Count;
320 }
321 
322 /**
323   Receive a GDB Remote Serial Protocol Packet
324 
325   $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',
326   the packet teminating character '#' and the two digit checksum.
327 
328   If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.
329   (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)
330 
331   If an ack '+' is not sent resend the packet
332 
333   @param PacketData   Payload data for the packet
334 
335   @retval             Number of bytes of packet data received.
336 
337 **/
338 UINTN
ReceivePacket(OUT CHAR8 * PacketData,IN UINTN PacketDataSize)339 ReceivePacket (
340   OUT  CHAR8 *PacketData,
341   IN   UINTN PacketDataSize
342  )
343 {
344   UINT8 CheckSum;
345   UINTN Index;
346   CHAR8 Char;
347   CHAR8 SumString[3];
348   CHAR8 TestChar;
349 
350   ZeroMem (PacketData, PacketDataSize);
351 
352   for (;;) {
353       // wait for the start of a packet
354     TestChar = GdbGetChar ();
355     while (TestChar != '$') {
356       TestChar = GdbGetChar ();
357     };
358 
359   retry:
360     for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {
361       Char = GdbGetChar ();
362       if (Char == '$') {
363         goto retry;
364       }
365       if (Char == '#') {
366         break;
367       }
368 
369       PacketData[Index] = Char;
370       CheckSum = CheckSum + Char;
371     }
372     PacketData[Index] = '\0';
373 
374     if (Index == PacketDataSize) {
375       continue;
376     }
377 
378     SumString[0] = GdbGetChar ();
379     SumString[1] = GdbGetChar ();
380     SumString[2] = '\0';
381 
382     if (AsciiStrHexToUintn (SumString) == CheckSum) {
383       // Ack: Success
384       GdbPutChar ('+');
385 
386       // Null terminate the callers string
387       PacketData[Index] = '\0';
388       return Index;
389     } else {
390       // Ack: Failure
391       GdbPutChar ('-');
392     }
393   }
394 
395   //return 0;
396 }
397 
398 
399 /**
400  Empties the given buffer
401  @param   Buf          pointer to the first element in buffer to be emptied
402  **/
403 VOID
EmptyBuffer(IN CHAR8 * Buf)404 EmptyBuffer (
405   IN  CHAR8           *Buf
406   )
407 {
408   *Buf = '\0';
409 }
410 
411 
412 /**
413  Converts an 8-bit Hex Char into a INTN.
414 
415  @param   Char the hex character to be converted into UINTN
416  @retval  a INTN, from 0 to 15, that corressponds to Char
417  -1 if Char is not a hex character
418  **/
419 INTN
HexCharToInt(IN CHAR8 Char)420 HexCharToInt (
421   IN  CHAR8           Char
422   )
423 {
424   if ((Char >= 'A') && (Char <= 'F')) {
425     return Char - 'A' + 10;
426   } else if ((Char >= 'a') && (Char <= 'f')) {
427     return Char - 'a' + 10;
428   } else if ((Char >= '0') && (Char <= '9')) {
429     return Char - '0';
430   } else { // if not a hex value, return a negative value
431     return -1;
432   }
433 }
434 
435   // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end
436 CHAR8 *gError = "E__";
437 
438 /** 'E NN'
439  Send an error with the given error number after converting to hex.
440  The error number is put into the buffer in hex. '255' is the biggest errno we can send.
441  ex: 162 will be sent as A2.
442 
443  @param   errno           the error number that will be sent
444  **/
445 VOID
446 EFIAPI
SendError(IN UINT8 ErrorNum)447 SendError (
448   IN  UINT8              ErrorNum
449   )
450 {
451   //
452   // Replace _, or old data, with current errno
453   //
454   gError[1] = mHexToStr [ErrorNum >> 4];
455   gError[2] = mHexToStr [ErrorNum & 0x0f];
456 
457   SendPacket (gError); // send buffer
458 }
459 
460 
461 
462 /**
463  Send 'OK' when the function is done executing successfully.
464  **/
465 VOID
466 EFIAPI
SendSuccess(VOID)467 SendSuccess (
468   VOID
469   )
470 {
471   SendPacket ("OK"); // send buffer
472 }
473 
474 
475 /**
476  Send empty packet to specify that particular command/functionality is not supported.
477  **/
478 VOID
479 EFIAPI
SendNotSupported(VOID)480 SendNotSupported (
481   VOID
482   )
483 {
484   SendPacket ("");
485 }
486 
487 
488 /**
489  Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints
490 
491  @param  SystemContext        Register content at time of the exception
492  @param  GdbExceptionType     GDB exception type
493  **/
494 VOID
GdbSendTSignal(IN EFI_SYSTEM_CONTEXT SystemContext,IN UINT8 GdbExceptionType)495 GdbSendTSignal (
496   IN  EFI_SYSTEM_CONTEXT  SystemContext,
497   IN  UINT8               GdbExceptionType
498   )
499 {
500   CHAR8 TSignalBuffer[128];
501   CHAR8 *TSignalPtr;
502   UINTN BreakpointDetected;
503   BREAK_TYPE BreakType;
504   UINTN DataAddress;
505   CHAR8 *WatchStrPtr = NULL;
506   UINTN RegSize;
507 
508   TSignalPtr = &TSignalBuffer[0];
509 
510   //Construct TSignal packet
511   *TSignalPtr++ = 'T';
512 
513   //
514   // replace _, or previous value, with Exception type
515   //
516   *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4];
517   *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];
518 
519   if (GdbExceptionType == GDB_SIGTRAP) {
520     if (gSymbolTableUpdate) {
521       //
522       // We can only send back on reason code. So if the flag is set it means the breakpoint is from our event handler
523       //
524       WatchStrPtr = "library:;";
525       while (*WatchStrPtr != '\0') {
526         *TSignalPtr++ = *WatchStrPtr++;
527       }
528       gSymbolTableUpdate = FALSE;
529     } else {
530 
531 
532       //
533       // possible n:r pairs
534       //
535 
536       //Retrieve the breakpoint number
537       BreakpointDetected = GetBreakpointDetected (SystemContext);
538 
539       //Figure out if the exception is happend due to watch, rwatch or awatch.
540       BreakType = GetBreakpointType (SystemContext, BreakpointDetected);
541 
542       //INFO: rwatch is not supported due to the way IA32 debug registers work
543       if ((BreakType == DataWrite) || (BreakType == DataRead) || (BreakType == DataReadWrite)) {
544 
545         //Construct n:r pair
546         DataAddress = GetBreakpointDataAddress (SystemContext, BreakpointDetected);
547 
548         //Assign appropriate buffer to print particular watchpoint type
549         if (BreakType == DataWrite) {
550           WatchStrPtr = "watch";
551         } else if (BreakType == DataRead) {
552           WatchStrPtr = "rwatch";
553         } else if (BreakType == DataReadWrite) {
554           WatchStrPtr = "awatch";
555         }
556 
557         while (*WatchStrPtr != '\0') {
558           *TSignalPtr++ = *WatchStrPtr++;
559         }
560 
561         *TSignalPtr++ = ':';
562 
563         //Set up series of bytes in big-endian byte order. "awatch" won't work with little-endian byte order.
564         RegSize = REG_SIZE;
565         while (RegSize > 0) {
566           RegSize = RegSize-4;
567           *TSignalPtr++ = mHexToStr[(UINT8)(DataAddress >> RegSize) & 0xf];
568         }
569 
570         //Always end n:r pair with ';'
571         *TSignalPtr++ = ';';
572       }
573     }
574   }
575 
576   *TSignalPtr = '\0';
577 
578   SendPacket (TSignalBuffer);
579 }
580 
581 
582 /**
583  Translates the EFI mapping to GDB mapping
584 
585  @param   EFIExceptionType    EFI Exception that is being processed
586  @retval  UINTN that corresponds to EFIExceptionType's GDB exception type number
587  **/
588 UINT8
ConvertEFItoGDBtype(IN EFI_EXCEPTION_TYPE EFIExceptionType)589 ConvertEFItoGDBtype (
590   IN  EFI_EXCEPTION_TYPE      EFIExceptionType
591   )
592 {
593   UINTN Index;
594 
595   for (Index = 0; Index < MaxEfiException () ; Index++) {
596     if (gExceptionType[Index].Exception == EFIExceptionType) {
597       return gExceptionType[Index].SignalNo;
598     }
599   }
600   return GDB_SIGTRAP; // this is a GDB trap
601 }
602 
603 
604 /** "m addr,length"
605  Find the Length of the area to read and the start addres. Finally, pass them to
606  another function, TransferFromMemToOutBufAndSend, that will read from that memory space and
607  send it as a packet.
608  **/
609 
610 VOID
611 EFIAPI
ReadFromMemory(CHAR8 * PacketData)612 ReadFromMemory (
613   CHAR8 *PacketData
614   )
615 {
616   UINTN Address;
617   UINTN Length;
618   CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars
619   CHAR8 *AddrBufPtr; // pointer to the address buffer
620   CHAR8 *InBufPtr; /// pointer to the input buffer
621 
622   AddrBufPtr = AddressBuffer;
623   InBufPtr = &PacketData[1];
624   while (*InBufPtr != ',') {
625     *AddrBufPtr++ = *InBufPtr++;
626   }
627   *AddrBufPtr = '\0';
628 
629   InBufPtr++; // this skips ',' in the buffer
630 
631   /* Error checking */
632   if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
633     Print((CHAR16 *)L"Address is too long\n");
634     SendError (GDB_EBADMEMADDRBUFSIZE);
635     return;
636   }
637 
638   // 2 = 'm' + ','
639   if (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {
640     Print((CHAR16 *)L"Length is too long\n");
641     SendError (GDB_EBADMEMLENGTH);
642     return;
643   }
644 
645   Address = AsciiStrHexToUintn (AddressBuffer);
646   Length = AsciiStrHexToUintn (InBufPtr);
647 
648   TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);
649 }
650 
651 
652 /** "M addr,length :XX..."
653  Find the Length of the area in bytes to write and the start addres. Finally, pass them to
654  another function, TransferFromInBufToMem, that will write to that memory space the info in
655  the input buffer.
656  **/
657 VOID
658 EFIAPI
WriteToMemory(IN CHAR8 * PacketData)659 WriteToMemory (
660   IN CHAR8 *PacketData
661   )
662 {
663   UINTN Address;
664   UINTN Length;
665   UINTN MessageLength;
666   CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars
667   CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars
668   CHAR8 *AddrBufPtr; // pointer to the Address buffer
669   CHAR8 *LengthBufPtr; // pointer to the Length buffer
670   CHAR8 *InBufPtr; /// pointer to the input buffer
671 
672   AddrBufPtr = AddressBuffer;
673   LengthBufPtr = LengthBuffer;
674   InBufPtr = &PacketData[1];
675 
676   while (*InBufPtr != ',') {
677     *AddrBufPtr++ = *InBufPtr++;
678   }
679   *AddrBufPtr = '\0';
680 
681   InBufPtr++; // this skips ',' in the buffer
682 
683   while (*InBufPtr != ':') {
684     *LengthBufPtr++ = *InBufPtr++;
685   }
686   *LengthBufPtr = '\0';
687 
688   InBufPtr++; // this skips ':' in the buffer
689 
690   Address = AsciiStrHexToUintn (AddressBuffer);
691   Length = AsciiStrHexToUintn (LengthBuffer);
692 
693   /* Error checking */
694 
695   //Check if Address is not too long.
696   if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
697     Print ((CHAR16 *)L"Address too long..\n");
698     SendError (GDB_EBADMEMADDRBUFSIZE);
699     return;
700   }
701 
702   //Check if message length is not too long
703   if (AsciiStrLen (LengthBuffer) >= MAX_LENGTH_SIZE) {
704     Print ((CHAR16 *)L"Length too long..\n");
705     SendError (GDB_EBADMEMLENGBUFSIZE);
706     return;
707   }
708 
709   // Check if Message is not too long/short.
710   // 3 = 'M' + ',' + ':'
711   MessageLength = (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - AsciiStrLen (LengthBuffer) - 3);
712   if (MessageLength != (2*Length)) {
713     //Message too long/short. New data is not the right size.
714     SendError (GDB_EBADMEMDATASIZE);
715     return;
716   }
717   TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);
718 }
719 
720 /**
721   Parses breakpoint packet data and captures Breakpoint type, Address and length.
722   In case of an error, function returns particular error code. Returning 0 meaning
723   no error.
724 
725   @param  PacketData  Pointer to the payload data for the packet.
726   @param  Type        Breakpoint type
727   @param  Address     Breakpoint address
728   @param  Length      Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)
729 
730   @retval 1           Success
731   @retval {other}     Particular error code
732 
733 **/
734 UINTN
ParseBreakpointPacket(IN CHAR8 * PacketData,OUT UINTN * Type,OUT UINTN * Address,OUT UINTN * Length)735 ParseBreakpointPacket (
736   IN  CHAR8 *PacketData,
737   OUT UINTN *Type,
738   OUT UINTN *Address,
739   OUT UINTN *Length
740   )
741 {
742   CHAR8 AddressBuffer[MAX_ADDR_SIZE];
743   CHAR8 *AddressBufferPtr;
744   CHAR8 *PacketDataPtr;
745 
746   PacketDataPtr = &PacketData[1];
747   AddressBufferPtr = AddressBuffer;
748 
749   *Type = AsciiStrHexToUintn (PacketDataPtr);
750 
751   //Breakpoint/watchpoint type should be between 0 to 4
752   if (*Type > 4) {
753     Print ((CHAR16 *)L"Type is invalid\n");
754     return 22; //EINVAL: Invalid argument.
755   }
756 
757   //Skip ',' in the buffer.
758   while (*PacketDataPtr++ != ',');
759 
760   //Parse Address information
761   while (*PacketDataPtr != ',') {
762     *AddressBufferPtr++ = *PacketDataPtr++;
763   }
764   *AddressBufferPtr = '\0';
765 
766   //Check if Address is not too long.
767   if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
768     Print ((CHAR16 *)L"Address too long..\n");
769     return 40; //EMSGSIZE: Message size too long.
770   }
771 
772   *Address = AsciiStrHexToUintn (AddressBuffer);
773 
774   PacketDataPtr++; //This skips , in the buffer
775 
776   //Parse Length information
777   *Length = AsciiStrHexToUintn (PacketDataPtr);
778 
779   //Length should be 1, 2 or 4 bytes
780   if (*Length > 4) {
781     Print ((CHAR16 *)L"Length is invalid\n");
782     return 22; //EINVAL: Invalid argument
783   }
784 
785   return 0; //0 = No error
786 }
787 
788 UINTN
gXferObjectReadResponse(IN CHAR8 Type,IN CHAR8 * Str)789 gXferObjectReadResponse (
790   IN  CHAR8         Type,
791   IN  CHAR8         *Str
792   )
793 {
794   CHAR8   *OutBufPtr;             // pointer to the output buffer
795   CHAR8   Char;
796   UINTN   Count;
797 
798   // Response starts with 'm' or 'l' if it is the end
799   OutBufPtr = gOutBuffer;
800   *OutBufPtr++ = Type;
801   Count = 1;
802 
803   // Binary data encoding
804   OutBufPtr = gOutBuffer;
805   while (*Str != '\0') {
806     Char = *Str++;
807     if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {
808       // escape character
809       *OutBufPtr++ = 0x7d;
810 
811       Char ^= 0x20;
812     }
813     *OutBufPtr++ = Char;
814     Count++;
815   }
816 
817   *OutBufPtr = '\0' ;  // the end of the buffer
818   SendPacket (gOutBuffer);
819 
820   return Count;
821 }
822 
823 
824 /**
825   Note: This should be a library function.  In the Apple case you have to add
826   the size of the PE/COFF header into the starting address to make things work
827   right as there is no way to pad the Mach-O for the size of the PE/COFF header.
828 
829 
830   Returns a pointer to the PDB file name for a PE/COFF image that has been
831   loaded into system memory with the PE/COFF Loader Library functions.
832 
833   Returns the PDB file name for the PE/COFF image specified by Pe32Data.  If
834   the PE/COFF image specified by Pe32Data is not a valid, then NULL is
835   returned.  If the PE/COFF image specified by Pe32Data does not contain a
836   debug directory entry, then NULL is returned.  If the debug directory entry
837   in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
838   then NULL is returned.
839   If Pe32Data is NULL, then ASSERT().
840 
841   @param  Pe32Data   Pointer to the PE/COFF image that is loaded in system
842                      memory.
843   @param  DebugBase  Address that the debugger would use as the base of the image
844 
845   @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
846           if it cannot be retrieved. DebugBase is only valid if PDB file name is
847           valid.
848 
849 **/
850 VOID *
851 EFIAPI
PeCoffLoaderGetDebuggerInfo(IN VOID * Pe32Data,OUT VOID ** DebugBase)852 PeCoffLoaderGetDebuggerInfo (
853   IN VOID     *Pe32Data,
854   OUT VOID    **DebugBase
855   )
856 {
857   EFI_IMAGE_DOS_HEADER                  *DosHdr;
858   EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION   Hdr;
859   EFI_IMAGE_DATA_DIRECTORY              *DirectoryEntry;
860   EFI_IMAGE_DEBUG_DIRECTORY_ENTRY       *DebugEntry;
861   UINTN                                 DirCount;
862   VOID                                  *CodeViewEntryPointer;
863   INTN                                  TEImageAdjust;
864   UINT32                                NumberOfRvaAndSizes;
865   UINT16                                Magic;
866   UINTN                                 SizeOfHeaders;
867 
868   ASSERT (Pe32Data   != NULL);
869 
870   TEImageAdjust       = 0;
871   DirectoryEntry      = NULL;
872   DebugEntry          = NULL;
873   NumberOfRvaAndSizes = 0;
874   SizeOfHeaders       = 0;
875 
876   DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
877   if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
878     //
879     // DOS image header is present, so read the PE header after the DOS image header.
880     //
881     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
882   } else {
883     //
884     // DOS image header is not present, so PE header is at the image base.
885     //
886     Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
887   }
888 
889   if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
890     if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
891       DirectoryEntry  = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
892       TEImageAdjust   = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
893       DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
894                     Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +
895                     TEImageAdjust);
896     }
897     SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
898 
899     // __APPLE__ check this math...
900     *DebugBase = ((CHAR8 *)Pe32Data) -  TEImageAdjust;
901   } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
902 
903     *DebugBase = Pe32Data;
904 
905 
906     //
907     // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
908     //       It is due to backward-compatibility, for some system might
909     //       generate PE32+ image with PE32 Magic.
910     //
911     switch (Hdr.Pe32->FileHeader.Machine) {
912     case EFI_IMAGE_MACHINE_IA32:
913       //
914       // Assume PE32 image with IA32 Machine field.
915       //
916       Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
917       break;
918     case EFI_IMAGE_MACHINE_X64:
919     case EFI_IMAGE_MACHINE_IA64:
920       //
921       // Assume PE32+ image with X64 or IPF Machine field
922       //
923       Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
924       break;
925     default:
926       //
927       // For unknow Machine field, use Magic in optional Header
928       //
929       Magic = Hdr.Pe32->OptionalHeader.Magic;
930     }
931 
932     if (Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
933       //
934       // Use PE32 offset get Debug Directory Entry
935       //
936       SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
937       NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
938       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
939       DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
940     } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
941       //
942       // Use PE32+ offset get Debug Directory Entry
943       //
944       SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
945       NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
946       DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
947       DebugEntry     = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ((UINTN) Pe32Data + DirectoryEntry->VirtualAddress);
948     }
949 
950     if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
951       DirectoryEntry = NULL;
952       DebugEntry = NULL;
953     }
954   } else {
955     return NULL;
956   }
957 
958   if (DebugEntry == NULL || DirectoryEntry == NULL) {
959     return NULL;
960   }
961 
962   for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
963     if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
964       if (DebugEntry->SizeOfData > 0) {
965         CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);
966         switch (* (UINT32 *) CodeViewEntryPointer) {
967         case CODEVIEW_SIGNATURE_NB10:
968           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
969         case CODEVIEW_SIGNATURE_RSDS:
970           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
971         case CODEVIEW_SIGNATURE_MTOC:
972           *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders);
973           return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
974         default:
975           break;
976         }
977       }
978     }
979   }
980 
981   (void)SizeOfHeaders;
982   return NULL;
983 }
984 
985 
986 /**
987   Process "qXfer:object:read:annex:offset,length" request.
988 
989   Returns an XML document that contains loaded libraries. In our case it is
990   information in the EFI Debug Image Table converted into an XML document.
991 
992   GDB will call with an arbitrary length (it can't know the real length and
993   will reply with chunks of XML that are easy for us to deal with. Gdb will
994   keep calling until we say we are done. XML doc looks like:
995 
996   <library-list>
997     <library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>
998     <library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>
999     <library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>
1000   </library-list>
1001 
1002   Since we can not allocate memory in interrupt context this module has
1003   assumptions about how it will get called:
1004   1) Length will generally be max remote packet size (big enough)
1005   2) First Offset of an XML document read needs to be 0
1006   3) This code will return back small chunks of the XML document on every read.
1007      Each subsequent call will ask for the next available part of the document.
1008 
1009   Note: The only variable size element in the XML is:
1010   "  <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is
1011   based on the file path and name of the symbol file. If the symbol file name
1012   is bigger than the max gdb remote packet size we could update this code
1013   to respond back in chunks.
1014 
1015  @param Offset  offset into special data area
1016  @param Length  number of bytes to read starting at Offset
1017 
1018  **/
1019 VOID
QxferLibrary(IN UINTN Offset,IN UINTN Length)1020 QxferLibrary (
1021   IN  UINTN   Offset,
1022   IN  UINTN   Length
1023   )
1024 {
1025   VOID                              *LoadAddress;
1026   CHAR8                             *Pdb;
1027   UINTN                             Size;
1028 
1029   if (Offset != gPacketqXferLibraryOffset) {
1030     SendError (GDB_EINVALIDARG);
1031     Print (L"\nqXferLibrary (%d, %d) != %d\n", Offset, Length, gPacketqXferLibraryOffset);
1032 
1033     // Force a retry from the beginning
1034     gPacketqXferLibraryOffset = 0;
1035 
1036     return;
1037   }
1038 
1039   if (Offset == 0) {
1040     gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");
1041 
1042     // The owner of the table may have had to ralloc it so grab a fresh copy every time
1043     // we assume qXferLibrary will get called over and over again until the entire XML table is
1044     // returned in a tight loop. Since we are in the debugger the table should not get updated
1045     gDebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;
1046     gEfiDebugImageTableEntry = 0;
1047     return;
1048   }
1049 
1050   if (gDebugTable != NULL) {
1051     for (; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) {
1052       if (gDebugTable->NormalImage != NULL) {
1053         if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&
1054             (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {
1055           Pdb = PeCoffLoaderGetDebuggerInfo (
1056                  gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase,
1057                  &LoadAddress
1058                  );
1059           if (Pdb != NULL) {
1060             Size = AsciiSPrint (
1061                     gXferLibraryBuffer,
1062                     sizeof (gXferLibraryBuffer),
1063                     "  <library name=\"%a\"><segment address=\"0x%p\"/></library>\n",
1064                     Pdb,
1065                     LoadAddress
1066                     );
1067             if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) {
1068               gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer);
1069 
1070               // Update loop variables so we are in the right place when we get back
1071               gEfiDebugImageTableEntry++;
1072               gDebugTable++;
1073               return;
1074             } else {
1075               // We could handle <library> entires larger than sizeof (gXferLibraryBuffer) here if
1076               // needed by breaking up into N packets
1077               // "<library name=\"%s
1078               // the rest of the string (as many packets as required
1079               // \"><segment address=\"%d\"/></library> (fixed size)
1080               //
1081               // But right now we just skip any entry that is too big
1082             }
1083           }
1084         }
1085       }
1086     }
1087   }
1088 
1089 
1090   gXferObjectReadResponse ('l', "</library-list>\n");
1091   gPacketqXferLibraryOffset = 0;
1092   return;
1093 }
1094 
1095 
1096 /**
1097  Exception Hanldler for GDB. It will be called for all exceptions
1098  registered via the gExceptionType[] array.
1099 
1100  @param ExceptionType     Exception that is being processed
1101  @param SystemContext     Register content at time of the exception
1102  **/
1103 VOID
1104 EFIAPI
GdbExceptionHandler(IN EFI_EXCEPTION_TYPE ExceptionType,IN OUT EFI_SYSTEM_CONTEXT SystemContext)1105 GdbExceptionHandler (
1106   IN  EFI_EXCEPTION_TYPE        ExceptionType,
1107   IN OUT EFI_SYSTEM_CONTEXT     SystemContext
1108   )
1109 {
1110   UINT8   GdbExceptionType;
1111   CHAR8   *Ptr;
1112 
1113 
1114   if (ValidateException (ExceptionType, SystemContext) == FALSE) {
1115     return;
1116   }
1117 
1118   RemoveSingleStep (SystemContext);
1119 
1120   GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);
1121   GdbSendTSignal (SystemContext, GdbExceptionType);
1122 
1123   for( ; ; ) {
1124     ReceivePacket (gInBuffer, MAX_BUF_SIZE);
1125 
1126     switch (gInBuffer[0]) {
1127       case '?':
1128         GdbSendTSignal (SystemContext, GdbExceptionType);
1129         break;
1130 
1131       case 'c':
1132         ContinueAtAddress (SystemContext, gInBuffer);
1133         return;
1134 
1135       case 'g':
1136         ReadGeneralRegisters (SystemContext);
1137         break;
1138 
1139       case 'G':
1140         WriteGeneralRegisters (SystemContext, gInBuffer);
1141         break;
1142 
1143       case 'H':
1144         //Return "OK" packet since we don't have more than one thread.
1145         SendSuccess ();
1146         break;
1147 
1148       case 'm':
1149         ReadFromMemory (gInBuffer);
1150         break;
1151 
1152       case 'M':
1153         WriteToMemory (gInBuffer);
1154         break;
1155 
1156       case 'P':
1157         WriteNthRegister (SystemContext, gInBuffer);
1158         break;
1159 
1160       //
1161       // Still debugging this code. Not used in Darwin
1162       //
1163       case 'q':
1164         // General Query Packets
1165         if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {
1166           // return what we currently support, we don't parse what gdb suports
1167           AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);
1168           SendPacket (gOutBuffer);
1169         } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {
1170           // ‘qXfer:libraries:read::offset,length
1171           // gInBuffer[22] is offset string, ++Ptr is length string’
1172           for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++);
1173 
1174           // Not sure if multi-radix support is required. Currently only support decimal
1175           QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr));
1176         } if (AsciiStrnCmp (gInBuffer, "qOffsets", 10) == 0) {
1177           AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");
1178           SendPacket (gOutBuffer);
1179         } else {
1180           //Send empty packet
1181           SendNotSupported ();
1182         }
1183         break;
1184 
1185       case 's':
1186         SingleStep (SystemContext, gInBuffer);
1187         return;
1188 
1189       case 'z':
1190         RemoveBreakPoint (SystemContext, gInBuffer);
1191         break;
1192 
1193       case 'Z':
1194         InsertBreakPoint (SystemContext, gInBuffer);
1195         break;
1196 
1197       default:
1198         //Send empty packet
1199         SendNotSupported ();
1200         break;
1201     }
1202   }
1203 }
1204 
1205 
1206 /**
1207  Periodic callback for GDB. This function is used to catch a ctrl-c or other
1208  break in type command from GDB.
1209 
1210  @param SystemContext     Register content at time of the call
1211  **/
1212 VOID
1213 EFIAPI
GdbPeriodicCallBack(IN OUT EFI_SYSTEM_CONTEXT SystemContext)1214 GdbPeriodicCallBack (
1215   IN OUT EFI_SYSTEM_CONTEXT     SystemContext
1216   )
1217 {
1218   //
1219   // gCtrlCBreakFlag may have been set from a previous F response package
1220   // and we set the global as we need to process it at a point where we
1221   // can update the system context. If we are in the middle of processing
1222   // a F Packet it is not safe to read the GDB serial stream so we need
1223   // to skip it on this check
1224   //
1225   if (!gCtrlCBreakFlag && !gProcessingFPacket) {
1226     //
1227     // Ctrl-C was not pending so grab any pending characters and see if they
1228     // are a Ctrl-c (0x03). If so set the Ctrl-C global.
1229     //
1230     while (TRUE) {
1231       if (!GdbIsCharAvailable ()) {
1232         //
1233         // No characters are pending so exit the loop
1234         //
1235         break;
1236       }
1237 
1238       if (GdbGetChar () == 0x03) {
1239         gCtrlCBreakFlag = TRUE;
1240         //
1241         // We have a ctrl-c so exit the loop
1242         //
1243         break;
1244       }
1245     }
1246   }
1247 
1248   if (gCtrlCBreakFlag) {
1249     //
1250     // Update the context to force a single step trap when we exit the GDB
1251     // stub. This will transfer control to GdbExceptionHandler () and let
1252     // us break into the program. We don't want to break into the GDB stub.
1253     //
1254     AddSingleStep (SystemContext);
1255     gCtrlCBreakFlag = FALSE;
1256   }
1257 }
1258