EmbeddedPkg: Fix typos in comments
[mirror_edk2.git] / EmbeddedPkg / Library / GdbDebugAgent / GdbDebugAgent.c
CommitLineData
969eba7b 1/** @file\r
2 Debug Agent library implementition with empty functions.\r
3\r
60274cca
HT
4 Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>\r
5 This program and the accompanying materials\r
969eba7b 6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution. The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9\r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "GdbDebugAgent.h"\r
16\r
17\r
18UINTN gMaxProcessorIndex = 0;\r
19\r
20//\r
21// Buffers for basic gdb communication\r
22//\r
23CHAR8 gInBuffer[MAX_BUF_SIZE];\r
24CHAR8 gOutBuffer[MAX_BUF_SIZE];\r
25\r
26\r
27//\r
28// Globals for returning XML from qXfer:libraries:read packet\r
29//\r
30UINTN gPacketqXferLibraryOffset = 0;\r
31UINTN gEfiDebugImageTableEntry = 0;\r
32CHAR8 gXferLibraryBuffer[2000];\r
33\r
34GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 mHexToStr[] = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};\r
35\r
36\r
460616bd
AB
37// add-symbol-file c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll 0x80008360\r
38CHAR8 *qXferHack = "<library name=\"c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll\"><segment address=\"0x80008360\"/></library>";\r
969eba7b 39\r
40UINTN\r
41gXferObjectReadResponse (\r
42 IN CHAR8 Type,\r
43 IN CHAR8 *Str\r
44 )\r
45{\r
46 CHAR8 *OutBufPtr; // pointer to the output buffer\r
47 CHAR8 Char;\r
48 UINTN Count;\r
49\r
50 // responce starts with 'm' or 'l' if it is the end\r
51 OutBufPtr = gOutBuffer;\r
52 *OutBufPtr++ = Type;\r
53 Count = 1;\r
54\r
3402aac7 55 // Binary data encoding\r
969eba7b 56 OutBufPtr = gOutBuffer;\r
57 while (*Str != '\0') {\r
58 Char = *Str++;\r
59 if ((Char == 0x7d) || (Char == 0x23) || (Char == 0x24) || (Char == 0x2a)) {\r
60 // escape character\r
61 *OutBufPtr++ = 0x7d;\r
62\r
63 Char ^= 0x20;\r
64 }\r
65 *OutBufPtr++ = Char;\r
66 Count++;\r
67 }\r
68\r
69 *OutBufPtr = '\0' ; // the end of the buffer\r
70 SendPacket (gOutBuffer);\r
3402aac7 71\r
969eba7b 72 return Count;\r
73}\r
74\r
3402aac7 75/**\r
969eba7b 76 Process "qXfer:object:read:annex:offset,length" request.\r
3402aac7
RC
77\r
78 Returns an XML document that contains loaded libraries. In our case it is\r
969eba7b 79 infomration in the EFI Debug Inmage Table converted into an XML document.\r
3402aac7
RC
80\r
81 GDB will call with an arbitrary length (it can't know the real length and\r
82 will reply with chunks of XML that are easy for us to deal with. Gdb will\r
969eba7b 83 keep calling until we say we are done. XML doc looks like:\r
3402aac7 84\r
969eba7b 85 <library-list>\r
86 <library name="/a/a/c/d.dSYM"><segment address="0x10000000"/></library>\r
87 <library name="/a/m/e/e.pdb"><segment address="0x20000000"/></library>\r
88 <library name="/a/l/f/f.dll"><segment address="0x30000000"/></library>\r
89 </library-list>\r
3402aac7
RC
90\r
91 Since we can not allocate memory in interupt context this module has\r
969eba7b 92 assumptions about how it will get called:\r
93 1) Length will generally be max remote packet size (big enough)\r
94 2) First Offset of an XML document read needs to be 0\r
95 3) This code will return back small chunks of the XML document on every read.\r
4f0624e8 96 Each subseqent call will ask for the next available part of the document.\r
3402aac7 97\r
969eba7b 98 Note: The only variable size element in the XML is:\r
3402aac7 99 " <library name=\"%s\"><segment address=\"%p\"/></library>\n" and it is\r
969eba7b 100 based on the file path and name of the symbol file. If the symbol file name\r
101 is bigger than the max gdb remote packet size we could update this code\r
102 to respond back in chunks.\r
103\r
104 @param Offset offset into special data area\r
3402aac7
RC
105 @param Length number of bytes to read starting at Offset\r
106\r
969eba7b 107 **/\r
108VOID\r
109QxferLibrary (\r
110 IN UINTN Offset,\r
111 IN UINTN Length\r
112 )\r
113{\r
114 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', "<library-list>\n");\r
115 gPacketqXferLibraryOffset += gXferObjectReadResponse ('m', qXferHack);\r
116 gXferObjectReadResponse ('l', "</library-list>\n");\r
117 gPacketqXferLibraryOffset = 0;\r
118}\r
119\r
120/**\r
121 Transfer length bytes of input buffer, starting at Address, to memory.\r
122\r
123 @param length the number of the bytes to be transferred/written\r
124 @param *address the start address of the transferring/writing the memory\r
125 @param *new_data the new data to be written to memory\r
126 **/\r
127\r
128VOID\r
129TransferFromInBufToMem (\r
130 IN UINTN Length,\r
131 IN unsigned char *Address,\r
132 IN CHAR8 *NewData\r
133 )\r
134{\r
135 CHAR8 c1;\r
136 CHAR8 c2;\r
3402aac7 137\r
969eba7b 138 while (Length-- > 0) {\r
139 c1 = (CHAR8)HexCharToInt (*NewData++);\r
140 c2 = (CHAR8)HexCharToInt (*NewData++);\r
141\r
142 if ((c1 < 0) || (c2 < 0)) {\r
3402aac7 143 SendError (GDB_EBADMEMDATA);\r
969eba7b 144 return;\r
145 }\r
146 *Address++ = (UINT8)((c1 << 4) + c2);\r
147 }\r
148\r
149 SendSuccess();\r
150}\r
151\r
152\r
153/**\r
154 Transfer Length bytes of memory starting at Address to an output buffer, OutBuffer. This function will finally send the buffer\r
155 as a packet.\r
156\r
157 @param Length the number of the bytes to be transferred/read\r
158 @param *address pointer to the start address of the transferring/reading the memory\r
159 **/\r
160\r
161VOID\r
162TransferFromMemToOutBufAndSend (\r
163 IN UINTN Length,\r
164 IN unsigned char *Address\r
165 )\r
166{\r
167 // there are Length bytes and every byte is represented as 2 hex chars\r
168 CHAR8 OutBuffer[MAX_BUF_SIZE];\r
169 CHAR8 *OutBufPtr; // pointer to the output buffer\r
170 CHAR8 Char;\r
171\r
172 OutBufPtr = OutBuffer;\r
173 while (Length > 0) {\r
3402aac7 174\r
969eba7b 175 Char = mHexToStr[*Address >> 4];\r
176 if ((Char >= 'A') && (Char <= 'F')) {\r
177 Char = Char - 'A' + 'a';\r
178 }\r
179 *OutBufPtr++ = Char;\r
180\r
181 Char = mHexToStr[*Address & 0x0f];\r
182 if ((Char >= 'A') && (Char <= 'F')) {\r
183 Char = Char - 'A' + 'a';\r
184 }\r
185 *OutBufPtr++ = Char;\r
186\r
187 Address++;\r
188 Length--;\r
189 }\r
190\r
191 *OutBufPtr = '\0' ; // the end of the buffer\r
192 SendPacket (OutBuffer);\r
193}\r
194\r
195\r
196\r
197/**\r
198 Send a GDB Remote Serial Protocol Packet\r
3402aac7
RC
199\r
200 $PacketData#checksum PacketData is passed in and this function adds the packet prefix '$',\r
969eba7b 201 the packet teminating character '#' and the two digit checksum.\r
3402aac7
RC
202\r
203 If an ack '+' is not sent resend the packet, but timeout eventually so we don't end up\r
969eba7b 204 in an infinit loop. This is so if you unplug the debugger code just keeps running\r
205\r
3402aac7
RC
206 @param PacketData Payload data for the packet\r
207\r
969eba7b 208\r
969eba7b 209 @retval Number of bytes of packet data sent.\r
210\r
211**/\r
212UINTN\r
213SendPacket (\r
214 IN CHAR8 *PacketData\r
215 )\r
216{\r
217 UINT8 CheckSum;\r
218 UINTN Timeout;\r
219 CHAR8 *Ptr;\r
220 CHAR8 TestChar;\r
221 UINTN Count;\r
3402aac7 222\r
969eba7b 223 Timeout = PcdGet32 (PcdGdbMaxPacketRetryCount);\r
224\r
225 Count = 0;\r
226 do {\r
227\r
228 Ptr = PacketData;\r
229\r
230 if (Timeout-- == 0) {\r
231 // Only try a finite number of times so we don't get stuck in the loop\r
232 return Count;\r
233 }\r
3402aac7 234\r
969eba7b 235 // Packet prefix\r
236 GdbPutChar ('$');\r
3402aac7 237\r
969eba7b 238 for (CheckSum = 0, Count =0 ; *Ptr != '\0'; Ptr++, Count++) {\r
239 GdbPutChar (*Ptr);\r
240 CheckSum = CheckSum + *Ptr;\r
241 }\r
3402aac7
RC
242\r
243 // Packet terminating character and checksum\r
969eba7b 244 GdbPutChar ('#');\r
245 GdbPutChar (mHexToStr[CheckSum >> 4]);\r
246 GdbPutChar (mHexToStr[CheckSum & 0x0F]);\r
3402aac7 247\r
969eba7b 248 TestChar = GdbGetChar ();\r
249 } while (TestChar != '+');\r
3402aac7 250\r
969eba7b 251 return Count;\r
252}\r
253\r
254/**\r
255 Receive 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
969eba7b 258 the packet teminating character '#' and the two digit checksum.\r
3402aac7 259\r
4f0624e8 260 If host re-starts sending a packet without ending the previous packet, only the last valid packet is processed.\r
969eba7b 261 (In other words, if received packet is '$12345$12345$123456#checksum', only '$123456#checksum' will be processed.)\r
3402aac7 262\r
969eba7b 263 If an ack '+' is not sent resend the packet\r
264\r
3402aac7 265 @param PacketData Payload data for the packet\r
969eba7b 266\r
267 @retval Number of bytes of packet data received.\r
268\r
269**/\r
270UINTN\r
271ReceivePacket (\r
272 OUT CHAR8 *PacketData,\r
273 IN UINTN PacketDataSize\r
274 )\r
275{\r
276 UINT8 CheckSum;\r
277 UINTN Index;\r
278 CHAR8 Char;\r
279 CHAR8 SumString[3];\r
280 CHAR8 TestChar;\r
3402aac7 281\r
969eba7b 282 ZeroMem (PacketData, PacketDataSize);\r
3402aac7 283\r
969eba7b 284 for (;;) {\r
285 // wait for the start of a packet\r
286 TestChar = GdbGetChar ();\r
287 while (TestChar != '$') {\r
288 TestChar = GdbGetChar ();\r
289 };\r
3402aac7 290\r
969eba7b 291 retry:\r
292 for (Index = 0, CheckSum = 0; Index < (PacketDataSize - 1); Index++) {\r
293 Char = GdbGetChar ();\r
294 if (Char == '$') {\r
295 goto retry;\r
296 }\r
297 if (Char == '#') {\r
298 break;\r
299 }\r
300\r
301 PacketData[Index] = Char;\r
302 CheckSum = CheckSum + Char;\r
303 }\r
304 PacketData[Index] = '\0';\r
305\r
306 if (Index == PacketDataSize) {\r
307 continue;\r
308 }\r
309\r
3402aac7 310 SumString[0] = GdbGetChar ();\r
969eba7b 311 SumString[1] = GdbGetChar ();\r
312 SumString[2] = '\0';\r
3402aac7 313\r
969eba7b 314 if (AsciiStrHexToUintn (SumString) == CheckSum) {\r
315 // Ack: Success\r
316 GdbPutChar ('+');\r
3402aac7 317\r
969eba7b 318 // Null terminate the callers string\r
319 PacketData[Index] = '\0';\r
320 return Index;\r
321 } else {\r
322 // Ack: Failure\r
323 GdbPutChar ('-');\r
324 }\r
325 }\r
3402aac7 326\r
969eba7b 327 //return 0;\r
328}\r
329\r
330\r
331/**\r
3402aac7 332 Empties the given buffer\r
969eba7b 333 @param Buf pointer to the first element in buffer to be emptied\r
334 **/\r
335VOID\r
3402aac7 336EmptyBuffer (\r
969eba7b 337 IN CHAR8 *Buf\r
338 )\r
3402aac7 339{\r
969eba7b 340 *Buf = '\0';\r
341}\r
342\r
343\r
344/**\r
345 Converts an 8-bit Hex Char into a INTN.\r
3402aac7 346\r
969eba7b 347 @param Char the hex character to be converted into UINTN\r
348 @retval a INTN, from 0 to 15, that corressponds to Char\r
349 -1 if Char is not a hex character\r
350 **/\r
351INTN\r
352HexCharToInt (\r
353 IN CHAR8 Char\r
354 )\r
355{\r
356 if ((Char >= 'A') && (Char <= 'F')) {\r
357 return Char - 'A' + 10;\r
358 } else if ((Char >= 'a') && (Char <= 'f')) {\r
359 return Char - 'a' + 10;\r
360 } else if ((Char >= '0') && (Char <= '9')) {\r
361 return Char - '0';\r
362 } else { // if not a hex value, return a negative value\r
3402aac7 363 return -1;\r
969eba7b 364 }\r
365}\r
366\r
367 // 'E' + the biggest error number is 255, so its 2 hex digits + buffer end\r
368CHAR8 *gError = "E__";\r
369\r
370/** 'E NN'\r
371 Send an error with the given error number after converting to hex.\r
372 The error number is put into the buffer in hex. '255' is the biggest errno we can send.\r
373 ex: 162 will be sent as A2.\r
3402aac7 374\r
969eba7b 375 @param errno the error number that will be sent\r
376 **/\r
377VOID\r
378EFIAPI\r
379SendError (\r
380 IN UINT8 ErrorNum\r
381 )\r
382{\r
383 //\r
384 // Replace _, or old data, with current errno\r
385 //\r
386 gError[1] = mHexToStr [ErrorNum >> 4];\r
387 gError[2] = mHexToStr [ErrorNum & 0x0f];\r
3402aac7 388\r
969eba7b 389 SendPacket (gError); // send buffer\r
390}\r
391\r
392\r
393\r
394/**\r
395 Send 'OK' when the function is done executing successfully.\r
396 **/\r
397VOID\r
398EFIAPI\r
399SendSuccess (\r
400 VOID\r
3402aac7 401 )\r
969eba7b 402{\r
403 SendPacket ("OK"); // send buffer\r
404}\r
405\r
406\r
407/**\r
408 Send empty packet to specify that particular command/functionality is not supported.\r
409 **/\r
3402aac7
RC
410VOID\r
411EFIAPI\r
969eba7b 412SendNotSupported (\r
3402aac7
RC
413 VOID\r
414 )\r
415{\r
969eba7b 416 SendPacket ("");\r
417}\r
418\r
419\r
420\r
421\r
422\r
423/**\r
424 Translates the EFI mapping to GDB mapping\r
3402aac7 425\r
969eba7b 426 @param EFIExceptionType EFI Exception that is being processed\r
427 @retval UINTN that corresponds to EFIExceptionType's GDB exception type number\r
428 **/\r
429UINT8\r
3402aac7 430ConvertEFItoGDBtype (\r
969eba7b 431 IN EFI_EXCEPTION_TYPE EFIExceptionType\r
432 )\r
3402aac7 433{\r
969eba7b 434 UINTN i;\r
3402aac7 435\r
969eba7b 436 for (i=0; i < MaxEfiException() ; i++) {\r
437 if (gExceptionType[i].Exception == EFIExceptionType) {\r
438 return gExceptionType[i].SignalNo;\r
439 }\r
440 }\r
441 return GDB_SIGTRAP; // this is a GDB trap\r
442}\r
443\r
444\r
445/** "m addr,length"\r
3402aac7
RC
446 Find the Length of the area to read and the start addres. Finally, pass them to\r
447 another function, TransferFromMemToOutBufAndSend, that will read from that memory space and\r
969eba7b 448 send it as a packet.\r
449 **/\r
450\r
451VOID\r
452EFIAPI\r
453ReadFromMemory (\r
454 CHAR8 *PacketData\r
455 )\r
456{\r
457 UINTN Address;\r
458 UINTN Length;\r
459 CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the address in hex chars\r
460 CHAR8 *AddrBufPtr; // pointer to the address buffer\r
461 CHAR8 *InBufPtr; /// pointer to the input buffer\r
3402aac7 462\r
969eba7b 463 AddrBufPtr = AddressBuffer;\r
464 InBufPtr = &PacketData[1];\r
465 while (*InBufPtr != ',') {\r
466 *AddrBufPtr++ = *InBufPtr++;\r
467 }\r
468 *AddrBufPtr = '\0';\r
3402aac7 469\r
969eba7b 470 InBufPtr++; // this skips ',' in the buffer\r
3402aac7 471\r
969eba7b 472 /* Error checking */\r
473 if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
3402aac7 474 SendError (GDB_EBADMEMADDRBUFSIZE);\r
969eba7b 475 return;\r
476 }\r
3402aac7 477\r
969eba7b 478 // 2 = 'm' + ','\r
479 if (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - 2 >= MAX_LENGTH_SIZE) {\r
3402aac7 480 SendError (GDB_EBADMEMLENGTH);\r
969eba7b 481 return;\r
482 }\r
3402aac7 483\r
969eba7b 484 Address = AsciiStrHexToUintn (AddressBuffer);\r
485 Length = AsciiStrHexToUintn (InBufPtr);\r
3402aac7 486\r
969eba7b 487 TransferFromMemToOutBufAndSend (Length, (unsigned char *)Address);\r
488}\r
489\r
490\r
491/** "M addr,length :XX..."\r
3402aac7 492 Find the Length of the area in bytes to write and the start addres. Finally, pass them to\r
969eba7b 493 another function, TransferFromInBufToMem, that will write to that memory space the info in\r
494 the input buffer.\r
495 **/\r
496VOID\r
497EFIAPI\r
498WriteToMemory (\r
499 IN CHAR8 *PacketData\r
500 )\r
501{\r
502 UINTN Address;\r
503 UINTN Length;\r
504 UINTN MessageLength;\r
505 CHAR8 AddressBuffer[MAX_ADDR_SIZE]; // the buffer that will hold the Address in hex chars\r
506 CHAR8 LengthBuffer[MAX_LENGTH_SIZE]; // the buffer that will hold the Length in hex chars\r
507 CHAR8 *AddrBufPtr; // pointer to the Address buffer\r
508 CHAR8 *LengthBufPtr; // pointer to the Length buffer\r
509 CHAR8 *InBufPtr; /// pointer to the input buffer\r
3402aac7 510\r
969eba7b 511 AddrBufPtr = AddressBuffer;\r
512 LengthBufPtr = LengthBuffer;\r
513 InBufPtr = &PacketData[1];\r
3402aac7 514\r
969eba7b 515 while (*InBufPtr != ',') {\r
516 *AddrBufPtr++ = *InBufPtr++;\r
517 }\r
518 *AddrBufPtr = '\0';\r
3402aac7 519\r
969eba7b 520 InBufPtr++; // this skips ',' in the buffer\r
3402aac7 521\r
969eba7b 522 while (*InBufPtr != ':') {\r
523 *LengthBufPtr++ = *InBufPtr++;\r
524 }\r
525 *LengthBufPtr = '\0';\r
3402aac7 526\r
969eba7b 527 InBufPtr++; // this skips ':' in the buffer\r
3402aac7 528\r
969eba7b 529 Address = AsciiStrHexToUintn (AddressBuffer);\r
530 Length = AsciiStrHexToUintn (LengthBuffer);\r
3402aac7 531\r
969eba7b 532 /* Error checking */\r
3402aac7 533\r
969eba7b 534 //Check if Address is not too long.\r
535 if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
3402aac7 536 SendError (GDB_EBADMEMADDRBUFSIZE);\r
969eba7b 537 return;\r
538 }\r
3402aac7 539\r
969eba7b 540 //Check if message length is not too long\r
541 if (AsciiStrLen(LengthBuffer) >= MAX_LENGTH_SIZE) {\r
3402aac7 542 SendError (GDB_EBADMEMLENGBUFSIZE);\r
969eba7b 543 return;\r
544 }\r
3402aac7 545\r
969eba7b 546 // Check if Message is not too long/short.\r
547 // 3 = 'M' + ',' + ':'\r
548 MessageLength = (AsciiStrLen(PacketData) - AsciiStrLen(AddressBuffer) - AsciiStrLen(LengthBuffer) - 3);\r
549 if (MessageLength != (2*Length)) {\r
550 //Message too long/short. New data is not the right size.\r
3402aac7 551 SendError (GDB_EBADMEMDATASIZE);\r
969eba7b 552 return;\r
553 }\r
554 TransferFromInBufToMem (Length, (unsigned char *)Address, InBufPtr);\r
555}\r
556\r
557/**\r
558 Parses breakpoint packet data and captures Breakpoint type, Address and length.\r
559 In case of an error, function returns particular error code. Returning 0 meaning\r
560 no error.\r
561\r
562 @param PacketData Pointer to the payload data for the packet.\r
563 @param Type Breakpoint type\r
564 @param Address Breakpoint address\r
565 @param Length Breakpoint length in Bytes (1 byte, 2 byte, 4 byte)\r
566\r
567 @retval 1 Success\r
568 @retval {other} Particular error code\r
569\r
570**/\r
571UINTN\r
572ParseBreakpointPacket (\r
573 IN CHAR8 *PacketData,\r
574 OUT UINTN *Type,\r
575 OUT UINTN *Address,\r
576 OUT UINTN *Length\r
577 )\r
578{\r
579 CHAR8 AddressBuffer[MAX_ADDR_SIZE];\r
580 CHAR8 *AddressBufferPtr;\r
581 CHAR8 *PacketDataPtr;\r
582\r
583 PacketDataPtr = &PacketData[1];\r
584 AddressBufferPtr = AddressBuffer;\r
585\r
586 *Type = AsciiStrHexToUintn (PacketDataPtr);\r
587\r
588 //Breakpoint/watchpoint type should be between 0 to 4\r
589 if (*Type > 4) {\r
590 return 22; //EINVAL: Invalid argument.\r
591 }\r
592\r
593 //Skip ',' in the buffer.\r
594 while (*PacketDataPtr++ != ',');\r
595\r
596 //Parse Address information\r
597 while (*PacketDataPtr != ',') {\r
598 *AddressBufferPtr++ = *PacketDataPtr++;\r
599 }\r
600 *AddressBufferPtr = '\0';\r
601\r
602 //Check if Address is not too long.\r
603 if (AsciiStrLen(AddressBuffer) >= MAX_ADDR_SIZE) {\r
604 return 40; //EMSGSIZE: Message size too long.\r
605 }\r
606\r
607 *Address = AsciiStrHexToUintn (AddressBuffer);\r
608\r
609 PacketDataPtr++; //This skips , in the buffer\r
610\r
611 //Parse Length information\r
612 *Length = AsciiStrHexToUintn (PacketDataPtr);\r
613\r
614 //Length should be 1, 2 or 4 bytes\r
615 if (*Length > 4) {\r
616 return 22; //EINVAL: Invalid argument\r
617 }\r
618\r
619 return 0; //0 = No error\r
620}\r
621\r
622\r
623\r
624/**\r
625 Send the T signal with the given exception type (in gdb order) and possibly with n:r pairs related to the watchpoints\r
3402aac7 626\r
969eba7b 627 @param SystemContext Register content at time of the exception\r
628 @param GdbExceptionType GDB exception type\r
629 **/\r
630VOID\r
631GdbSendTSignal (\r
632 IN EFI_SYSTEM_CONTEXT SystemContext,\r
633 IN UINT8 GdbExceptionType\r
634 )\r
635{\r
636 CHAR8 TSignalBuffer[128];\r
637 CHAR8 *TSignalPtr;\r
638\r
639 TSignalPtr = &TSignalBuffer[0];\r
640\r
641 //Construct TSignal packet\r
642 *TSignalPtr++ = 'T';\r
643\r
644 //\r
645 // replace _, or previous value, with Exception type\r
646 //\r
3402aac7 647 *TSignalPtr++ = mHexToStr [GdbExceptionType >> 4];\r
969eba7b 648 *TSignalPtr++ = mHexToStr [GdbExceptionType & 0x0f];\r
3402aac7 649\r
969eba7b 650 ProcessorSendTSignal (SystemContext, GdbExceptionType, TSignalPtr, sizeof (TSignalBuffer) - 2);\r
651\r
3402aac7 652 SendPacket (TSignalBuffer);\r
969eba7b 653}\r
654\r
655VOID\r
656GdbFWrite (\r
657 IN UINTN Fd,\r
658 IN CHAR8 *Data,\r
659 IN UINTN DataSize\r
660 )\r
661{\r
662 CHAR8 Buffer[128];\r
663\r
664 AsciiSPrint (Buffer, sizeof (Buffer), "Fwrite,%x,%x,%x", Fd, Data, DataSize);\r
665 SendPacket (Buffer);\r
666\r
667 for( ; ; ) {\r
668 ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
3402aac7 669\r
969eba7b 670 switch (gInBuffer[0]) {\r
671 case 'm':\r
672 ReadFromMemory (gInBuffer);\r
673 break;\r
674\r
675 case 'M':\r
676 WriteToMemory (gInBuffer);\r
677 break;\r
678\r
679 case 'F':\r
680 return;\r
969eba7b 681 }\r
682 }\r
683}\r
684\r
685\r
686VOID\r
687GdbFPutString (\r
688 IN CHAR8 *String\r
689 )\r
690{\r
691 UINTN Len = AsciiStrSize (String);\r
692\r
693 GdbFWrite (2, String, Len);\r
694}\r
695\r
696\r
697/**\r
698 Exception Hanldler for GDB. It will be called for all exceptions\r
699 registered via the gExceptionType[] array.\r
3402aac7 700\r
969eba7b 701 @param ExceptionType Exception that is being processed\r
3402aac7 702 @param SystemContext Register content at time of the exception\r
969eba7b 703 **/\r
704VOID\r
705EFIAPI\r
3402aac7
RC
706GdbExceptionHandler (\r
707 IN EFI_EXCEPTION_TYPE ExceptionType,\r
708 IN OUT EFI_SYSTEM_CONTEXT SystemContext\r
969eba7b 709 )\r
710{\r
711 UINT8 GdbExceptionType;\r
712 CHAR8 *Ptr;\r
3402aac7 713\r
969eba7b 714 if (ProcessorControlC (ExceptionType, SystemContext)) {\r
715 // We tried to process a control C handler and there is nothing to do\r
716 return;\r
717 }\r
718\r
719 GdbExceptionType = ConvertEFItoGDBtype (ExceptionType);\r
720 GdbSendTSignal (SystemContext, GdbExceptionType);\r
3402aac7 721\r
969eba7b 722 for( ; ; ) {\r
723 ReceivePacket (gInBuffer, MAX_BUF_SIZE);\r
3402aac7 724\r
969eba7b 725 switch (gInBuffer[0]) {\r
726 case '?':\r
727 GdbSendTSignal (SystemContext, GdbExceptionType);\r
728 break;\r
3402aac7 729\r
969eba7b 730 case 'c':\r
3402aac7 731 ContinueAtAddress (SystemContext, gInBuffer);\r
969eba7b 732 return;\r
733\r
734 case 'D':\r
3402aac7 735 // gdb wants to disconnect so return "OK" packet since.\r
969eba7b 736 SendSuccess ();\r
737 return;\r
738\r
739 case 'g':\r
740 ReadGeneralRegisters (SystemContext);\r
741 break;\r
3402aac7 742\r
969eba7b 743 case 'G':\r
744 WriteGeneralRegisters (SystemContext, gInBuffer);\r
745 break;\r
3402aac7 746\r
969eba7b 747 case 'H':\r
3402aac7 748 //Return "OK" packet since we don't have more than one thread.\r
969eba7b 749 SendSuccess ();\r
750 break;\r
3402aac7 751\r
969eba7b 752 case 'm':\r
753 ReadFromMemory (gInBuffer);\r
754 break;\r
755\r
756 case 'M':\r
757 WriteToMemory (gInBuffer);\r
758 break;\r
759\r
760 case 'P':\r
761 WriteNthRegister (SystemContext, gInBuffer);\r
762 break;\r
763\r
764 //\r
765 // Still debugging this code. Not used in Darwin\r
766 //\r
3402aac7 767 case 'q':\r
969eba7b 768 // General Query Packets\r
769 if (AsciiStrnCmp (gInBuffer, "qSupported", 10) == 0) {\r
770 // return what we currently support, we don't parse what gdb suports\r
771 AsciiSPrint (gOutBuffer, MAX_BUF_SIZE, "qXfer:libraries:read+;PacketSize=%d", MAX_BUF_SIZE);\r
772 SendPacket (gOutBuffer);\r
773 } else if (AsciiStrnCmp (gInBuffer, "qXfer:libraries:read::", 22) == 0) {\r
774