TianoCore EDK2 master
Loading...
Searching...
No Matches
GdbStub.c
Go to the documentation of this file.
1
14#include <GdbStubInternal.h>
15#include <Protocol/DebugPort.h>
16
17UINTN gMaxProcessorIndex = 0;
18
19//
20// Buffers for basic gdb communication
21//
22CHAR8 gInBuffer[MAX_BUF_SIZE];
23CHAR8 gOutBuffer[MAX_BUF_SIZE];
24
25// Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default
26// this value to FALSE. Since gdb can reconnect its self a global default is not good enough
27BOOLEAN gSymbolTableUpdate = FALSE;
28EFI_EVENT gEvent;
29VOID *gGdbSymbolEventHandlerRegistration = NULL;
30
31//
32// Globals for returning XML from qXfer:libraries:read packet
33//
34UINTN gPacketqXferLibraryOffset = 0;
35UINTN gEfiDebugImageTableEntry = 0;
36EFI_DEBUG_IMAGE_INFO_TABLE_HEADER *gDebugImageTableHeader = NULL;
37EFI_DEBUG_IMAGE_INFO *gDebugTable = NULL;
38CHAR8 gXferLibraryBuffer[2000];
39
40GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
41
42VOID
43EFIAPI
44GdbSymbolEventHandler (
45 IN EFI_EVENT Event,
46 IN VOID *Context
47 )
48{
49}
50
64EFIAPI
66 IN EFI_HANDLE ImageHandle,
67 IN EFI_SYSTEM_TABLE *SystemTable
68 )
69{
70 EFI_STATUS Status;
71 EFI_DEBUG_SUPPORT_PROTOCOL *DebugSupport;
72 UINTN HandleCount;
73 EFI_HANDLE *Handles;
74 UINTN Index;
75 UINTN Processor;
76 BOOLEAN IsaSupported;
77
78 Status = EfiGetSystemConfigurationTable (&gEfiDebugImageInfoTableGuid, (VOID **)&gDebugImageTableHeader);
79 if (EFI_ERROR (Status)) {
80 gDebugImageTableHeader = NULL;
81 }
82
83 Status = gBS->LocateHandleBuffer (
85 &gEfiDebugSupportProtocolGuid,
86 NULL,
87 &HandleCount,
88 &Handles
89 );
90 if (EFI_ERROR (Status)) {
91 DEBUG ((DEBUG_ERROR, "Debug Support Protocol not found\n"));
92
93 return Status;
94 }
95
96 DebugSupport = NULL;
97 IsaSupported = FALSE;
98 do {
99 HandleCount--;
100 Status = gBS->HandleProtocol (
101 Handles[HandleCount],
102 &gEfiDebugSupportProtocolGuid,
103 (VOID **)&DebugSupport
104 );
105 if (!EFI_ERROR (Status)) {
106 if (CheckIsa (DebugSupport->Isa)) {
107 // We found what we are looking for so break out of the loop
108 IsaSupported = TRUE;
109 break;
110 }
111 }
112 } while (HandleCount > 0);
113
114 FreePool (Handles);
115
116 if (!IsaSupported) {
117 DEBUG ((DEBUG_ERROR, "Debug Support Protocol does not support our ISA\n"));
118
119 return EFI_NOT_FOUND;
120 }
121
122 Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex);
123 ASSERT_EFI_ERROR (Status);
124
125 DEBUG ((DEBUG_INFO, "Debug Support Protocol ISA %x\n", DebugSupport->Isa));
126 DEBUG ((DEBUG_INFO, "Debug Support Protocol Processor Index %d\n", gMaxProcessorIndex));
127
128 // Call processor-specific init routine
129 InitializeProcessor ();
130
131 for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) {
132 for (Index = 0; Index < MaxEfiException (); Index++) {
133 Status = DebugSupport->RegisterExceptionCallback (DebugSupport, Processor, GdbExceptionHandler, gExceptionType[Index].Exception);
134 ASSERT_EFI_ERROR (Status);
135 }
136
137 //
138 // Current edk2 DebugPort is not interrupt context safe so we can not use it
139 //
140 Status = DebugSupport->RegisterPeriodicCallback (DebugSupport, Processor, GdbPeriodicCallBack);
141 ASSERT_EFI_ERROR (Status);
142 }
143
144 //
145 // This even fires every time an image is added. This allows the stub to know when gdb needs
146 // to update the symbol table.
147 //
148 Status = gBS->CreateEvent (
149 EVT_NOTIFY_SIGNAL,
150 TPL_CALLBACK,
151 GdbSymbolEventHandler,
152 NULL,
153 &gEvent
154 );
155 ASSERT_EFI_ERROR (Status);
156
157 //
158 // Register for protocol notifications on this event
159 //
160 Status = gBS->RegisterProtocolNotify (
161 &gEfiLoadedImageProtocolGuid,
162 gEvent,
163 &gGdbSymbolEventHandlerRegistration
164 );
165 ASSERT_EFI_ERROR (Status);
166
167 if (PcdGetBool (PcdGdbSerial)) {
169 }
170
171 return EFI_SUCCESS;
172}
173
181VOID
183 IN UINTN Length,
184 IN unsigned char *Address,
185 IN CHAR8 *NewData
186 )
187{
188 CHAR8 c1;
189 CHAR8 c2;
190
191 while (Length-- > 0) {
192 c1 = (CHAR8)HexCharToInt (*NewData++);
193 c2 = (CHAR8)HexCharToInt (*NewData++);
194
195 if ((c1 < 0) || (c2 < 0)) {
196 Print ((CHAR16 *)L"Bad message from write to memory..\n");
197 SendError (GDB_EBADMEMDATA);
198 return;
199 }
200
201 *Address++ = (UINT8)((c1 << 4) + c2);
202 }
203
204 SendSuccess ();
205}
206
214VOID
216 IN UINTN Length,
217 IN unsigned char *Address
218 )
219{
220 // there are Length bytes and every byte is represented as 2 hex chars
221 CHAR8 OutBuffer[MAX_BUF_SIZE];
222 CHAR8 *OutBufPtr; // pointer to the output buffer
223 CHAR8 Char;
224
225 if (ValidateAddress (Address) == FALSE) {
226 SendError (14);
227 return;
228 }
229
230 OutBufPtr = OutBuffer;
231 while (Length > 0) {
232 Char = mHexToStr[*Address >> 4];
233 if ((Char >= 'A') && (Char <= 'F')) {
234 Char = Char - 'A' + 'a';
235 }
236
237 *OutBufPtr++ = Char;
238
239 Char = mHexToStr[*Address & 0x0f];
240 if ((Char >= 'A') && (Char <= 'F')) {
241 Char = Char - 'A' + 'a';
242 }
243
244 *OutBufPtr++ = Char;
245
246 Address++;
247 Length--;
248 }
249
250 *OutBufPtr = '\0'; // the end of the buffer
251 SendPacket (OutBuffer);
252}
253
269UINTN
271 IN CHAR8 *PacketData
272 )
273{
274 UINT8 CheckSum;
275 UINTN Timeout;
276 CHAR8 *Ptr;
277 CHAR8 TestChar;
278 UINTN Count;
279
280 Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);
281
282 Count = 0;
283 do {
284 Ptr = PacketData;
285
286 if (Timeout-- == 0) {
287 // Only try a finite number of times so we don't get stuck in the loop
288 return Count;
289 }
290
291 // Packet prefix
292 GdbPutChar ('$');
293
294 for (CheckSum = 0, Count = 0; *Ptr != '\0'; Ptr++, Count++) {
295 GdbPutChar (*Ptr);
296 CheckSum = CheckSum + *Ptr;
297 }
298
299 // Packet terminating character and checksum
300 GdbPutChar ('#');
301 GdbPutChar (mHexToStr[CheckSum >> 4]);
302 GdbPutChar (mHexToStr[CheckSum & 0x0F]);
303
304 TestChar = GdbGetChar ();
305 } while (TestChar != '+');
306
307 return Count;
308}
309
326UINTN
328 OUT CHAR8 *PacketData,
329 IN UINTN PacketDataSize
330 )
331{
332 UINT8 CheckSum;
333 UINTN Index;
334 CHAR8 Char;
335 CHAR8 SumString[3];
336 CHAR8 TestChar;
337
338 ZeroMem (PacketData, PacketDataSize);
339
340 for ( ; ;) {
341 // wait for the start of a packet
342 TestChar = GdbGetChar ();
343 while (TestChar != '$') {
344 TestChar = GdbGetChar ();
345 }
346
347retry:
348 for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {
349 Char = GdbGetChar ();
350 if (Char == '$') {
351 goto retry;
352 }
353
354 if (Char == '#') {
355 break;
356 }
357
358 PacketData[Index] = Char;
359 CheckSum = CheckSum + Char;
360 }
361
362 PacketData[Index] = '\0';
363
364 if (Index == PacketDataSize) {
365 continue;
366 }
367
368 SumString[0] = GdbGetChar ();
369 SumString[1] = GdbGetChar ();
370 SumString[2] = '\0';
371
372 if (AsciiStrHexToUintn (SumString) == CheckSum) {
373 // Ack: Success
374 GdbPutChar ('+');
375
376 // Null terminate the callers string
377 PacketData[Index] = '\0';
378 return Index;
379 } else {
380 // Ack: Failure
381 GdbPutChar ('-');
382 }
383 }
384
385 // return 0;
386}
387
392VOID
394 IN CHAR8 *Buf
395 )
396{
397 *Buf = '\0';
398}
399
407INTN
409 IN CHAR8 Char
410 )
411{
412 if ((Char >= 'A') && (Char <= 'F')) {
413 return Char - 'A' + 10;
414 } else if ((Char >= 'a') && (Char <= 'f')) {
415 return Char - 'a' + 10;
416 } else if ((Char >= '0') && (Char <= '9')) {
417 return Char - '0';
418 } else {
419 // if not a hex value, return a negative value
420 return -1;
421 }
422}
423
424// 'E' + the biggest error number is 255, so its 2 hex digits + buffer end
425CHAR8 *gError = "E__";
426
434VOID
435EFIAPI
437 IN UINT8 ErrorNum
438 )
439{
440 //
441 // Replace _, or old data, with current errno
442 //
443 gError[1] = mHexToStr[ErrorNum >> 4];
444 gError[2] = mHexToStr[ErrorNum & 0x0f];
445
446 SendPacket (gError); // send buffer
447}
448
452VOID
453EFIAPI
455 VOID
456 )
457{
458 SendPacket ("OK"); // send buffer
459}
460
464VOID
465EFIAPI
467 VOID
468 )
469{
470 SendPacket ("");
471}
472
479VOID
481 IN EFI_SYSTEM_CONTEXT SystemContext,
482 IN UINT8 GdbExceptionType
483 )
484{
485 CHAR8 TSignalBuffer[128];
486 CHAR8 *TSignalPtr;
487 UINTN BreakpointDetected;
488 BREAK_TYPE BreakType;
489 UINTN DataAddress;
490 CHAR8 *WatchStrPtr = NULL;
491 UINTN RegSize;
492
493 TSignalPtr = &TSignalBuffer[0];
494
495 // Construct TSignal packet
496 *TSignalPtr++ = 'T';
497
498 //
499 // replace _, or previous value, with Exception type
500 //
501 *TSignalPtr++ = mHexToStr[GdbExceptionType >> 4];
502 *TSignalPtr++ = mHexToStr[GdbExceptionType & 0x0f];
503
504 if (GdbExceptionType == GDB_SIGTRAP) {
505 if (gSymbolTableUpdate) {
506 //
507 // We can only send back on reason code. So if the flag is set it means the breakpoint is from our event handler
508 //
509 WatchStrPtr = "library:;";
510 while (*WatchStrPtr != '\0') {
511 *TSignalPtr++ = *WatchStrPtr++;
512 }
513
514 gSymbolTableUpdate = FALSE;
515 } else {
516 //
517 // possible n:r pairs
518 //
519
520 // Retrieve the breakpoint number
521 BreakpointDetected = GetBreakpointDetected (SystemContext);
522
523 // Figure out if the exception is happend due to watch, rwatch or awatch.
524 BreakType = GetBreakpointType (SystemContext, BreakpointDetected);
525
526 // INFO: rwatch is not supported due to the way IA32 debug registers work
527 if ((BreakType == DataWrite) || (BreakType == DataRead) || (BreakType == DataReadWrite)) {
528 // Construct n:r pair
529 DataAddress = GetBreakpointDataAddress (SystemContext, BreakpointDetected);
530
531 // Assign appropriate buffer to print particular watchpoint type
532 if (BreakType == DataWrite) {
533 WatchStrPtr = "watch";
534 } else if (BreakType == DataRead) {
535 WatchStrPtr = "rwatch";
536 } else if (BreakType == DataReadWrite) {
537 WatchStrPtr = "awatch";
538 }
539
540 while (*WatchStrPtr != '\0') {
541 *TSignalPtr++ = *WatchStrPtr++;
542 }
543
544 *TSignalPtr++ = ':';
545
546 // Set up series of bytes in big-endian byte order. "awatch" won't work with little-endian byte order.
547 RegSize = REG_SIZE;
548 while (RegSize > 0) {
549 RegSize = RegSize-4;
550 *TSignalPtr++ = mHexToStr[(UINT8)(DataAddress >> RegSize) & 0xf];
551 }
552
553 // Always end n:r pair with ';'
554 *TSignalPtr++ = ';';
555 }
556 }
557 }
558
559 *TSignalPtr = '\0';
560
561 SendPacket (TSignalBuffer);
562}
563
570UINT8
572 IN EFI_EXCEPTION_TYPE EFIExceptionType
573 )
574{
575 UINTN Index;
576
577 for (Index = 0; Index < MaxEfiException (); Index++) {
578 if (gExceptionType[Index].Exception == EFIExceptionType) {
579 return gExceptionType[Index].SignalNo;
580 }
581 }
582
583 return GDB_SIGTRAP; // this is a GDB trap
584}
585
591VOID
592EFIAPI
594 CHAR8 *PacketData
595 )
596{
597 UINTN Address;
598 UINTN Length;
599 CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars
600 CHAR8 *AddrBufPtr; // pointer to the address buffer
601 CHAR8 *InBufPtr;
602
603 AddrBufPtr = AddressBuffer;
604 InBufPtr = &PacketData[1];
605 while (*InBufPtr != ',') {
606 *AddrBufPtr++ = *InBufPtr++;
607 }
608
609 *AddrBufPtr = '\0';
610
611 InBufPtr++; // this skips ',' in the buffer
612
613 /* Error checking */
614 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
615 Print ((CHAR16 *)L"Address is too long\n");
616 SendError (GDB_EBADMEMADDRBUFSIZE);
617 return;
618 }
619
620 // 2 = 'm' + ','
621 if (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {
622 Print ((CHAR16 *)L"Length is too long\n");
623 SendError (GDB_EBADMEMLENGTH);
624 return;
625 }
626
627 Address = AsciiStrHexToUintn (AddressBuffer);
628 Length = AsciiStrHexToUintn (InBufPtr);
629
630 TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);
631}
632
638VOID
639EFIAPI
641 IN CHAR8 *PacketData
642 )
643{
644 UINTN Address;
645 UINTN Length;
646 UINTN MessageLength;
647 CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars
648 CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars
649 CHAR8 *AddrBufPtr; // pointer to the Address buffer
650 CHAR8 *LengthBufPtr; // pointer to the Length buffer
651 CHAR8 *InBufPtr;
652
653 AddrBufPtr = AddressBuffer;
654 LengthBufPtr = LengthBuffer;
655 InBufPtr = &PacketData[1];
656
657 while (*InBufPtr != ',') {
658 *AddrBufPtr++ = *InBufPtr++;
659 }
660
661 *AddrBufPtr = '\0';
662
663 InBufPtr++; // this skips ',' in the buffer
664
665 while (*InBufPtr != ':') {
666 *LengthBufPtr++ = *InBufPtr++;
667 }
668
669 *LengthBufPtr = '\0';
670
671 InBufPtr++; // this skips ':' in the buffer
672
673 Address = AsciiStrHexToUintn (AddressBuffer);
674 Length = AsciiStrHexToUintn (LengthBuffer);
675
676 /* Error checking */
677
678 // Check if Address is not too long.
679 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
680 Print ((CHAR16 *)L"Address too long..\n");
681 SendError (GDB_EBADMEMADDRBUFSIZE);
682 return;
683 }
684
685 // Check if message length is not too long
686 if (AsciiStrLen (LengthBuffer) >= MAX_LENGTH_SIZE) {
687 Print ((CHAR16 *)L"Length too long..\n");
688 SendError (GDB_EBADMEMLENGBUFSIZE);
689 return;
690 }
691
692 // Check if Message is not too long/short.
693 // 3 = 'M' + ',' + ':'
694 MessageLength = (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - AsciiStrLen (LengthBuffer) - 3);
695 if (MessageLength != (2*Length)) {
696 // Message too long/short. New data is not the right size.
697 SendError (GDB_EBADMEMDATASIZE);
698 return;
699 }
700
701 TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);
702}
703
718UINTN
720 IN CHAR8 *PacketData,
721 OUT UINTN *Type,
722 OUT UINTN *Address,
723 OUT UINTN *Length
724 )
725{
726 CHAR8 AddressBuffer[MAX_ADDR_SIZE];
727 CHAR8 *AddressBufferPtr;
728 CHAR8 *PacketDataPtr;
729
730 PacketDataPtr = &PacketData[1];
731 AddressBufferPtr = AddressBuffer;
732
733 *Type = AsciiStrHexToUintn (PacketDataPtr);
734
735 // Breakpoint/watchpoint type should be between 0 to 4
736 if (*Type > 4) {
737 Print ((CHAR16 *)L"Type is invalid\n");
738 return 22; // EINVAL: Invalid argument.
739 }
740
741 // Skip ',' in the buffer.
742 while (*PacketDataPtr++ != ',') {
743 }
744
745 // Parse Address information
746 while (*PacketDataPtr != ',') {
747 *AddressBufferPtr++ = *PacketDataPtr++;
748 }
749
750 *AddressBufferPtr = '\0';
751
752 // Check if Address is not too long.
753 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {
754 Print ((CHAR16 *)L"Address too long..\n");
755 return 40; // EMSGSIZE: Message size too long.
756 }
757
758 *Address = AsciiStrHexToUintn (AddressBuffer);
759
760 PacketDataPtr++; // This skips , in the buffer
761
762 // Parse Length information
763 *Length = AsciiStrHexToUintn (PacketDataPtr);
764
765 // Length should be 1, 2 or 4 bytes
766 if (*Length > 4) {
767 Print ((CHAR16 *)L"Length is invalid\n");
768 return 22; // EINVAL: Invalid argument
769 }
770
771 return 0; // 0 = No error
772}
773
774UINTN
775gXferObjectReadResponse (
776 IN CHAR8 Type,
777 IN CHAR8 *Str
778 )
779{
780 CHAR8 *OutBufPtr; // pointer to the output buffer
781 CHAR8 Char;
782 UINTN Count;
783
784 // Response starts with 'm' or 'l' if it is the end
785 OutBufPtr = gOutBuffer;
786 *OutBufPtr++ = Type;
787 Count = 1;
788
789 // Binary data encoding
790 OutBufPtr = gOutBuffer;
791 while (*Str != '\0') {
792 Char = *Str++;
793 if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {
794 // escape character
795 *OutBufPtr++ = 0x7d;
796
797 Char ^= 0x20;
798 }
799
800 *OutBufPtr++ = Char;
801 Count++;
802 }
803
804 *OutBufPtr = '\0'; // the end of the buffer
805 SendPacket (gOutBuffer);
806
807 return Count;
808}
809
836VOID *
837EFIAPI
839 IN VOID *Pe32Data,
840 OUT VOID **DebugBase
841 )
842{
843 EFI_IMAGE_DOS_HEADER *DosHdr;
845 EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
847 UINTN DirCount;
848 VOID *CodeViewEntryPointer;
849 INTN TEImageAdjust;
850 UINT32 NumberOfRvaAndSizes;
851 UINT16 Magic;
852 UINTN SizeOfHeaders;
853
854 ASSERT (Pe32Data != NULL);
855
856 TEImageAdjust = 0;
857 DirectoryEntry = NULL;
858 DebugEntry = NULL;
859 NumberOfRvaAndSizes = 0;
860 SizeOfHeaders = 0;
861
862 DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
863 if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
864 //
865 // DOS image header is present, so read the PE header after the DOS image header.
866 //
867 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN)Pe32Data + (UINTN)((DosHdr->e_lfanew) & 0x0ffff));
868 } else {
869 //
870 // DOS image header is not present, so PE header is at the image base.
871 //
872 Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
873 }
874
875 if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
876 if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
877 DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
878 TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
879 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Hdr.Te +
880 Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress +
881 TEImageAdjust);
882 }
883
884 SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN)Hdr.Te->BaseOfCode - (UINTN)Hdr.Te->StrippedSize;
885
886 // __APPLE__ check this math...
887 *DebugBase = ((CHAR8 *)Pe32Data) - TEImageAdjust;
888 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
889 *DebugBase = Pe32Data;
890
891 //
892 // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
893 // It is due to backward-compatibility, for some system might
894 // generate PE32+ image with PE32 Magic.
895 //
896 switch (Hdr.Pe32->FileHeader.Machine) {
898 //
899 // Assume PE32 image with IA32 Machine field.
900 //
902 break;
905 //
906 // Assume PE32+ image with X64 or IPF Machine field
907 //
909 break;
910 default:
911 //
912 // For unknown Machine field, use Magic in optional Header
913 //
914 Magic = Hdr.Pe32->OptionalHeader.Magic;
915 }
916
918 //
919 // Use PE32 offset get Debug Directory Entry
920 //
921 SizeOfHeaders = Hdr.Pe32->OptionalHeader.SizeOfHeaders;
922 NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
923 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
924 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress);
925 } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
926 //
927 // Use PE32+ offset get Debug Directory Entry
928 //
929 SizeOfHeaders = Hdr.Pe32Plus->OptionalHeader.SizeOfHeaders;
930 NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
931 DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
932 DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN)Pe32Data + DirectoryEntry->VirtualAddress);
933 }
934
935 if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
936 DirectoryEntry = NULL;
937 DebugEntry = NULL;
938 }
939 } else {
940 return NULL;
941 }
942
943 if ((DebugEntry == NULL) || (DirectoryEntry == NULL)) {
944 return NULL;
945 }
946
947 for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
948 if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
949 if (DebugEntry->SizeOfData > 0) {
950 CodeViewEntryPointer = (VOID *)((UINTN)DebugEntry->RVA + ((UINTN)Pe32Data) + (UINTN)TEImageAdjust);
951 switch (*(UINT32 *)CodeViewEntryPointer) {
953 return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
955 return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
957 *DebugBase = (VOID *)(UINTN)((UINTN)DebugBase - SizeOfHeaders);
958 return (VOID *)((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
959 default:
960 break;
961 }
962 }
963 }
964 }
965
966 (void)SizeOfHeaders;
967 return NULL;
968}
969
1003VOID
1005 IN UINTN Offset,
1006 IN UINTN Length
1007 )
1008{
1009 VOID *LoadAddress;
1010 CHAR8 *Pdb;
1011 UINTN Size;
1012
1013 if (Offset != gPacketqXferLibraryOffset) {
1014 SendError (GDB_EINVALIDARG);
1015 Print (L"\nqXferLibrary (%d, %d) != %d\n", Offset, Length, gPacketqXferLibraryOffset);
1016
1017 // Force a retry from the beginning
1018 gPacketqXferLibraryOffset = 0;
1019
1020 return;
1021 }
1022
1023 if (Offset == 0) {
1024 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");
1025
1026 // The owner of the table may have had to ralloc it so grab a fresh copy every time
1027 // we assume qXferLibrary will get called over and over again until the entire XML table is
1028 // returned in a tight loop. Since we are in the debugger the table should not get updated
1029 gDebugTable = gDebugImageTableHeader->EfiDebugImageInfoTable;
1030 gEfiDebugImageTableEntry = 0;
1031 return;
1032 }
1033
1034 if (gDebugTable != NULL) {
1035 for ( ; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) {
1036 if (gDebugTable->NormalImage != NULL) {
1037 if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&
1038 (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL))
1039 {
1041 gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase,
1042 &LoadAddress
1043 );
1044 if (Pdb != NULL) {
1045 Size = AsciiSPrint (
1046 gXferLibraryBuffer,
1047 sizeof (gXferLibraryBuffer),
1048 " <library name=\"%a\"><segment address=\"0x%p\"/></library>\n",
1049 Pdb,
1050 LoadAddress
1051 );
1052 if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) {
1053 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer);
1054
1055 // Update loop variables so we are in the right place when we get back
1056 gEfiDebugImageTableEntry++;
1057 gDebugTable++;
1058 return;
1059 } else {
1060 // We could handle <library> entires larger than sizeof (gXferLibraryBuffer) here if
1061 // needed by breaking up into N packets
1062 // "<library name=\"%s
1063 // the rest of the string (as many packets as required
1064 // \"><segment address=\"%d\"/></library> (fixed size)
1065 //
1066 // But right now we just skip any entry that is too big
1067 }
1068 }
1069 }
1070 }
1071 }
1072 }
1073
1074 gXferObjectReadResponse ('l', "</library-list>\n");
1075 gPacketqXferLibraryOffset = 0;
1076 return;
1077}
1078
1086VOID
1087EFIAPI
1089 IN EFI_EXCEPTION_TYPE ExceptionType,
1090 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1091 )
1092{
1093 UINT8 GdbExceptionType;
1094 CHAR8 *Ptr;
1095
1096 if (ValidateException (ExceptionType, SystemContext) == FALSE) {
1097 return;
1098 }
1099
1100 RemoveSingleStep (SystemContext);
1101
1102 GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);
1103 GdbSendTSignal (SystemContext, GdbExceptionType);
1104
1105 for ( ; ; ) {
1106 ReceivePacket (gInBuffer, MAX_BUF_SIZE);
1107
1108 switch (gInBuffer[0]) {
1109 case '?':
1110 GdbSendTSignal (SystemContext, GdbExceptionType);
1111 break;
1112
1113 case 'c':
1114 ContinueAtAddress (SystemContext, gInBuffer);
1115 return;
1116
1117 case 'g':
1118 ReadGeneralRegisters (SystemContext);
1119 break;
1120
1121 case 'G':
1122 WriteGeneralRegisters (SystemContext, gInBuffer);
1123 break;
1124
1125 case 'H':
1126 // Return "OK" packet since we don't have more than one thread.
1127 SendSuccess ();
1128 break;
1129
1130 case 'm':
1131 ReadFromMemory (gInBuffer);
1132 break;
1133
1134 case 'M':
1135 WriteToMemory (gInBuffer);
1136 break;
1137
1138 case 'P':
1139 WriteNthRegister (SystemContext, gInBuffer);
1140 break;
1141
1142 //
1143 // Still debugging this code. Not used in Darwin
1144 //
1145 case 'q':
1146 // General Query Packets
1147 if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {
1148 // return what we currently support, we don't parse what gdb supports
1149 AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);
1150 SendPacket (gOutBuffer);
1151 } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {
1152 // ‘qXfer:libraries:read::offset,length
1153 // gInBuffer[22] is offset string, ++Ptr is length string’
1154 for (Ptr = &gInBuffer[22]; *Ptr != ','; Ptr++) {
1155 }
1156
1157 // Not sure if multi-radix support is required. Currently only support decimal
1158 QxferLibrary (AsciiStrHexToUintn (&gInBuffer[22]), AsciiStrHexToUintn (++Ptr));
1159 }
1160
1161 if (AsciiStrnCmp (gInBuffer, "qOffsets", 10) == 0) {
1162 AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "Text=1000;Data=f000;Bss=f000");
1163 SendPacket (gOutBuffer);
1164 } else {
1165 // Send empty packet
1167 }
1168
1169 break;
1170
1171 case 's':
1172 SingleStep (SystemContext, gInBuffer);
1173 return;
1174
1175 case 'z':
1176 RemoveBreakPoint (SystemContext, gInBuffer);
1177 break;
1178
1179 case 'Z':
1180 InsertBreakPoint (SystemContext, gInBuffer);
1181 break;
1182
1183 default:
1184 // Send empty packet
1186 break;
1187 }
1188 }
1189}
1190
1197VOID
1198EFIAPI
1200 IN OUT EFI_SYSTEM_CONTEXT SystemContext
1201 )
1202{
1203 //
1204 // gCtrlCBreakFlag may have been set from a previous F response package
1205 // and we set the global as we need to process it at a point where we
1206 // can update the system context. If we are in the middle of processing
1207 // a F Packet it is not safe to read the GDB serial stream so we need
1208 // to skip it on this check
1209 //
1210 if (!gCtrlCBreakFlag && !gProcessingFPacket) {
1211 //
1212 // Ctrl-C was not pending so grab any pending characters and see if they
1213 // are a Ctrl-c (0x03). If so set the Ctrl-C global.
1214 //
1215 while (TRUE) {
1216 if (!GdbIsCharAvailable ()) {
1217 //
1218 // No characters are pending so exit the loop
1219 //
1220 break;
1221 }
1222
1223 if (GdbGetChar () == 0x03) {
1224 gCtrlCBreakFlag = TRUE;
1225 //
1226 // We have a ctrl-c so exit the loop
1227 //
1228 break;
1229 }
1230 }
1231 }
1232
1233 if (gCtrlCBreakFlag) {
1234 //
1235 // Update the context to force a single step trap when we exit the GDB
1236 // stub. This will transfer control to GdbExceptionHandler () and let
1237 // us break into the program. We don't want to break into the GDB stub.
1238 //
1239 AddSingleStep (SystemContext);
1240 gCtrlCBreakFlag = FALSE;
1241 }
1242}
UINT64 UINTN
INT64 INTN
UINTN MaxEfiException(VOID)
Definition: Processor.c:77
VOID EFIAPI RemoveBreakPoint(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData)
Definition: Processor.c:608
VOID EFIAPI WriteGeneralRegisters(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *InBuffer)
Definition: Processor.c:330
VOID EFIAPI InsertBreakPoint(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData)
Definition: Processor.c:575
BOOLEAN CheckIsa(IN EFI_INSTRUCTION_SET_ARCHITECTURE Isa)
Definition: Processor.c:105
VOID EFIAPI ReadGeneralRegisters(IN EFI_SYSTEM_CONTEXT SystemContext)
Definition: Processor.c:216
VOID RemoveSingleStep(IN EFI_SYSTEM_CONTEXT SystemContext)
Definition: Processor.c:417
VOID AddSingleStep(IN EFI_SYSTEM_CONTEXT SystemContext)
Definition: Processor.c:386
VOID EFIAPI SingleStep(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData)
Definition: Processor.c:462
VOID WriteNthRegister(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *InBuffer)
Definition: Processor.c:292
VOID EFIAPI ContinueAtAddress(IN EFI_SYSTEM_CONTEXT SystemContext, IN CHAR8 *PacketData)
Definition: Processor.c:444
UINTN EFIAPI AsciiStrLen(IN CONST CHAR8 *String)
Definition: String.c:641
INTN EFIAPI AsciiStrnCmp(IN CONST CHAR8 *FirstString, IN CONST CHAR8 *SecondString, IN UINTN Length)
Definition: String.c:872
UINTN EFIAPI AsciiStrHexToUintn(IN CONST CHAR8 *String)
Definition: String.c:1104
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
VOID EFIAPI FreePool(IN VOID *Buffer)
CHAR8 EFIAPI GdbGetChar(VOID)
BOOLEAN EFIAPI GdbIsCharAvailable(VOID)
VOID EFIAPI GdbPutChar(IN CHAR8 Char)
UINT8 ConvertEFItoGDBtype(IN EFI_EXCEPTION_TYPE EFIExceptionType)
Definition: GdbStub.c:571
VOID EFIAPI WriteToMemory(IN CHAR8 *PacketData)
Definition: GdbStub.c:640
VOID EFIAPI ReadFromMemory(CHAR8 *PacketData)
Definition: GdbStub.c:593
VOID QxferLibrary(IN UINTN Offset, IN UINTN Length)
Definition: GdbStub.c:1004
UINTN ParseBreakpointPacket(IN CHAR8 *PacketData, OUT UINTN *Type, OUT UINTN *Address, OUT UINTN *Length)
Definition: GdbStub.c:719
VOID EFIAPI SendNotSupported(VOID)
Definition: GdbStub.c:466
VOID TransferFromMemToOutBufAndSend(IN UINTN Length, IN unsigned char *Address)
Definition: GdbStub.c:215
VOID EFIAPI GdbExceptionHandler(IN EFI_EXCEPTION_TYPE ExceptionType, IN OUT EFI_SYSTEM_CONTEXT SystemContext)
Definition: GdbStub.c:1088
UINTN SendPacket(IN CHAR8 *PacketData)
Definition: GdbStub.c:270
EFI_STATUS EFIAPI GdbStubEntry(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable)
Definition: GdbStub.c:65
VOID EFIAPI SendSuccess(VOID)
Definition: GdbStub.c:454
VOID GdbSendTSignal(IN EFI_SYSTEM_CONTEXT SystemContext, IN UINT8 GdbExceptionType)
Definition: GdbStub.c:480
VOID EmptyBuffer(IN CHAR8 *Buf)
Definition: GdbStub.c:393
UINTN ReceivePacket(OUT CHAR8 *PacketData, IN UINTN PacketDataSize)
Definition: GdbStub.c:327
INTN HexCharToInt(IN CHAR8 Char)
Definition: GdbStub.c:408
VOID *EFIAPI PeCoffLoaderGetDebuggerInfo(IN VOID *Pe32Data, OUT VOID **DebugBase)
Definition: GdbStub.c:838
VOID TransferFromInBufToMem(IN UINTN Length, IN unsigned char *Address, IN CHAR8 *NewData)
Definition: GdbStub.c:182
VOID EFIAPI SendError(IN UINT8 ErrorNum)
Definition: GdbStub.c:436
VOID EFIAPI GdbPeriodicCallBack(IN OUT EFI_SYSTEM_CONTEXT SystemContext)
Definition: GdbStub.c:1199
VOID GdbInitializeSerialConsole(VOID)
Definition: SerialIo.c:498
UINTN EFIAPI AsciiSPrint(OUT CHAR8 *StartOfBuffer, IN UINTN BufferSize, IN CONST CHAR8 *FormatString,...)
Definition: PrintLib.c:813
#define NULL
Definition: Base.h:319
#define CONST
Definition: Base.h:259
#define TRUE
Definition: Base.h:301
#define FALSE
Definition: Base.h:307
#define IN
Definition: Base.h:279
#define OUT
Definition: Base.h:284
#define GLOBAL_REMOVE_IF_UNREFERENCED
Definition: Base.h:48
#define ASSERT_EFI_ERROR(StatusParameter)
Definition: DebugLib.h:462
#define DEBUG(Expression)
Definition: DebugLib.h:434
INTN EFI_EXCEPTION_TYPE
Definition: DebugSupport.h:35
#define PcdGet32(TokenName)
Definition: PcdLib.h:362
#define PcdGetBool(TokenName)
Definition: PcdLib.h:401
#define CODEVIEW_SIGNATURE_NB10
Definition: PeImage.h:657
#define EFI_IMAGE_DEBUG_TYPE_CODEVIEW
The Visual C++ debug information.
Definition: PeImage.h:651
#define CODEVIEW_SIGNATURE_RSDS
Definition: PeImage.h:671
#define EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC
Definition: PeImage.h:143
#define EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC
Definition: PeImage.h:194
#define CODEVIEW_SIGNATURE_MTOC
Definition: PeImage.h:687
#define EFI_IMAGE_MACHINE_IA32
Definition: UefiBaseType.h:218
RETURN_STATUS EFI_STATUS
Definition: UefiBaseType.h:29
VOID * EFI_EVENT
Definition: UefiBaseType.h:37
#define EFI_IMAGE_MACHINE_IA64
Definition: UefiBaseType.h:223
#define EFI_IMAGE_MACHINE_X64
Definition: UefiBaseType.h:233
VOID * EFI_HANDLE
Definition: UefiBaseType.h:33
#define EFI_SUCCESS
Definition: UefiBaseType.h:112
EFI_BOOT_SERVICES * gBS
EFI_STATUS EFIAPI EfiGetSystemConfigurationTable(IN EFI_GUID *TableGuid, OUT VOID **Table)
Definition: UefiLib.c:82
UINTN EFIAPI Print(IN CONST CHAR16 *Format,...)
Definition: UefiLibPrint.c:113
@ ByProtocol
Definition: UefiSpec.h:1518
EFI_INSTRUCTION_SET_ARCHITECTURE Isa
Definition: DebugSupport.h:946
EFI_LOADED_IMAGE_PROTOCOL * LoadedImageProtocolInstance
EFI_DEBUG_IMAGE_INFO * EfiDebugImageInfoTable
UINT32 RVA
The address of the debug data when loaded, relative to the image base.
Definition: PeImage.h:647
UINT32 e_lfanew
File address of new exe header.
Definition: PeImage.h:76
UINT16 e_magic
Magic number.
Definition: PeImage.h:58
VOID * ImageBase
The base address at which the image was loaded.
Definition: LoadedImage.h:67
UINT16 Signature
The signature for TE format = "VZ".
Definition: PeImage.h:781
UINT32 BaseOfCode
From original image – required for ITP debug.
Definition: PeImage.h:787
EFI_IMAGE_DATA_DIRECTORY DataDirectory[2]
Only base relocation and debug directory.
Definition: PeImage.h:789
UINT16 StrippedSize
Number of bytes we removed from the header.
Definition: PeImage.h:785