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