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