]> git.proxmox.com Git - mirror_edk2.git/blame - EmbeddedPkg/GdbStub/GdbStub.c
EmbeddedPkg: Fix various typos
[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
c6a72cd7 5 will blow out the stack. Serial IO calls DEBUG, debug calls Serial IO, ...\r
3402aac7 6\r
1e57a462 7\r
8 Copyright (c) 2008 - 2009, Apple Inc. All rights reserved.<BR>\r
3402aac7 9\r
878b807a 10 SPDX-License-Identifier: BSD-2-Clause-Patent\r
1e57a462 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
3402aac7 26// Assume gdb does a "qXfer:libraries:read::offset,length" when it connects so we can default\r
1e57a462 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
3402aac7 56 as the real entry point for the image goes into a library that calls this\r
1e57a462 57 function.\r
58\r
3402aac7 59 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1e57a462 60 @param[in] SystemTable A pointer to the EFI System Table.\r
3402aac7 61\r
1e57a462 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
1e57a462 72{\r
3402aac7 73 EFI_STATUS Status;\r
1e57a462 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
6f711615 80\r
1e57a462 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
3402aac7 98\r
1e57a462 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
3402aac7 117\r
1e57a462 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
3402aac7 123\r
1e57a462 124 Status = DebugSupport->GetMaximumProcessorIndex (DebugSupport, &gMaxProcessorIndex);\r
125 ASSERT_EFI_ERROR (Status);\r
3402aac7 126\r
1e57a462 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
3402aac7 129\r
1e57a462 130 // Call processor-specific init routine\r
6f711615 131 InitializeProcessor ();\r
1e57a462 132\r
133 for (Processor = 0; Processor <= gMaxProcessorIndex; Processor++) {\r
1e57a462 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
3402aac7 144\r
1e57a462 145 //\r
146 // This even fires every time an image is added. This allows the stub to know when gdb needs\r
3402aac7 147 // to update the symbol table.\r
1e57a462 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
6f711615 159 // Register for protocol notifications on this event\r
1e57a462 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
3402aac7 168\r
1e57a462 169 if (PcdGetBool (PcdGdbSerial)) {\r
170 GdbInitializeSerialConsole ();\r
171 }\r
3402aac7 172\r
1e57a462 173 return EFI_SUCCESS;\r
174}\r
175\r
1e57a462 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
3402aac7 193\r
1e57a462 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
3402aac7 200 SendError (GDB_EBADMEMDATA);\r
1e57a462 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
3402aac7 236\r
1e57a462 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
3402aac7
RC
261\r
262 $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',\r
c6a72cd7 263 the packet terminating character '#' and the two digit checksum.\r
3402aac7
RC
264\r
265 If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up\r
c6a72cd7 266 in an infinite loop. This is so if you unplug the debugger code just keeps running\r
1e57a462 267\r
3402aac7
RC
268 @param PacketData Payload data for the packet\r
269\r
1e57a462 270\r
1e57a462 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
3402aac7 284\r
1e57a462 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
3402aac7 296\r
1e57a462 297 // Packet prefix\r
298 GdbPutChar ('$');\r
3402aac7 299\r
1e57a462 300 for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {\r
301 GdbPutChar (*Ptr);\r
302 CheckSum = CheckSum + *Ptr;\r
303 }\r
3402aac7
RC
304\r
305 // Packet terminating character and checksum\r
1e57a462 306 GdbPutChar ('#');\r
307 GdbPutChar (mHexToStr[CheckSum >> 4]);\r
308 GdbPutChar (mHexToStr[CheckSum & 0x0F]);\r
3402aac7 309\r
1e57a462 310 TestChar = GdbGetChar ();\r
311 } while (TestChar != '+');\r
3402aac7 312\r
1e57a462 313 return Count;\r
314}\r
315\r
316/**\r
317 Receive a GDB Remote Serial Protocol Packet\r
3402aac7
RC
318\r
319 $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',\r
c6a72cd7 320 the packet terminating character '#' and the two digit checksum.\r
3402aac7 321\r
4f0624e8 322 If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.\r
1e57a462 323 (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)\r
3402aac7 324\r
1e57a462 325 If an ack '+' is not sent resend the packet\r
326\r
3402aac7 327 @param PacketData Payload data for the packet\r
1e57a462 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
3402aac7 343\r
1e57a462 344 ZeroMem (PacketData, PacketDataSize);\r
3402aac7 345\r
1e57a462 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
3402aac7 352\r
1e57a462 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
3402aac7 372 SumString[0] = GdbGetChar ();\r
1e57a462 373 SumString[1] = GdbGetChar ();\r
374 SumString[2] = '\0';\r
3402aac7 375\r
1e57a462 376 if (AsciiStrHexToUintn (SumString) == CheckSum) {\r
377 // Ack: Success\r
378 GdbPutChar ('+');\r
3402aac7 379\r
1e57a462 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
3402aac7 388\r
1e57a462 389 //return 0;\r
390}\r
391\r
392\r
393/**\r
3402aac7 394 Empties the given buffer\r
1e57a462 395 @param Buf pointer to the first element in buffer to be emptied\r
396 **/\r
397VOID\r
3402aac7 398EmptyBuffer (\r
1e57a462 399 IN CHAR8 *Buf\r
400 )\r
3402aac7 401{\r
1e57a462 402 *Buf = '\0';\r
403}\r
404\r
405\r
406/**\r
407 Converts an 8-bit Hex Char into a INTN.\r
3402aac7 408\r
1e57a462 409 @param Char the hex character to be converted into UINTN\r
c6a72cd7 410 @retval a INTN, from 0 to 15, that corresponds to Char\r
1e57a462 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
3402aac7 425 return -1;\r
1e57a462 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
3402aac7 436\r
1e57a462 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
3402aac7 450\r
1e57a462 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
3402aac7 463 )\r
1e57a462 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
3402aac7
RC
472VOID\r
473EFIAPI\r
1e57a462 474SendNotSupported (\r
3402aac7
RC
475 VOID\r
476 )\r
6f711615 477{\r
1e57a462 478 SendPacket ("");\r
479}\r
480\r
481\r
1e57a462 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
3402aac7 484\r
1e57a462 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
3402aac7 510 *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4];\r
1e57a462 511 *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];\r
3402aac7 512\r
1e57a462 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
3402aac7 528 //\r
1e57a462 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
3402aac7 534 BreakType = GetBreakpointType (SystemContext, BreakpointDetected);\r
1e57a462 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
3402aac7 538\r
1e57a462 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
3402aac7 556\r
1e57a462 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
3402aac7 572 SendPacket (TSignalBuffer);\r
1e57a462 573}\r
574\r
575\r
576/**\r
577 Translates the EFI mapping to GDB mapping\r
3402aac7 578\r
1e57a462 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
3402aac7 583ConvertEFItoGDBtype (\r
1e57a462 584 IN EFI_EXCEPTION_TYPE EFIExceptionType\r
585 )\r
3402aac7 586{\r
6f711615 587 UINTN Index;\r
3402aac7 588\r
6f711615 589 for (Index = 0; Index < MaxEfiException () ; Index++) {\r
590 if (gExceptionType[Index].Exception == EFIExceptionType) {\r
591 return gExceptionType[Index].SignalNo;\r
1e57a462 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
c6a72cd7 599 Find the Length of the area to read and the start address. Finally, pass them to\r
3402aac7 600 another function, TransferFromMemToOutBufAndSend, that will read from that memory space and\r
1e57a462 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
3402aac7 615\r
1e57a462 616 AddrBufPtr = AddressBuffer;\r
617 InBufPtr = &PacketData[1];\r
618 while (*InBufPtr != ',') {\r
619 *AddrBufPtr++ = *InBufPtr++;\r
620 }\r
621 *AddrBufPtr = '\0';\r
3402aac7 622\r
1e57a462 623 InBufPtr++; // this skips ',' in the buffer\r
3402aac7 624\r
1e57a462 625 /* Error checking */\r
6f711615 626 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
1e57a462 627 Print((CHAR16 *)L"Address is too long\n");\r
3402aac7 628 SendError (GDB_EBADMEMADDRBUFSIZE);\r
1e57a462 629 return;\r
630 }\r
3402aac7 631\r
1e57a462 632 // 2 = 'm' + ','\r
6f711615 633 if (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {\r
1e57a462 634 Print((CHAR16 *)L"Length is too long\n");\r
3402aac7 635 SendError (GDB_EBADMEMLENGTH);\r
1e57a462 636 return;\r
637 }\r
3402aac7 638\r
1e57a462 639 Address = AsciiStrHexToUintn (AddressBuffer);\r
640 Length = AsciiStrHexToUintn (InBufPtr);\r
3402aac7 641\r
1e57a462 642 TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);\r
643}\r
644\r
645\r
646/** "M addr,length :XX..."\r
c6a72cd7 647 Find the Length of the area in bytes to write and the start address. Finally, pass them to\r
1e57a462 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
3402aac7 665\r
1e57a462 666 AddrBufPtr = AddressBuffer;\r
667 LengthBufPtr = LengthBuffer;\r
668 InBufPtr = &PacketData[1];\r
3402aac7 669\r
1e57a462 670 while (*InBufPtr != ',') {\r
671 *AddrBufPtr++ = *InBufPtr++;\r
672 }\r
673 *AddrBufPtr = '\0';\r
3402aac7 674\r
1e57a462 675 InBufPtr++; // this skips ',' in the buffer\r
3402aac7 676\r
1e57a462 677 while (*InBufPtr != ':') {\r
678 *LengthBufPtr++ = *InBufPtr++;\r
679 }\r
680 *LengthBufPtr = '\0';\r
3402aac7 681\r
1e57a462 682 InBufPtr++; // this skips ':' in the buffer\r
3402aac7 683\r
1e57a462 684 Address = AsciiStrHexToUintn (AddressBuffer);\r
685 Length = AsciiStrHexToUintn (LengthBuffer);\r
3402aac7 686\r
1e57a462 687 /* Error checking */\r
3402aac7 688\r
1e57a462 689 //Check if Address is not too long.\r
6f711615 690 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
1e57a462 691 Print ((CHAR16 *)L"Address too long..\n");\r
3402aac7 692 SendError (GDB_EBADMEMADDRBUFSIZE);\r
1e57a462 693 return;\r
694 }\r
3402aac7 695\r
1e57a462 696 //Check if message length is not too long\r
6f711615 697 if (AsciiStrLen (LengthBuffer) >= MAX_LENGTH_SIZE) {\r
1e57a462 698 Print ((CHAR16 *)L"Length too long..\n");\r
3402aac7 699 SendError (GDB_EBADMEMLENGBUFSIZE);\r
1e57a462 700 return;\r
701 }\r
3402aac7 702\r
1e57a462 703 // Check if Message is not too long/short.\r
704 // 3 = 'M' + ',' + ':'\r
6f711615 705 MessageLength = (AsciiStrLen (PacketData) - AsciiStrLen (AddressBuffer) - AsciiStrLen (LengthBuffer) - 3);\r
1e57a462 706 if (MessageLength != (2*Length)) {\r
707 //Message too long/short. New data is not the right size.\r
3402aac7 708 SendError (GDB_EBADMEMDATASIZE);\r
1e57a462 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
6f711615 761 if (AsciiStrLen (AddressBuffer) >= MAX_ADDR_SIZE) {\r
1e57a462 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
6f711615 792 // Response starts with 'm' or 'l' if it is the end\r
1e57a462 793 OutBufPtr = gOutBuffer;\r
794 *OutBufPtr++ = Type;\r
795 Count = 1;\r
796\r
3402aac7 797 // Binary data encoding\r
1e57a462 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
3402aac7 813\r
1e57a462 814 return Count;\r
815}\r
816\r
817\r
818/**\r
3402aac7
RC
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
1e57a462 821 right as there is no way to pad the Mach-O for the size of the PE/COFF header.\r
3402aac7
RC
822\r
823\r
1e57a462 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
3402aac7 841 valid.\r
1e57a462 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
3402aac7 892\r
1e57a462 893 // __APPLE__ check this math...\r
894 *DebugBase = ((CHAR8 *)Pe32Data) - TEImageAdjust;\r
895 } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {\r
3402aac7 896\r
1e57a462 897 *DebugBase = Pe32Data;\r
3402aac7
RC
898\r
899\r
1e57a462 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
c6a72cd7 921 // For unknown Machine field, use Magic in optional Header\r
1e57a462 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
3402aac7 980/**\r
1e57a462 981 Process "qXfer:object:read:annex:offset,length" request.\r
3402aac7
RC
982\r
983 Returns an XML document that contains loaded libraries. In our case it is\r
6f711615 984 information in the EFI Debug Image Table converted into an XML document.\r
3402aac7
RC
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
1e57a462 988 keep calling until we say we are done. XML doc looks like:\r
3402aac7 989\r
1e57a462 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
3402aac7 995\r
6f711615 996 Since we can not allocate memory in interrupt context this module has\r
1e57a462 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
6f711615 1001 Each subsequent call will ask for the next available part of the document.\r
3402aac7 1002\r
1e57a462 1003 Note: The only variable size element in the XML is:\r
3402aac7 1004 " <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is\r
1e57a462 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
3402aac7
RC
1010 @param Length number of bytes to read starting at Offset\r
1011\r
1e57a462 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
3402aac7
RC
1026\r
1027 // Force a retry from the beginning\r
1e57a462 1028 gPacketqXferLibraryOffset = 0;\r
6f711615 1029\r
1e57a462 1030 return;\r
1031 }\r
1032\r
1033 if (Offset == 0) {\r
1034 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");\r
3402aac7 1035\r
1e57a462 1036 // The owner of the table may have had to ralloc it so grab a fresh copy every time\r
3402aac7 1037 // we assume qXferLibrary will get called over and over again until the entire XML table is\r
1e57a462 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
3402aac7 1043\r
1e57a462 1044 if (gDebugTable != NULL) {\r
1045 for (; gEfiDebugImageTableEntry < gDebugImageTableHeader->TableSize; gEfiDebugImageTableEntry++, gDebugTable++) {\r
1046 if (gDebugTable->NormalImage != NULL) {\r
3402aac7 1047 if ((gDebugTable->NormalImage->ImageInfoType == EFI_DEBUG_IMAGE_INFO_TYPE_NORMAL) &&\r
1e57a462 1048 (gDebugTable->NormalImage->LoadedImageProtocolInstance != NULL)) {\r
1049 Pdb = PeCoffLoaderGetDebuggerInfo (\r
3402aac7 1050 gDebugTable->NormalImage->LoadedImageProtocolInstance->ImageBase,\r
1e57a462 1051 &LoadAddress\r
1052 );\r
1053 if (Pdb != NULL) {\r
1054 Size = AsciiSPrint (\r
3402aac7
RC
1055 gXferLibraryBuffer,\r
1056 sizeof (gXferLibraryBuffer),\r
1057 " <library name=\"%a\"><segment address=\"0x%p\"/></library>\n",\r
1e57a462 1058 Pdb,\r
1059 LoadAddress\r
1060 );\r
1061 if ((Size != 0) && (Size != (sizeof (gXferLibraryBuffer) - 1))) {\r
1062 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', gXferLibraryBuffer);\r
3402aac7 1063\r
1e57a462 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
3402aac7 1069 // We could handle <library> entires larger than sizeof (gXferLibraryBuffer) here if\r
1e57a462 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
3402aac7 1077 }\r
1e57a462 1078 }\r
3402aac7 1079 }\r
1e57a462 1080 }\r
1081 }\r
3402aac7
RC
1082\r
1083\r
1e57a462 1084 gXferObjectReadResponse ('l', "</library-list>\n");\r
1085 gPacketqXferLibraryOffset = 0;\r
1086 return;\r
1087}\r
1088\r
1089\r
1090/**\r
c6a72cd7 1091 Exception Handler for GDB. It will be called for all exceptions\r
1e57a462 1092 registered via the gExceptionType[] array.\r
3402aac7 1093\r
1e57a462 1094 @param ExceptionType Exception that is being processed\r
3402aac7 1095 @param SystemContext Register content at time of the exception\r
1e57a462 1096 **/\r
1097VOID\r
1098EFIAPI\r
3402aac7
RC
1099GdbExceptionHandler (\r
1100 IN EFI_EXCEPTION_TYPE ExceptionType,\r
1101 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 1102 )\r
1103{\r
1104 UINT8 GdbExceptionType;\r
1105 CHAR8 *Ptr;\r
3402aac7
RC
1106\r
1107\r
6f711615 1108 if (ValidateException (ExceptionType, SystemContext) == FALSE) {\r
1e57a462 1109 return;\r
1110 }\r
1111\r
1112 RemoveSingleStep (SystemContext);\r
3402aac7 1113\r
1e57a462 1114 GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);\r
1115 GdbSendTSignal (SystemContext, GdbExceptionType);\r
3402aac7 1116\r
1e57a462 1117 for( ; ; ) {\r
1118 ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
3402aac7 1119\r
1e57a462 1120 switch (gInBuffer[0]) {\r
1121 case '?':\r
1122 GdbSendTSignal (SystemContext, GdbExceptionType);\r
1123 break;\r
3402aac7 1124\r
1e57a462 1125 case 'c':\r
3402aac7 1126 ContinueAtAddress (SystemContext, gInBuffer);\r
1e57a462 1127 return;\r
1128\r
1129 case 'g':\r
1130 ReadGeneralRegisters (SystemContext);\r
1131 break;\r
3402aac7 1132\r
1e57a462 1133 case 'G':\r
1134 WriteGeneralRegisters (SystemContext, gInBuffer);\r
1135 break;\r
3402aac7 1136\r
1e57a462 1137 case 'H':\r
3402aac7 1138 //Return "OK" packet since we don't have more than one thread.\r
1e57a462 1139 SendSuccess ();\r
1140 break;\r
3402aac7 1141\r
1e57a462 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
3402aac7 1157 case 'q':\r
1e57a462 1158 // General Query Packets\r
1159 if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {\r
c6a72cd7 1160 // return what we currently support, we don't parse what gdb supports\r
1e57a462 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
3402aac7 1167\r
1e57a462 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
3402aac7 1180 SingleStep (SystemContext, gInBuffer);\r
1e57a462 1181 return;\r
3402aac7 1182\r
1e57a462 1183 case 'z':\r
1184 RemoveBreakPoint (SystemContext, gInBuffer);\r
1185 break;\r
3402aac7 1186\r
1e57a462 1187 case 'Z':\r
1188 InsertBreakPoint (SystemContext, gInBuffer);\r
1189 break;\r
3402aac7
RC
1190\r
1191 default:\r
1e57a462 1192 //Send empty packet\r
1193 SendNotSupported ();\r
1194 break;\r
1195 }\r
1196 }\r
1197}\r
1198\r
1199\r
1200/**\r
3402aac7 1201 Periodic callback for GDB. This function is used to catch a ctrl-c or other\r
1e57a462 1202 break in type command from GDB.\r
3402aac7
RC
1203\r
1204 @param SystemContext Register content at time of the call\r
1e57a462 1205 **/\r
1206VOID\r
1207EFIAPI\r
3402aac7
RC
1208GdbPeriodicCallBack (\r
1209 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
1e57a462 1210 )\r
1211{\r
1212 //\r
3402aac7
RC
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
1e57a462 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
3402aac7
RC
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
1e57a462 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
3402aac7 1231\r
1e57a462 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
3402aac7 1241\r
1e57a462 1242 if (gCtrlCBreakFlag) {\r
1243 //\r
1244 // Update the context to force a single step trap when we exit the GDB\r
6f711615 1245 // stub. This will transfer control to GdbExceptionHandler () and let\r
1e57a462 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