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