]> git.proxmox.com Git - mirror_edk2.git/blob - EmbeddedPkg/Library/GdbDebugAgent/GdbDebugAgent.c
2e67de6f996b77b6c68e81b8c2647a3928ad8a8f
[mirror_edk2.git] / EmbeddedPkg / Library / GdbDebugAgent / GdbDebugAgent.c
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
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 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 **/
108 VOID
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
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
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
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 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 **/
270 UINTN
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
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
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
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
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
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
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
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
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
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
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
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
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
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 // \91qXfer:libraries:read::offset,length
775 // gInBuffer[22] is offset string, ++Ptr is length string\92
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