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