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