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
18UINTN     gMaxProcessorIndex = 0;
19
20//
21// Buffers for basic gdb communication
22//
23CHAR8 gInBuffer[MAX_BUF_SIZE];
24CHAR8 gOutBuffer[MAX_BUF_SIZE];
25
26
27//
28// Globals for returning XML from qXfer:libraries:read packet
29//
30UINTN                             gPacketqXferLibraryOffset = 0;
31UINTN                             gEfiDebugImageTableEntry = 0;
32CHAR8                             gXferLibraryBuffer[2000];
33
34GLOBAL_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
38CHAR8  *qXferHack = "<library name=\"c:/work/edk2/Build/BeagleBoard/DEBUG_GCC48/ARM/BeagleBoardPkg/Sec/Sec/DEBUG/BeagleBoardSec.dll\"><segment address=\"0x80008360\"/></library>";
39
40UINTN
41gXferObjectReadResponse (
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 availble 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 **/
108VOID
109QxferLibrary (
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
128VOID
129TransferFromInBufToMem (
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
161VOID
162TransferFromMemToOutBufAndSend (
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**/
212UINTN
213SendPacket (
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 proccessed.
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**/
270UINTN
271ReceivePacket (
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 **/
335VOID
336EmptyBuffer (
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 **/
351INTN
352HexCharToInt (
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
368CHAR8 *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 **/
377VOID
378EFIAPI
379SendError (
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 **/
397VOID
398EFIAPI
399SendSuccess (
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 **/
410VOID
411EFIAPI
412SendNotSupported (
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 **/
429UINT8
430ConvertEFItoGDBtype (
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
451VOID
452EFIAPI
453ReadFromMemory (
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 **/
496VOID
497EFIAPI
498WriteToMemory (
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**/
571UINTN
572ParseBreakpointPacket (
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 **/
630VOID
631GdbSendTSignal (
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
655VOID
656GdbFWrite (
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
686VOID
687GdbFPutString (
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 **/
704VOID
705EFIAPI
706GdbExceptionHandler (
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