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