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