儲存庫 vbox 的更動 84627
- 時間撮記:
- 2020-6-1 下午08:13:57 (5 年 以前)
- svn:sync-xref-src-repo-rev:
- 138367
- 位置:
- trunk/src/VBox/Debugger
- 檔案:
-
- 修改 4 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/Debugger/DBGCGdbRemoteStub.cpp
r82968 r84627 22 22 #include <VBox/dbg.h> 23 23 #include <VBox/vmm/dbgf.h> 24 #include <iprt/errcore.h> 25 24 #include <VBox/vmm/vmapi.h> /* VMR3GetVM() */ 25 #include <VBox/vmm/hm.h> /* HMR3IsEnabled */ 26 #include <VBox/vmm/nem.h> /* NEMR3IsEnabled */ 27 #include <iprt/cdefs.h> 28 #include <iprt/err.h> 29 #include <iprt/mem.h> 30 #include <iprt/string.h> 31 32 #include <stdlib.h> 33 34 #include "DBGCInternal.h" 35 36 37 /********************************************************************************************************************************* 38 * Defined Constants And Macros * 39 *********************************************************************************************************************************/ 40 41 /** Character indicating the start of a packet. */ 42 #define GDBSTUB_PKT_START '$' 43 /** Character indicating the end of a packet (excluding the checksum). */ 44 #define GDBSTUB_PKT_END '#' 45 /** The escape character. */ 46 #define GDBSTUB_PKT_ESCAPE '{' 47 /** The out-of-band interrupt character. */ 48 #define GDBSTUB_OOB_INTERRUPT 0x03 49 50 51 /** Indicate support for the 'qXfer:features:read' packet to support the target description. */ 52 #define GDBSTUBCTX_FEATURES_F_TGT_DESC RT_BIT(0) 53 54 55 /********************************************************************************************************************************* 56 * Structures and Typedefs * 57 *********************************************************************************************************************************/ 58 59 /** 60 * Trace point type. 61 */ 62 typedef enum GDBSTUBTPTYPE 63 { 64 /** Invalid type, do not use. */ 65 GDBSTUBTPTYPE_INVALID = 0, 66 /** An instruction software trace point. */ 67 GDBSTUBTPTYPE_EXEC_SW, 68 /** An instruction hardware trace point. */ 69 GDBSTUBTPTYPE_EXEC_HW, 70 /** A memory read trace point. */ 71 GDBSTUBTPTYPE_MEM_READ, 72 /** A memory write trace point. */ 73 GDBSTUBTPTYPE_MEM_WRITE, 74 /** A memory access trace point. */ 75 GDBSTUBTPTYPE_MEM_ACCESS, 76 /** 32bit hack. */ 77 GDBSTUBTPTYPE_32BIT_HACK = 0x7fffffff 78 } GDBSTUBTPTYPE; 79 80 81 /** 82 * GDB stub receive state. 83 */ 84 typedef enum GDBSTUBRECVSTATE 85 { 86 /** Invalid state. */ 87 GDBSTUBRECVSTATE_INVALID = 0, 88 /** Waiting for the start character. */ 89 GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START, 90 /** Reiceiving the packet body up until the END character. */ 91 GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY, 92 /** Receiving the checksum. */ 93 GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM, 94 /** Blow up the enum to 32bits for easier alignment of members in structs. */ 95 GDBSTUBRECVSTATE_32BIT_HACK = 0x7fffffff 96 } GDBSTUBRECVSTATE; 97 98 99 /** 100 * GDB stub context data. 101 */ 102 typedef struct GDBSTUBCTX 103 { 104 /** Internal debugger console data. */ 105 DBGC Dbgc; 106 /** The current state when receiving a new packet. */ 107 GDBSTUBRECVSTATE enmState; 108 /** Maximum number of bytes the packet buffer can hold. */ 109 size_t cbPktBufMax; 110 /** Current offset into the packet buffer. */ 111 uint32_t offPktBuf; 112 /** The size of the packet (minus the start, end characters and the checksum). */ 113 uint32_t cbPkt; 114 /** Pointer to the packet buffer data. */ 115 uint8_t *pbPktBuf; 116 /** Number of bytes left for the checksum. */ 117 size_t cbChksumRecvLeft; 118 /** Send packet checksum. */ 119 uint8_t uChkSumSend; 120 /** Feature flags supported we negotiated with the remote end. */ 121 uint32_t fFeatures; 122 /** Pointer to the XML target description. */ 123 char *pachTgtXmlDesc; 124 /** Size of the XML target description. */ 125 size_t cbTgtXmlDesc; 126 /** Flag whether the stub is in extended mode. */ 127 bool fExtendedMode; 128 } GDBSTUBCTX; 129 /** Pointer to the GDB stub context data. */ 130 typedef GDBSTUBCTX *PGDBSTUBCTX; 131 /** Pointer to const GDB stub context data. */ 132 typedef const GDBSTUBCTX *PCGDBSTUBCTX; 133 /** Pointer to a GDB stub context data pointer. */ 134 typedef PGDBSTUBCTX *PPGDBSTUBCTX; 135 136 137 /** 138 * Specific query packet processor callback. 139 * 140 * @returns Status code. 141 * @param pThis The GDB stub context. 142 * @param pbArgs Pointer to the arguments. 143 * @param cbArgs Size of the arguments in bytes. 144 */ 145 typedef DECLCALLBACK(int) FNGDBSTUBQPKTPROC(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs); 146 typedef FNGDBSTUBQPKTPROC *PFNGDBSTUBQPKTPROC; 147 148 149 /** 150 * 'q' packet processor. 151 */ 152 typedef struct GDBSTUBQPKTPROC 153 { 154 /** Name */ 155 const char *pszName; 156 /** Length of name in characters (without \0 terminator). */ 157 uint32_t cchName; 158 /** The callback to call for processing the particular query. */ 159 PFNGDBSTUBQPKTPROC pfnProc; 160 } GDBSTUBQPKTPROC; 161 /** Pointer to a 'q' packet processor entry. */ 162 typedef GDBSTUBQPKTPROC *PGDBSTUBQPKTPROC; 163 /** Pointer to a const 'q' packet processor entry. */ 164 typedef const GDBSTUBQPKTPROC *PCGDBSTUBQPKTPROC; 165 166 167 /** 168 * 'v' packet processor. 169 */ 170 typedef struct GDBSTUBVPKTPROC 171 { 172 /** Name */ 173 const char *pszName; 174 /** Length of name in characters (without \0 terminator). */ 175 uint32_t cchName; 176 /** Replay to a query packet (ends with ?). */ 177 const char *pszReplyQ; 178 /** Length of the query reply (without \0 terminator). */ 179 uint32_t cchReplyQ; 180 /** The callback to call for processing the particular query. */ 181 PFNGDBSTUBQPKTPROC pfnProc; 182 } GDBSTUBVPKTPROC; 183 /** Pointer to a 'q' packet processor entry. */ 184 typedef GDBSTUBVPKTPROC *PGDBSTUBVPKTPROC; 185 /** Pointer to a const 'q' packet processor entry. */ 186 typedef const GDBSTUBVPKTPROC *PCGDBSTUBVPKTPROC; 187 188 189 /** 190 * Feature callback. 191 * 192 * @returns Status code. 193 * @param pThis The GDB stub context. 194 * @param pbVal Pointer to the value. 195 * @param cbVal Size of the value in bytes. 196 */ 197 typedef DECLCALLBACK(int) FNGDBSTUBFEATHND(PGDBSTUBCTX pThis, const uint8_t *pbVal, size_t cbVal); 198 typedef FNGDBSTUBFEATHND *PFNGDBSTUBFEATHND; 199 200 201 /** 202 * GDB feature descriptor. 203 */ 204 typedef struct GDBSTUBFEATDESC 205 { 206 /** Feature name */ 207 const char *pszName; 208 /** Length of the feature name in characters (without \0 terminator). */ 209 uint32_t cchName; 210 /** The callback to call for processing the particular feature. */ 211 PFNGDBSTUBFEATHND pfnHandler; 212 /** Flag whether the feature requires a value. */ 213 bool fVal; 214 } GDBSTUBFEATDESC; 215 /** Pointer to a GDB feature descriptor. */ 216 typedef GDBSTUBFEATDESC *PGDBSTUBFEATDESC; 217 /** Pointer to a const GDB feature descriptor. */ 218 typedef const GDBSTUBFEATDESC *PCGDBSTUBFEATDESC; 219 220 221 /********************************************************************************************************************************* 222 * Internal Functions * 223 *********************************************************************************************************************************/ 224 225 /** 226 * Converts a given to the hexadecimal value if valid. 227 * 228 * @returns The hexadecimal value the given character represents 0-9,a-f,A-F or 0xff on error. 229 * @param ch The character to convert. 230 */ 231 DECLINLINE(uint8_t) dbgcGdbStubCtxChrToHex(char ch) 232 { 233 if (ch >= '0' && ch <= '9') 234 return ch - '0'; 235 if (ch >= 'A' && ch <= 'F') 236 return ch - 'A' + 0xa; 237 if (ch >= 'a' && ch <= 'f') 238 return ch - 'a' + 0xa; 239 240 return 0xff; 241 } 242 243 244 /** 245 * Converts a 4bit hex number to the appropriate character. 246 * 247 * @returns Character representing the 4bit hex number. 248 * @param uHex The 4 bit hex number. 249 */ 250 DECLINLINE(char) dbgcGdbStubCtxHexToChr(uint8_t uHex) 251 { 252 if (uHex < 0xa) 253 return '0' + uHex; 254 if (uHex <= 0xf) 255 return 'A' + uHex - 0xa; 256 257 return 'X'; 258 } 259 260 261 /** 262 * Wrapper for the I/O interface write callback. 263 * 264 * @returns Status code. 265 * @param pThis The GDB stub context. 266 * @param pvPkt The packet data to send. 267 * @param cbPkt Size of the packet in bytes. 268 */ 269 DECLINLINE(int) dbgcGdbStubCtxWrite(PGDBSTUBCTX pThis, const void *pvPkt, size_t cbPkt) 270 { 271 return pThis->Dbgc.pBack->pfnWrite(pThis->Dbgc.pBack, pvPkt, cbPkt, NULL /*pcbWritten*/); 272 } 273 274 275 /** 276 * Starts transmission of a new reply packet. 277 * 278 * @returns Status code. 279 * @param pThis The GDB stub context. 280 */ 281 static int dbgcGdbStubCtxReplySendBegin(PGDBSTUBCTX pThis) 282 { 283 pThis->uChkSumSend = 0; 284 285 uint8_t chPktStart = GDBSTUB_PKT_START; 286 return dbgcGdbStubCtxWrite(pThis, &chPktStart, sizeof(chPktStart)); 287 } 288 289 290 /** 291 * Sends the given data in the reply. 292 * 293 * @returns Status code. 294 * @param pThis The GDB stub context. 295 * @param pbReplyData The reply data to send. 296 * @param cbReplyData Size of the reply data in bytes. 297 */ 298 static int dbgcGdbStubCtxReplySendData(PGDBSTUBCTX pThis, const void *pvReplyData, size_t cbReplyData) 299 { 300 /* Update checksum. */ 301 const uint8_t *pbData = (const uint8_t *)pvReplyData; 302 for (uint32_t i = 0; i < cbReplyData; i++) 303 pThis->uChkSumSend += pbData[i]; 304 305 return dbgcGdbStubCtxWrite(pThis, pvReplyData, cbReplyData); 306 } 307 308 309 /** 310 * Finishes transmission of the current reply by sending the packet end character and the checksum. 311 * 312 * @returns Status code. 313 * @param pThis The GDB stub context. 314 */ 315 static int dbgcGdbStubCtxReplySendEnd(PGDBSTUBCTX pThis) 316 { 317 uint8_t achPktEnd[3]; 318 319 achPktEnd[0] = GDBSTUB_PKT_END; 320 achPktEnd[1] = dbgcGdbStubCtxHexToChr(pThis->uChkSumSend >> 4); 321 achPktEnd[2] = dbgcGdbStubCtxHexToChr(pThis->uChkSumSend & 0xf); 322 323 return dbgcGdbStubCtxWrite(pThis, &achPktEnd[0], sizeof(achPktEnd)); 324 } 325 326 327 /** 328 * Sends the given reply packet, doing the framing, checksumming, etc. in one call. 329 * 330 * @returns Status code. 331 * @param pThis The GDB stub context. 332 * @param pbReplyPkt The reply packet to send. 333 * @param cbReplyPkt Size of the reply packet in bytes. 334 */ 335 static int dbgcGdbStubCtxReplySend(PGDBSTUBCTX pThis, const void *pvReplyPkt, size_t cbReplyPkt) 336 { 337 int rc = dbgcGdbStubCtxReplySendBegin(pThis); 338 if (RT_SUCCESS(rc)) 339 { 340 rc = dbgcGdbStubCtxReplySendData(pThis, pvReplyPkt, cbReplyPkt); 341 if (RT_SUCCESS(rc)) 342 rc = dbgcGdbStubCtxReplySendEnd(pThis); 343 } 344 345 return rc; 346 } 347 348 349 /** 350 * Encodes the given buffer as a hexstring string it into the given destination buffer. 351 * 352 * @returns Status code. 353 * @param pbDst Where store the resulting hex string on success. 354 * @param cbDst Size of the destination buffer in bytes. 355 * @param pvSrc The data to encode. 356 * @param cbSrc Number of bytes to encode. 357 */ 358 DECLINLINE(int) dbgcGdbStubCtxEncodeBinaryAsHex(uint8_t *pbDst, size_t cbDst, void *pvSrc, size_t cbSrc) 359 { 360 return RTStrPrintHexBytes((char *)pbDst, cbDst, pvSrc, cbSrc, RTSTRPRINTHEXBYTES_F_UPPER); 361 } 362 363 364 /** 365 * Decodes the given ASCII hexstring as binary data up until the given separator is found or the end of the string is reached. 366 * 367 * @returns Status code. 368 * @param pbBuf The buffer containing the hexstring to convert. 369 * @param cbBuf Size of the buffer in bytes. 370 * @param pvDst Where to store the decoded data. 371 * @param cbDst Maximum buffer sizein bytes. 372 * @param chSep The character to stop conversion at. 373 * @param ppbSep Where to store the pointer in the buffer where the separator was found, optional. 374 */ 375 static int dbgcGdbStubCtxParseHexStringAsInteger(const uint8_t *pbBuf, size_t cbBuf, uint64_t *puVal, uint8_t chSep, const uint8_t **ppbSep) 376 { 377 uint64_t uVal = 0; 378 379 while ( cbBuf 380 && *pbBuf != chSep) 381 { 382 uVal = uVal * 16 + dbgcGdbStubCtxChrToHex(*pbBuf++); 383 cbBuf--; 384 } 385 386 *puVal = uVal; 387 388 if (ppbSep) 389 *ppbSep = pbBuf; 390 391 return VINF_SUCCESS; 392 } 393 394 395 /** 396 * Decodes the given ASCII hexstring as a byte buffer up until the given separator is found or the end of the string is reached. 397 * 398 * @returns Status code. 399 * @param pbBuf The buffer containing the hexstring to convert. 400 * @param cbBuf Size of the buffer in bytes. 401 * @param pvDst Where to store the decoded data. 402 * @param cbDst Maximum buffer size in bytes. 403 * @param pcbDecoded Where to store the number of consumed bytes from the input. 404 */ 405 DECLINLINE(int) dbgcGdbStubCtxParseHexStringAsByteBuf(const uint8_t *pbBuf, size_t cbBuf, void *pvDst, size_t cbDst, size_t *pcbDecoded) 406 { 407 size_t cbDecode = RT_MIN(cbBuf, cbDst * 2); 408 409 if (pcbDecoded) 410 *pcbDecoded = cbDecode; 411 412 return RTStrConvertHexBytes((const char *)pbBuf, pvDst, cbDecode, 0 /* fFlags*/); 413 } 414 415 #if 0 /*unused for now*/ 416 /** 417 * Sends a 'OK' part of a reply packet only (packet start and end needs to be handled separately). 418 * 419 * @returns Status code. 420 * @param pThis The GDB stub context. 421 */ 422 static int dbgcGdbStubCtxReplySendOkData(PGDBSTUBCTX pThis) 423 { 424 char achOk[2] = { 'O', 'K' }; 425 return dbgcGdbStubCtxReplySendData(pThis, &achOk[0], sizeof(achOk)); 426 } 427 #endif 428 429 430 /** 431 * Sends a 'OK' reply packet. 432 * 433 * @returns Status code. 434 * @param pThis The GDB stub context. 435 */ 436 static int dbgcGdbStubCtxReplySendOk(PGDBSTUBCTX pThis) 437 { 438 char achOk[2] = { 'O', 'K' }; 439 return dbgcGdbStubCtxReplySend(pThis, &achOk[0], sizeof(achOk)); 440 } 441 442 #if 0 /*unused for now*/ 443 /** 444 * Sends a 'E NN' part of a reply packet only (packet start and end needs to be handled separately). 445 * 446 * @returns Status code. 447 * @param pThis The GDB stub context. 448 * @param uErr The error code to send. 449 */ 450 static int dbgcGdbStubCtxReplySendErrData(PGDBSTUBCTX pThis, uint8_t uErr) 451 { 452 char achErr[3] = { 'E', 0, 0 }; 453 achErr[1] = dbgcGdbStubCtxHexToChr(uErr >> 4); 454 achErr[2] = dbgcGdbStubCtxHexToChr(uErr & 0xf); 455 return dbgcGdbStubCtxReplySendData(pThis, &achErr[0], sizeof(achErr)); 456 } 457 #endif 458 459 /** 460 * Sends a 'E NN' reply packet. 461 * 462 * @returns Status code. 463 * @param pThis The GDB stub context. 464 * @param uErr The error code to send. 465 */ 466 static int dbgcGdbStubCtxReplySendErr(PGDBSTUBCTX pThis, uint8_t uErr) 467 { 468 char achErr[3] = { 'E', 0, 0 }; 469 achErr[1] = dbgcGdbStubCtxHexToChr(uErr >> 4); 470 achErr[2] = dbgcGdbStubCtxHexToChr(uErr & 0xf); 471 return dbgcGdbStubCtxReplySend(pThis, &achErr[0], sizeof(achErr)); 472 } 473 474 475 /** 476 * Sends a signal trap (S 05) packet to indicate that the target has stopped. 477 * 478 * @returns Status code. 479 * @param pThis The GDB stub context. 480 */ 481 static int dbgcGdbStubCtxReplySendSigTrap(PGDBSTUBCTX pThis) 482 { 483 uint8_t achSigTrap[3] = { 'S', '0', '5' }; 484 return dbgcGdbStubCtxReplySend(pThis, &achSigTrap[0], sizeof(achSigTrap)); 485 } 486 487 488 /** 489 * Sends a GDB stub status code indicating an error using the error reply packet. 490 * 491 * @returns Status code. 492 * @param pThis The GDB stub context. 493 * @param rc The status code to send. 494 */ 495 static int dbgcGdbStubCtxReplySendErrSts(PGDBSTUBCTX pThis, int rc) 496 { 497 /** @todo convert error codes maybe. */ 498 return dbgcGdbStubCtxReplySendErr(pThis, (-rc) & 0xff); 499 } 500 501 502 /** 503 * Ensures that there is at least the given amount of bytes of free space left in the packet buffer. 504 * 505 * @returns Status code (error when increasing the buffer failed). 506 * @param pThis The GDB stub context. 507 * @param cbSpace Number of bytes required. 508 */ 509 static int dbgcGdbStubCtxEnsurePktBufSpace(PGDBSTUBCTX pThis, size_t cbSpace) 510 { 511 if (pThis->cbPktBufMax - pThis->offPktBuf >= cbSpace) 512 return VINF_SUCCESS; 513 514 /* Slow path allocate new buffer and copy content over. */ 515 int rc = VINF_SUCCESS; 516 size_t cbPktBufMaxNew = pThis->cbPktBufMax + cbSpace; 517 void *pvNew = RTMemRealloc(pThis->pbPktBuf, cbPktBufMaxNew); 518 if (pvNew) 519 { 520 pThis->pbPktBuf = (uint8_t *)pvNew; 521 pThis->cbPktBufMax = cbPktBufMaxNew; 522 } 523 else 524 rc = VERR_NO_MEMORY; 525 526 return rc; 527 } 528 529 530 /** 531 * Parses the arguments of a 'Z' and 'z' packet. 532 * 533 * @returns Status code. 534 * @param pbArgs Pointer to the start of the first argument. 535 * @param cbArgs Number of argument bytes. 536 * @param penmTpType Where to store the tracepoint type on success. 537 * @param pGdbTgtAddr Where to store the address on success. 538 * @param puKind Where to store the kind argument on success. 539 */ 540 static int dbgcGdbStubCtxParseTpPktArgs(const uint8_t *pbArgs, size_t cbArgs, GDBSTUBTPTYPE *penmTpType, uint64_t *pGdbTgtAddr, uint64_t *puKind) 541 { 542 const uint8_t *pbPktSep = NULL; 543 uint64_t uType = 0; 544 545 int rc = dbgcGdbStubCtxParseHexStringAsInteger(pbArgs, cbArgs, &uType, 546 ',', &pbPktSep); 547 if (RT_SUCCESS(rc)) 548 { 549 cbArgs -= (uintptr_t)(pbPktSep - pbArgs) - 1; 550 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, cbArgs, pGdbTgtAddr, 551 ',', &pbPktSep); 552 if (RT_SUCCESS(rc)) 553 { 554 cbArgs -= (uintptr_t)(pbPktSep - pbArgs) - 1; 555 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, cbArgs, puKind, 556 GDBSTUB_PKT_END, NULL); 557 if (RT_SUCCESS(rc)) 558 { 559 switch (uType) 560 { 561 case 0: 562 *penmTpType = GDBSTUBTPTYPE_EXEC_SW; 563 break; 564 case 1: 565 *penmTpType = GDBSTUBTPTYPE_EXEC_HW; 566 break; 567 case 2: 568 *penmTpType = GDBSTUBTPTYPE_MEM_WRITE; 569 break; 570 case 3: 571 *penmTpType = GDBSTUBTPTYPE_MEM_READ; 572 break; 573 case 4: 574 *penmTpType = GDBSTUBTPTYPE_MEM_ACCESS; 575 break; 576 default: 577 rc = VERR_INVALID_PARAMETER; 578 break; 579 } 580 } 581 } 582 } 583 584 return rc; 585 } 586 587 588 /** 589 * Processes the 'TStatus' query. 590 * 591 * @returns Status code. 592 * @param pThis The GDB stub context. 593 * @param pbArgs Pointer to the start of the arguments in the packet. 594 * @param cbArgs Size of arguments in bytes. 595 */ 596 static int dbgcGdbStubCtxPktProcessQueryTStatus(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs) 597 { 598 RT_NOREF(pbArgs, cbArgs); 599 600 char achReply[2] = { 'T', '0' }; 601 return dbgcGdbStubCtxReplySend(pThis, &achReply[0], sizeof(achReply)); 602 } 603 604 605 /** 606 * @copydoc{FNGDBSTUBQPKTPROC} 607 */ 608 static int dbgcGdbStubCtxPktProcessFeatXmlRegs(PGDBSTUBCTX pThis, const uint8_t *pbVal, size_t cbVal) 609 { 610 /* 611 * xmlRegisters contain a list of supported architectures delimited by ','. 612 * Check that the architecture is in the supported list. 613 */ 614 while (cbVal) 615 { 616 /* Find the next delimiter. */ 617 size_t cbThisVal = cbVal; 618 const uint8_t *pbDelim = (const uint8_t *)memchr(pbVal, ',', cbVal); 619 if (pbDelim) 620 cbThisVal = pbDelim - pbVal; 621 622 size_t cchArch = sizeof("i386:x86-64") - 1; 623 if (!memcmp(pbVal, "i386:x86-64", RT_MIN(cbVal, cchArch))) 624 { 625 /* Set the flag to support the qXfer:features:read packet. */ 626 pThis->fFeatures |= GDBSTUBCTX_FEATURES_F_TGT_DESC; 627 break; 628 } 629 630 cbVal -= cbThisVal + (pbDelim ? 1 : 0); 631 pbVal = pbDelim + (pbDelim ? 1 : 0); 632 } 633 634 return VINF_SUCCESS; 635 } 636 637 638 /** 639 * Features which can be reported by the remote GDB which we might support. 640 * 641 * @note The sorting matters for features which start the same, the longest must come first. 642 */ 643 static const GDBSTUBFEATDESC g_aGdbFeatures[] = 644 { 645 #define GDBSTUBFEATDESC_INIT(a_Name, a_pfnHnd, a_fVal) { a_Name, sizeof(a_Name) - 1, a_pfnHnd, a_fVal } 646 GDBSTUBFEATDESC_INIT("xmlRegisters", dbgcGdbStubCtxPktProcessFeatXmlRegs, true), 647 #undef GDBSTUBFEATDESC_INIT 648 }; 649 650 651 /** 652 * Calculates the feature length of the next feature pointed to by the given arguments buffer. 653 * 654 * @returns Status code. 655 * @param pbArgs Pointer to the start of the arguments in the packet. 656 * @param cbArgs Size of arguments in bytes. 657 * @param pcbArg Where to store the size of the argument in bytes on success (excluding the delimiter). 658 * @param pfTerminator Whereto store the flag whether the packet terminator (#) was seen as a delimiter. 659 */ 660 static int dbgcGdbStubCtxQueryPktQueryFeatureLen(const uint8_t *pbArgs, size_t cbArgs, size_t *pcbArg, bool *pfTerminator) 661 { 662 const uint8_t *pbArgCur = pbArgs; 663 664 while ( cbArgs 665 && *pbArgCur != ';' 666 && *pbArgCur != GDBSTUB_PKT_END) 667 { 668 cbArgs--; 669 pbArgCur++; 670 } 671 672 if ( !cbArgs 673 && *pbArgCur != ';' 674 && *pbArgCur != GDBSTUB_PKT_END) 675 return VERR_NET_PROTOCOL_ERROR; 676 677 *pcbArg = pbArgCur - pbArgs; 678 *pfTerminator = *pbArgCur == GDBSTUB_PKT_END ? true : false; 679 680 return VINF_SUCCESS; 681 } 682 683 684 /** 685 * Sends the reply to the 'qSupported' packet. 686 * 687 * @returns Status code. 688 * @param pThis The GDB stub context. 689 */ 690 static int dbgcGdbStubCtxPktProcessQuerySupportedReply(PGDBSTUBCTX pThis) 691 { 692 /** @todo Enhance. */ 693 if (pThis->fFeatures & GDBSTUBCTX_FEATURES_F_TGT_DESC) 694 return dbgcGdbStubCtxReplySend(pThis, "qXfer:features:read+", sizeof("qXfer:features:read+") - 1); 695 696 return dbgcGdbStubCtxReplySend(pThis, NULL, 0); 697 } 698 699 700 /** 701 * Processes the 'Supported' query. 702 * 703 * @returns Status code. 704 * @param pThis The GDB stub context. 705 * @param pbArgs Pointer to the start of the arguments in the packet. 706 * @param cbArgs Size of arguments in bytes. 707 */ 708 static int dbgcGdbStubCtxPktProcessQuerySupported(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs) 709 { 710 /* Skip the : following the qSupported start. */ 711 if ( cbArgs < 1 712 || pbArgs[0] != ':') 713 return VERR_NET_PROTOCOL_ERROR; 714 715 cbArgs--; 716 pbArgs++; 717 718 /* 719 * Each feature but the last one are separated by ; and the last one is delimited by the # packet end symbol. 720 * We first determine the boundaries of the reported feature and pass it to the appropriate handler. 721 */ 722 int rc = VINF_SUCCESS; 723 while ( cbArgs 724 && RT_SUCCESS(rc)) 725 { 726 bool fTerminator = false; 727 size_t cbArg = 0; 728 rc = dbgcGdbStubCtxQueryPktQueryFeatureLen(pbArgs, cbArgs, &cbArg, &fTerminator); 729 if (RT_SUCCESS(rc)) 730 { 731 /* Search for the feature handler. */ 732 for (uint32_t i = 0; i < RT_ELEMENTS(g_aGdbFeatures); i++) 733 { 734 PCGDBSTUBFEATDESC pFeatDesc = &g_aGdbFeatures[i]; 735 736 if ( cbArg > pFeatDesc->cchName /* At least one character must come after the feature name ('+', '-' or '='). */ 737 && !memcmp(pFeatDesc->pszName, pbArgs, pFeatDesc->cchName)) 738 { 739 /* Found, execute handler after figuring out whether there is a value attached. */ 740 const uint8_t *pbVal = pbArgs + pFeatDesc->cchName; 741 size_t cbVal = cbArg - pFeatDesc->cchName; 742 743 if (pFeatDesc->fVal) 744 { 745 if ( *pbVal == '=' 746 && cbVal > 1) 747 { 748 pbVal++; 749 cbVal--; 750 } 751 else 752 rc = VERR_NET_PROTOCOL_ERROR; 753 } 754 else if ( cbVal != 1 755 || ( *pbVal != '+' 756 && *pbVal != '-')) /* '+' and '-' are allowed to indicate support for a particular feature. */ 757 rc = VERR_NET_PROTOCOL_ERROR; 758 759 if (RT_SUCCESS(rc)) 760 rc = pFeatDesc->pfnHandler(pThis, pbVal, cbVal); 761 break; 762 } 763 } 764 765 cbArgs -= cbArg; 766 pbArgs += cbArg; 767 if (!fTerminator) 768 { 769 cbArgs--; 770 pbArgs++; 771 } 772 else 773 break; 774 } 775 } 776 777 /* If everything went alright send the reply with our supported features. */ 778 if (RT_SUCCESS(rc)) 779 rc = dbgcGdbStubCtxPktProcessQuerySupportedReply(pThis); 780 781 return rc; 782 } 783 784 785 /** 786 * Sends the reply to a 'qXfer:<object>:read:...' request. 787 * 788 * @returns Status code. 789 * @param pThis The GDB stub context. 790 * @param offRead Where to start reading from within the object. 791 * @param cbRead How much to read. 792 * @param pbObj The start of the object. 793 * @param cbObj Size of the object. 794 */ 795 static int dbgcGdbStubCtxQueryXferReadReply(PGDBSTUBCTX pThis, uint32_t offRead, size_t cbRead, const uint8_t *pbObj, size_t cbObj) 796 { 797 int rc = VINF_SUCCESS; 798 if (offRead < cbObj) 799 { 800 /** @todo Escaping */ 801 size_t cbThisRead = offRead + cbRead < cbObj ? cbRead : cbObj - offRead; 802 803 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbThisRead + 1); 804 if (RT_SUCCESS(rc)) 805 { 806 uint8_t *pbPktBuf = pThis->pbPktBuf; 807 *pbPktBuf++ = cbThisRead < cbRead ? 'l' : 'm'; 808 memcpy(pbPktBuf, pbObj + offRead, cbThisRead); 809 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbThisRead + 1); 810 } 811 else 812 rc = dbgcGdbStubCtxReplySendErr(pThis, VERR_NO_MEMORY); 813 } 814 else if (offRead == cbObj) 815 rc = dbgcGdbStubCtxReplySend(pThis, "l", sizeof("l") - 1); 816 else 817 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR); 818 819 return rc; 820 } 821 822 823 /** 824 * Parses the annex:offset,length part of a 'qXfer:<object>:read:...' request. 825 * 826 * @returns Status code. 827 * @param pbArgs Start of the arguments beginning with <annex>. 828 * @param cbArgs Number of bytes remaining for the arguments. 829 * @param ppchAnnex Where to store the pointer to the beginning of the annex on success. 830 * @param pcchAnnex Where to store the number of characters for the annex on success. 831 * @param poff Where to store the offset on success. 832 * @param pcb Where to store the length on success. 833 */ 834 static int dbgcGdbStubCtxPktProcessQueryXferParseAnnexOffLen(const uint8_t *pbArgs, size_t cbArgs, const char **ppchAnnex, size_t *pcchAnnex, 835 uint32_t *poffRead, size_t *pcbRead) 836 { 837 int rc = VINF_SUCCESS; 838 const uint8_t *pbSep = (const uint8_t *)memchr(pbArgs, ':', cbArgs); 839 if (pbSep) 840 { 841 *ppchAnnex = (const char *)pbArgs; 842 *pcchAnnex = pbSep - pbArgs; 843 844 pbSep++; 845 cbArgs -= *pcchAnnex + 1; 846 847 uint64_t u64Tmp = 0; 848 const uint8_t *pbLenStart = NULL; 849 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbSep, cbArgs, &u64Tmp, ',', &pbLenStart); 850 if ( RT_SUCCESS(rc) 851 && (uint32_t)u64Tmp == u64Tmp) 852 { 853 *poffRead = (uint32_t)u64Tmp; 854 cbArgs -= pbLenStart - pbSep; 855 856 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbLenStart + 1, cbArgs, &u64Tmp, '#', &pbLenStart); 857 if ( RT_SUCCESS(rc) 858 && (size_t)u64Tmp == u64Tmp) 859 *pcbRead = (size_t)u64Tmp; 860 else 861 rc = VERR_NET_PROTOCOL_ERROR; 862 } 863 else 864 rc = VERR_NET_PROTOCOL_ERROR; 865 } 866 else 867 rc = VERR_NET_PROTOCOL_ERROR; 868 869 return rc; 870 } 871 872 873 /** 874 * GDB registers. 875 */ 876 static const struct GDBREGDESC 877 { 878 /** Register name. */ 879 const char *pszName; 880 /** DBGF register index. */ 881 DBGFREG enmReg; 882 /** Bitsize */ 883 uint32_t cBits; 884 /** Type. */ 885 const char *pszType; 886 /** Group. */ 887 const char *pszGroup; 888 } g_aGdbRegs[] = 889 { 890 #define DBGREG_DESC_INIT_INT64(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "int64", NULL } 891 #define DBGREG_DESC_INIT_INT32(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 32, "int32", NULL } 892 #define DBGREG_DESC_INIT_DATA_PTR(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "data_ptr", NULL } 893 #define DBGREG_DESC_INIT_CODE_PTR(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 64, "code_ptr", NULL } 894 #define DBGREG_DESC_INIT_X87(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 80, "i387_ext", NULL } 895 #define DBGREG_DESC_INIT_X87_CTRL(a_Name, a_enmDbgfReg) { a_Name, a_enmDbgfReg, 32, "int", "float" } 896 DBGREG_DESC_INIT_INT64( "rax", DBGFREG_RAX), 897 DBGREG_DESC_INIT_INT64( "rbx", DBGFREG_RBX), 898 DBGREG_DESC_INIT_INT64( "rcx", DBGFREG_RCX), 899 DBGREG_DESC_INIT_INT64( "rdx", DBGFREG_RDX), 900 DBGREG_DESC_INIT_INT64( "rsi", DBGFREG_RSI), 901 DBGREG_DESC_INIT_INT64( "rdi", DBGFREG_RDI), 902 DBGREG_DESC_INIT_DATA_PTR("rbp", DBGFREG_RBP), 903 DBGREG_DESC_INIT_DATA_PTR("rsp", DBGFREG_RSP), 904 DBGREG_DESC_INIT_INT64( "r8", DBGFREG_R8), 905 DBGREG_DESC_INIT_INT64( "r9", DBGFREG_R9), 906 DBGREG_DESC_INIT_INT64( "r10", DBGFREG_R10), 907 DBGREG_DESC_INIT_INT64( "r11", DBGFREG_R11), 908 DBGREG_DESC_INIT_INT64( "r12", DBGFREG_R12), 909 DBGREG_DESC_INIT_INT64( "r13", DBGFREG_R13), 910 DBGREG_DESC_INIT_INT64( "r14", DBGFREG_R14), 911 DBGREG_DESC_INIT_INT64( "r15", DBGFREG_R15), 912 DBGREG_DESC_INIT_CODE_PTR("rip", DBGFREG_RIP), 913 DBGREG_DESC_INIT_INT32( "eflags", DBGFREG_FLAGS), 914 DBGREG_DESC_INIT_INT32( "cs", DBGFREG_CS), 915 DBGREG_DESC_INIT_INT32( "ss", DBGFREG_SS), 916 DBGREG_DESC_INIT_INT32( "ds", DBGFREG_DS), 917 DBGREG_DESC_INIT_INT32( "es", DBGFREG_ES), 918 DBGREG_DESC_INIT_INT32( "fs", DBGFREG_FS), 919 DBGREG_DESC_INIT_INT32( "gs", DBGFREG_GS), 920 921 DBGREG_DESC_INIT_X87( "st0", DBGFREG_ST0), 922 DBGREG_DESC_INIT_X87( "st1", DBGFREG_ST1), 923 DBGREG_DESC_INIT_X87( "st2", DBGFREG_ST2), 924 DBGREG_DESC_INIT_X87( "st3", DBGFREG_ST3), 925 DBGREG_DESC_INIT_X87( "st4", DBGFREG_ST4), 926 DBGREG_DESC_INIT_X87( "st5", DBGFREG_ST5), 927 DBGREG_DESC_INIT_X87( "st6", DBGFREG_ST6), 928 DBGREG_DESC_INIT_X87( "st7", DBGFREG_ST7), 929 930 DBGREG_DESC_INIT_X87_CTRL("fctrl", DBGFREG_FCW), 931 DBGREG_DESC_INIT_X87_CTRL("fstat", DBGFREG_FSW), 932 DBGREG_DESC_INIT_X87_CTRL("ftag", DBGFREG_FTW), 933 DBGREG_DESC_INIT_X87_CTRL("fop", DBGFREG_FOP), 934 DBGREG_DESC_INIT_X87_CTRL("fioff", DBGFREG_FPUIP), 935 DBGREG_DESC_INIT_X87_CTRL("fiseg", DBGFREG_FPUCS), 936 DBGREG_DESC_INIT_X87_CTRL("fooff", DBGFREG_FPUDP), 937 DBGREG_DESC_INIT_X87_CTRL("foseg", DBGFREG_FPUDS) 938 939 #undef DBGREG_DESC_INIT_CODE_PTR 940 #undef DBGREG_DESC_INIT_DATA_PTR 941 #undef DBGREG_DESC_INIT_INT32 942 #undef DBGREG_DESC_INIT_INT64 943 }; 944 945 946 /** 947 * Creates the target XML description. 948 * 949 * @returns Status code. 950 * @param pThis The GDB stub context. 951 */ 952 static int dbgcGdbStubCtxTgtXmlDescCreate(PGDBSTUBCTX pThis) 953 { 954 static const char s_szXmlTgtHdr[] = 955 "<?xml version=\"1.0\"?>\n" 956 "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n" 957 "<target version=\"1.0\">\n" 958 " <architecture>i386:x86-64</architecture>\n" 959 " <feature name=\"org.gnu.gdb.i386.core\">\n"; 960 static const char s_szXmlTgtFooter[] = 961 " </feature>\n" 962 "</target>\n"; 963 964 int rc = VINF_SUCCESS; 965 966 pThis->pachTgtXmlDesc = (char *)RTStrAlloc(_32K); 967 if (pThis->pachTgtXmlDesc) 968 { 969 size_t cbLeft = _32K; 970 char *pachXmlCur = pThis->pachTgtXmlDesc; 971 pThis->cbTgtXmlDesc = cbLeft; 972 973 rc = RTStrCatP(&pachXmlCur, &cbLeft, &s_szXmlTgtHdr[0]); 974 if (RT_SUCCESS(rc)) 975 { 976 /* Register */ 977 for (uint32_t i = 0; i < RT_ELEMENTS(g_aGdbRegs) && RT_SUCCESS(rc); i++) 978 { 979 const struct GDBREGDESC *pReg = &g_aGdbRegs[i]; 980 981 ssize_t cchStr = 0; 982 if (pReg->pszGroup) 983 cchStr = RTStrPrintf2(pachXmlCur, cbLeft, 984 "<reg name=\"%s\" bitsize=\"%u\" regnum=\"%u\" type=\"%s\" group=\"%s\"/>\n", 985 pReg->pszName, pReg->cBits, pReg->enmReg, pReg->pszType, pReg->pszGroup); 986 else 987 cchStr = RTStrPrintf2(pachXmlCur, cbLeft, 988 "<reg name=\"%s\" bitsize=\"%u\" regnum=\"%u\" type=\"%s\"/>\n", 989 pReg->pszName, pReg->cBits, pReg->enmReg, pReg->pszType); 990 991 if (cchStr > 0) 992 { 993 pachXmlCur += cchStr; 994 cbLeft -= cchStr; 995 } 996 else 997 rc = VERR_BUFFER_OVERFLOW; 998 } 999 } 1000 1001 if (RT_SUCCESS(rc)) 1002 rc = RTStrCatP(&pachXmlCur, &cbLeft, &s_szXmlTgtFooter[0]); 1003 1004 pThis->cbTgtXmlDesc -= cbLeft; 1005 } 1006 else 1007 rc = VERR_NO_MEMORY; 1008 1009 return rc; 1010 } 1011 1012 1013 /** 1014 * Returns the GDB register descriptor describing the given DBGF register enum. 1015 * 1016 * @returns Pointer to the GDB register descriptor or NULL if not found. 1017 * @param enmReg The register to look for. 1018 */ 1019 static const GDBREGDESC *dbgcGdbStubRegGet(DBGFREG enmReg) 1020 { 1021 for (uint32_t i = 0; i < RT_ELEMENTS(g_aGdbRegs); i++) 1022 { 1023 const struct GDBREGDESC *pReg = &g_aGdbRegs[i]; 1024 1025 if (pReg->enmReg == enmReg) 1026 return pReg; 1027 } 1028 1029 return NULL; 1030 } 1031 1032 1033 /** 1034 * Processes the 'Xfer:features:read' query. 1035 * 1036 * @returns Status code. 1037 * @param pThis The GDB stub context. 1038 * @param pbArgs Pointer to the start of the arguments in the packet. 1039 * @param cbArgs Size of arguments in bytes. 1040 */ 1041 static int dbgcGdbStubCtxPktProcessQueryXferFeatRead(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs) 1042 { 1043 /* Skip the : following the Xfer:features:read start. */ 1044 if ( cbArgs < 1 1045 || pbArgs[0] != ':') 1046 return VERR_NET_PROTOCOL_ERROR; 1047 1048 cbArgs--; 1049 pbArgs++; 1050 1051 int rc = VINF_SUCCESS; 1052 if (pThis->fFeatures & GDBSTUBCTX_FEATURES_F_TGT_DESC) 1053 { 1054 /* Create the target XML description if not existing. */ 1055 if (!pThis->pachTgtXmlDesc) 1056 rc = dbgcGdbStubCtxTgtXmlDescCreate(pThis); 1057 1058 if (RT_SUCCESS(rc)) 1059 { 1060 /* Parse annex, offset and length and return the data. */ 1061 const char *pchAnnex = NULL; 1062 size_t cchAnnex = 0; 1063 uint32_t offRead = 0; 1064 size_t cbRead = 0; 1065 1066 rc = dbgcGdbStubCtxPktProcessQueryXferParseAnnexOffLen(pbArgs, cbArgs, 1067 &pchAnnex, &cchAnnex, 1068 &offRead, &cbRead); 1069 if (RT_SUCCESS(rc)) 1070 { 1071 /* Check whether the annex is supported. */ 1072 if ( cchAnnex == sizeof("target.xml") - 1 1073 && !memcmp(pchAnnex, "target.xml", cchAnnex)) 1074 rc = dbgcGdbStubCtxQueryXferReadReply(pThis, offRead, cbRead, (const uint8_t *)pThis->pachTgtXmlDesc, 1075 pThis->cbTgtXmlDesc); 1076 else 1077 rc = dbgcGdbStubCtxReplySendErr(pThis, 0); 1078 } 1079 else 1080 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1081 } 1082 else 1083 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1084 } 1085 else 1086 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0); /* Not supported. */ 1087 1088 return rc; 1089 } 1090 1091 1092 #if 0 1093 /** 1094 * Calls the given command handler and processes the reply. 1095 * 1096 * @returns Status code. 1097 * @param pThis The GDB stub context. 1098 * @param pCmd The command to call - NULL if using the generic monitor command received callback in the 1099 * interface callback table. 1100 * @param pszArgs Argument string to call the command with. 1101 */ 1102 static int gdbStubCtxCmdProcess(PGDBSTUBCTXINT pThis, PCGDBSTUBCMD pCmd, const char *pszArgs) 1103 { 1104 int rc = gdbStubCtxReplySendBegin(pThis); 1105 if (rc == GDBSTUB_INF_SUCCESS) 1106 { 1107 gdbStubOutCtxReset(&pThis->OutCtx); 1108 int rcCmd = GDBSTUB_INF_SUCCESS; 1109 if (pCmd) 1110 rcCmd = pCmd->pfnCmd(pThis, &pThis->OutCtx.Hlp, pszArgs, pThis->pvUser); 1111 else 1112 rcCmd = pThis->pIf->pfnMonCmd(pThis, &pThis->OutCtx.Hlp, pszArgs, pThis->pvUser); 1113 if (rcCmd == GDBSTUB_INF_SUCCESS) 1114 { 1115 if (!pThis->OutCtx.offScratch) /* No output, just send OK reply. */ 1116 rc = gdbStubCtxReplySendOkData(pThis); 1117 else 1118 rc = gdbStubCtxReplySendData(pThis, &pThis->OutCtx.abScratch[0], pThis->OutCtx.offScratch); 1119 1120 /* Try to finish the reply in case of an error anyway (but we might be completely screwed at this point anyway). */ 1121 gdbStubCtxReplySendEnd(pThis); 1122 } 1123 else 1124 rc = gdbStubCtxReplySendErrStsData(pThis, rcCmd); 1125 } 1126 1127 return rc; 1128 } 1129 1130 1131 /** 1132 * Processes the 'Rcmd' query. 1133 * 1134 * @returns Status code. 1135 * @param pThis The GDB stub context. 1136 * @param pbArgs Pointer to the start of the arguments in the packet. 1137 * @param cbArgs Size of arguments in bytes. 1138 */ 1139 static int gdbStubCtxPktProcessQueryRcmd(PGDBSTUBCTXINT pThis, const uint8_t *pbArgs, size_t cbArgs) 1140 { 1141 int rc = GDBSTUB_INF_SUCCESS; 1142 1143 /* Skip the , following the qRcmd start. */ 1144 if ( cbArgs < 1 1145 || pbArgs[0] != ',') 1146 return GDBSTUB_ERR_PROTOCOL_VIOLATION; 1147 1148 if (!pThis->pIf->paCmds) 1149 return GDBSTUB_ERR_NOT_FOUND; 1150 1151 cbArgs--; 1152 pbArgs++; 1153 1154 /* Decode the command. */ 1155 /** @todo Make this dynamic. */ 1156 char szCmd[4096]; 1157 if (cbArgs / 2 >= sizeof(szCmd)) 1158 return GDBSTUB_ERR_BUFFER_OVERFLOW; 1159 1160 size_t cbDecoded = 0; 1161 rc = gdbStubCtxParseHexStringAsByteBuf(pbArgs, cbArgs - 1, &szCmd[0], sizeof(szCmd), &cbDecoded); 1162 if (rc == GDBSTUB_INF_SUCCESS) 1163 { 1164 const char *pszArgs = NULL; 1165 1166 cbDecoded /= 2; 1167 szCmd[cbDecoded] = '\0'; /* Ensure zero termination. */ 1168 1169 /** @todo Sanitize string. */ 1170 1171 /* Look for the first space and take that as the separator between command identifier. */ 1172 uint8_t *pbDelim = gdbStubCtxMemchr(&szCmd[0], ' ', cbDecoded); 1173 if (pbDelim) 1174 { 1175 *pbDelim = '\0'; 1176 pszArgs = pbDelim + 1; 1177 } 1178 1179 /* Search for the command. */ 1180 PCGDBSTUBCMD pCmd = &pThis->pIf->paCmds[0]; 1181 rc = GDBSTUB_ERR_NOT_FOUND; 1182 while (pCmd->pszCmd) 1183 { 1184 if (!gdbStubStrcmp(pCmd->pszCmd, &szCmd[0])) 1185 { 1186 rc = gdbStubCtxCmdProcess(pThis, pCmd, pszArgs); 1187 break; 1188 } 1189 pCmd++; 1190 } 1191 1192 if ( rc == GDBSTUB_ERR_NOT_FOUND 1193 && pThis->pIf->pfnMonCmd) 1194 { 1195 /* Restore delimiter. */ 1196 if (pbDelim) 1197 *pbDelim = ' '; 1198 rc = gdbStubCtxCmdProcess(pThis, NULL, &szCmd[0]); 1199 } 1200 else 1201 rc = gdbStubCtxReplySendErrSts(pThis, rc); /** @todo Send string. */ 1202 } 1203 1204 return rc; 1205 } 1206 #endif 1207 1208 1209 /** 1210 * List of supported query packets. 1211 */ 1212 static const GDBSTUBQPKTPROC g_aQPktProcs[] = 1213 { 1214 #define GDBSTUBQPKTPROC_INIT(a_Name, a_pfnProc) { a_Name, sizeof(a_Name) - 1, a_pfnProc } 1215 GDBSTUBQPKTPROC_INIT("TStatus", dbgcGdbStubCtxPktProcessQueryTStatus), 1216 GDBSTUBQPKTPROC_INIT("Supported", dbgcGdbStubCtxPktProcessQuerySupported), 1217 GDBSTUBQPKTPROC_INIT("Xfer:features:read", dbgcGdbStubCtxPktProcessQueryXferFeatRead), 1218 //GDBSTUBQPKTPROC_INIT("Rcmd", dbgcGdbStubCtxPktProcessQueryRcmd), 1219 #undef GDBSTUBQPKTPROC_INIT 1220 }; 1221 1222 1223 /** 1224 * Processes a 'q' packet, sending the appropriate reply. 1225 * 1226 * @returns Status code. 1227 * @param pThis The GDB stub context. 1228 * @param pbQuery The query packet data (without the 'q'). 1229 * @param cbQuery Size of the remaining query packet in bytes. 1230 */ 1231 static int dbgcGdbStubCtxPktProcessQuery(PGDBSTUBCTX pThis, const uint8_t *pbQuery, size_t cbQuery) 1232 { 1233 /* Search the query and execute the processor or return an empty reply if not supported. */ 1234 for (uint32_t i = 0; i < RT_ELEMENTS(g_aQPktProcs); i++) 1235 { 1236 size_t cbCmp = g_aQPktProcs[i].cchName < cbQuery ? g_aQPktProcs[i].cchName : cbQuery; 1237 1238 if (!memcmp(pbQuery, g_aQPktProcs[i].pszName, cbCmp)) 1239 return g_aQPktProcs[i].pfnProc(pThis, pbQuery + cbCmp, cbQuery - cbCmp); 1240 } 1241 1242 return dbgcGdbStubCtxReplySend(pThis, NULL, 0); 1243 } 1244 1245 1246 /** 1247 * Processes a 'vCont[;action[:thread-id]]' packet. 1248 * 1249 * @returns Status code. 1250 * @param pThis The GDB stub context. 1251 * @param pbArgs Pointer to the start of the arguments in the packet. 1252 * @param cbArgs Size of arguments in bytes. 1253 */ 1254 static int dbgcGdbStubCtxPktProcessVCont(PGDBSTUBCTX pThis, const uint8_t *pbArgs, size_t cbArgs) 1255 { 1256 int rc = VINF_SUCCESS; 1257 1258 /* Skip the ; following the identifier. */ 1259 if ( cbArgs < 2 1260 || pbArgs[0] != ';') 1261 return dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR); 1262 1263 pbArgs++; 1264 cbArgs--; 1265 1266 /** @todo For now we don't care about multiple threads and ignore thread IDs and multiple actions. */ 1267 switch (pbArgs[0]) 1268 { 1269 case 'c': 1270 { 1271 if (DBGFR3IsHalted(pThis->Dbgc.pUVM)) 1272 DBGFR3Resume(pThis->Dbgc.pUVM); 1273 break; 1274 } 1275 case 's': 1276 { 1277 PDBGFADDRESS pStackPop = NULL; 1278 RTGCPTR cbStackPop = 0; 1279 rc = DBGFR3StepEx(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGF_STEP_F_INTO, NULL, 1280 pStackPop, cbStackPop, 1 /*cMaxSteps*/); 1281 if (RT_FAILURE(rc)) 1282 dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1283 break; 1284 } 1285 case 't': 1286 { 1287 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM)) 1288 rc = DBGFR3Halt(pThis->Dbgc.pUVM); 1289 /* The reply will be send in the event loop. */ 1290 break; 1291 } 1292 default: 1293 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR); 1294 } 1295 1296 return rc; 1297 } 1298 1299 1300 /** 1301 * List of supported 'v<identifier>' packets. 1302 */ 1303 static const GDBSTUBVPKTPROC g_aVPktProcs[] = 1304 { 1305 #define GDBSTUBVPKTPROC_INIT(a_Name, a_pszReply, a_pfnProc) { a_Name, sizeof(a_Name) - 1, a_pszReply, sizeof(a_pszReply) - 1, a_pfnProc } 1306 GDBSTUBVPKTPROC_INIT("Cont", "vCont;s;c;t", dbgcGdbStubCtxPktProcessVCont) 1307 #undef GDBSTUBVPKTPROC_INIT 1308 }; 1309 1310 1311 /** 1312 * Processes a 'v<identifier>' packet, sending the appropriate reply. 1313 * 1314 * @returns Status code. 1315 * @param pThis The GDB stub context. 1316 * @param pbPktRem The remaining packet data (without the 'v'). 1317 * @param cbPktRem Size of the remaining packet in bytes. 1318 */ 1319 static int dbgcGdbStubCtxPktProcessV(PGDBSTUBCTX pThis, const uint8_t *pbPktRem, size_t cbPktRem) 1320 { 1321 /* Determine the end of the identifier, delimiters are '?', ';' or end of packet. */ 1322 bool fQuery = false; 1323 const uint8_t *pbDelim = (const uint8_t *)memchr(pbPktRem, '?', cbPktRem); 1324 if (!pbDelim) 1325 pbDelim = (const uint8_t *)memchr(pbPktRem, ';', cbPktRem); 1326 else 1327 fQuery = true; 1328 1329 size_t cchId = 0; 1330 if (pbDelim) /* Delimiter found, calculate length. */ 1331 cchId = pbDelim - pbPktRem; 1332 else /* Not found, size goes till end of packet. */ 1333 cchId = cbPktRem; 1334 1335 /* Search the query and execute the processor or return an empty reply if not supported. */ 1336 for (uint32_t i = 0; i < RT_ELEMENTS(g_aVPktProcs); i++) 1337 { 1338 PCGDBSTUBVPKTPROC pVProc = &g_aVPktProcs[i]; 1339 1340 if ( pVProc->cchName == cchId 1341 && !memcmp(pbPktRem, pVProc->pszName, cchId)) 1342 { 1343 /* Just send the static reply for a query and execute the processor for everything else. */ 1344 if (fQuery) 1345 return dbgcGdbStubCtxReplySend(pThis, pVProc->pszReplyQ, pVProc->cchReplyQ); 1346 1347 /* Execute the handler. */ 1348 return pVProc->pfnProc(pThis, pbPktRem + cchId, cbPktRem - cchId); 1349 } 1350 } 1351 1352 return dbgcGdbStubCtxReplySend(pThis, NULL, 0); 1353 } 1354 1355 1356 /** 1357 * Processes a completely received packet. 1358 * 1359 * @returns Status code. 1360 * @param pThis The GDB stub context. 1361 */ 1362 static int dbgcGdbStubCtxPktProcess(PGDBSTUBCTX pThis) 1363 { 1364 int rc = VINF_SUCCESS; 1365 1366 if (pThis->cbPkt >= 1) 1367 { 1368 switch (pThis->pbPktBuf[1]) 1369 { 1370 case '!': /* Enabled extended mode. */ 1371 { 1372 pThis->fExtendedMode = true; 1373 rc = dbgcGdbStubCtxReplySendOk(pThis); 1374 break; 1375 } 1376 case '?': 1377 { 1378 /* Return signal state. */ 1379 rc = dbgcGdbStubCtxReplySendSigTrap(pThis); 1380 break; 1381 } 1382 case 's': /* Single step, response will be sent in the event loop. */ 1383 { 1384 PDBGFADDRESS pStackPop = NULL; 1385 RTGCPTR cbStackPop = 0; 1386 rc = DBGFR3StepEx(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, DBGF_STEP_F_INTO, NULL, 1387 pStackPop, cbStackPop, 1 /*cMaxSteps*/); 1388 if (RT_FAILURE(rc)) 1389 dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1390 break; 1391 } 1392 case 'c': /* Continue, no response */ 1393 { 1394 if (DBGFR3IsHalted(pThis->Dbgc.pUVM)) 1395 DBGFR3Resume(pThis->Dbgc.pUVM); 1396 break; 1397 } 1398 case 'g': /* Read general registers. */ 1399 { 1400 uint32_t idxRegMax = 0; 1401 size_t cbRegs = 0; 1402 for (;;) 1403 { 1404 const GDBREGDESC *pReg = &g_aGdbRegs[idxRegMax++]; 1405 cbRegs += pReg->cBits / 8; 1406 if (pReg->enmReg == DBGFREG_SS) /* Up to this seems to belong to the general register set. */ 1407 break; 1408 } 1409 1410 size_t cbReplyPkt = cbRegs * 2 + 1; /* One byte needs two characters. */ 1411 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt); 1412 if (RT_SUCCESS(rc)) 1413 { 1414 size_t cbLeft = cbReplyPkt; 1415 uint8_t *pbReply = pThis->pbPktBuf; 1416 1417 for (uint32_t i = 0; i < idxRegMax && RT_SUCCESS(rc); i++) 1418 { 1419 const GDBREGDESC *pReg = &g_aGdbRegs[i]; 1420 size_t cbReg = pReg->cBits / 8; 1421 union 1422 { 1423 uint32_t u32; 1424 uint64_t u64; 1425 uint8_t au8[8]; 1426 } RegVal; 1427 1428 if (pReg->cBits == 32) 1429 rc = DBGFR3RegCpuQueryU32(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->enmReg, &RegVal.u32); 1430 else 1431 rc = DBGFR3RegCpuQueryU64(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->enmReg, &RegVal.u64); 1432 1433 if (RT_SUCCESS(rc)) 1434 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pbReply, cbLeft, &RegVal.au8[0], cbReg); 1435 1436 pbReply += cbReg * 2; 1437 cbLeft -= cbReg * 2; 1438 } 1439 1440 if (RT_SUCCESS(rc)) 1441 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt); 1442 else 1443 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1444 } 1445 1446 break; 1447 } 1448 case 'm': /* Read memory. */ 1449 { 1450 uint64_t GdbTgtAddr = 0; 1451 const uint8_t *pbPktSep = NULL; 1452 1453 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &GdbTgtAddr, 1454 ',', &pbPktSep); 1455 if (RT_SUCCESS(rc)) 1456 { 1457 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2]; 1458 size_t cbRead = 0; 1459 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &cbRead, GDBSTUB_PKT_END, NULL); 1460 if (RT_SUCCESS(rc)) 1461 { 1462 size_t cbReplyPkt = cbRead * 2 + 1; /* One byte needs two characters. */ 1463 1464 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt); 1465 if (RT_SUCCESS(rc)) 1466 { 1467 uint8_t *pbPktBuf = pThis->pbPktBuf; 1468 size_t cbPktBufLeft = cbReplyPkt; 1469 DBGFADDRESS AddrRead; 1470 1471 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrRead, GdbTgtAddr); 1472 1473 while ( cbRead 1474 && RT_SUCCESS(rc)) 1475 { 1476 uint8_t abTmp[_4K]; 1477 size_t cbThisRead = RT_MIN(cbRead, sizeof(abTmp)); 1478 1479 rc = DBGFR3MemRead(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrRead, &abTmp[0], cbThisRead); 1480 if (RT_FAILURE(rc)) 1481 break; 1482 1483 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pbPktBuf, cbPktBufLeft, &abTmp[0], cbThisRead); 1484 if (RT_FAILURE(rc)) 1485 break; 1486 1487 DBGFR3AddrAdd(&AddrRead, cbThisRead); 1488 cbRead -= cbThisRead; 1489 pbPktBuf += cbThisRead; 1490 cbPktBufLeft -= cbThisRead; 1491 } 1492 1493 if (RT_SUCCESS(rc)) 1494 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt); 1495 else 1496 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1497 } 1498 else 1499 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1500 } 1501 else 1502 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1503 } 1504 else 1505 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1506 break; 1507 } 1508 case 'M': /* Write memory. */ 1509 { 1510 uint64_t GdbTgtAddr = 0; 1511 const uint8_t *pbPktSep = NULL; 1512 1513 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &GdbTgtAddr, 1514 ',', &pbPktSep); 1515 if (RT_SUCCESS(rc)) 1516 { 1517 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2]; 1518 size_t cbWrite = 0; 1519 rc = dbgcGdbStubCtxParseHexStringAsInteger(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &cbWrite, ':', &pbPktSep); 1520 if (RT_SUCCESS(rc)) 1521 { 1522 cbProcessed = pbPktSep - &pThis->pbPktBuf[2]; 1523 const uint8_t *pbDataCur = pbPktSep + 1; 1524 size_t cbDataLeft = pThis->cbPkt - 1 - cbProcessed - 1 - 1; 1525 DBGFADDRESS AddrWrite; 1526 1527 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &AddrWrite, GdbTgtAddr); 1528 1529 while ( cbWrite 1530 && RT_SUCCESS(rc)) 1531 { 1532 uint8_t abTmp[_4K]; 1533 size_t cbThisWrite = RT_MIN(cbWrite, sizeof(abTmp)); 1534 size_t cbDecoded = 0; 1535 1536 rc = dbgcGdbStubCtxParseHexStringAsByteBuf(pbDataCur, cbDataLeft, &abTmp[0], cbThisWrite, &cbDecoded); 1537 if (!rc) 1538 rc = DBGFR3MemWrite(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &AddrWrite, &abTmp[0], cbThisWrite); 1539 1540 DBGFR3AddrAdd(&AddrWrite, cbThisWrite); 1541 cbWrite -= cbThisWrite; 1542 pbDataCur += cbDecoded; 1543 cbDataLeft -= cbDecoded; 1544 } 1545 1546 if (RT_SUCCESS(rc)) 1547 rc = dbgcGdbStubCtxReplySendOk(pThis); 1548 else 1549 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1550 } 1551 else 1552 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1553 } 1554 else 1555 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1556 break; 1557 } 1558 case 'p': /* Read a single register */ 1559 { 1560 uint64_t uReg = 0; 1561 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &uReg, 1562 GDBSTUB_PKT_END, NULL); 1563 if (RT_SUCCESS(rc)) 1564 { 1565 DBGFREGVAL RegVal; 1566 DBGFREGVALTYPE enmType; 1567 DBGFREG enmReg = (DBGFREG)uReg; 1568 const GDBREGDESC *pReg = dbgcGdbStubRegGet(enmReg); 1569 if (RT_LIKELY(pReg)) 1570 { 1571 rc = DBGFR3RegNmQuery(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->pszName, &RegVal, &enmType); 1572 if (RT_SUCCESS(rc)) 1573 { 1574 size_t cbReg = pReg->cBits / 8; 1575 size_t cbReplyPkt = cbReg * 2 + 1; /* One byte needs two characters. */ 1576 1577 /* Encode data and send. */ 1578 rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, cbReplyPkt); 1579 if (RT_SUCCESS(rc)) 1580 { 1581 rc = dbgcGdbStubCtxEncodeBinaryAsHex(pThis->pbPktBuf, pThis->cbPktBufMax, &RegVal.au8[0], cbReg); 1582 if (RT_SUCCESS(rc)) 1583 rc = dbgcGdbStubCtxReplySend(pThis, pThis->pbPktBuf, cbReplyPkt); 1584 else 1585 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1586 } 1587 else 1588 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1589 } 1590 else 1591 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1592 } 1593 else 1594 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR); 1595 } 1596 else 1597 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1598 break; 1599 } 1600 case 'P': /* Write a single register */ 1601 { 1602 uint64_t uReg = 0; 1603 const uint8_t *pbPktSep = NULL; 1604 rc = dbgcGdbStubCtxParseHexStringAsInteger(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &uReg, 1605 '=', &pbPktSep); 1606 if (RT_SUCCESS(rc)) 1607 { 1608 DBGFREG enmReg = (DBGFREG)uReg; 1609 const GDBREGDESC *pReg = dbgcGdbStubRegGet(enmReg); 1610 1611 if (pReg) 1612 { 1613 DBGFREGVAL RegVal; 1614 DBGFREGVALTYPE enmValType = pReg->cBits == 64 ? DBGFREGVALTYPE_U64 : DBGFREGVALTYPE_U32; 1615 size_t cbProcessed = pbPktSep - &pThis->pbPktBuf[2]; 1616 rc = dbgcGdbStubCtxParseHexStringAsByteBuf(pbPktSep + 1, pThis->cbPkt - 1 - cbProcessed - 1, &RegVal.au8[0], pReg->cBits / 8, NULL); 1617 if (RT_SUCCESS(rc)) 1618 { 1619 rc = DBGFR3RegNmSet(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, pReg->pszName, &RegVal, enmValType); 1620 if (RT_SUCCESS(rc)) 1621 rc = dbgcGdbStubCtxReplySendOk(pThis); 1622 else 1623 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1624 } 1625 } 1626 else 1627 rc = dbgcGdbStubCtxReplySendErrSts(pThis, VERR_NET_PROTOCOL_ERROR); 1628 } 1629 else 1630 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1631 break; 1632 } 1633 case 'Z': /* Insert a breakpoint/watchpoint. */ 1634 { 1635 GDBSTUBTPTYPE enmTpType = GDBSTUBTPTYPE_INVALID; 1636 uint64_t GdbTgtTpAddr = 0; 1637 uint64_t uKind = 0; 1638 1639 rc = dbgcGdbStubCtxParseTpPktArgs(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &enmTpType, &GdbTgtTpAddr, &uKind); 1640 if (RT_SUCCESS(rc)) 1641 { 1642 uint32_t iBp = 0; 1643 DBGFADDRESS BpAddr; 1644 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &BpAddr, GdbTgtTpAddr); 1645 1646 switch (enmTpType) 1647 { 1648 case GDBSTUBTPTYPE_EXEC_SW: 1649 { 1650 rc = DBGFR3BpSetInt3(pThis->Dbgc.pUVM, pThis->Dbgc.idCpu, &BpAddr, 1651 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, &iBp); 1652 break; 1653 } 1654 case GDBSTUBTPTYPE_EXEC_HW: 1655 { 1656 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr, 1657 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, 1658 X86_DR7_RW_EO, 1 /*cb*/, &iBp); 1659 break; 1660 } 1661 case GDBSTUBTPTYPE_MEM_ACCESS: 1662 case GDBSTUBTPTYPE_MEM_READ: 1663 { 1664 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr, 1665 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, 1666 X86_DR7_RW_RW, uKind /*cb*/, &iBp); 1667 break; 1668 } 1669 case GDBSTUBTPTYPE_MEM_WRITE: 1670 { 1671 rc = DBGFR3BpSetReg(pThis->Dbgc.pUVM, &BpAddr, 1672 1 /*iHitTrigger*/, UINT64_MAX /*iHitDisable*/, 1673 X86_DR7_RW_WO, uKind /*cb*/, &iBp); 1674 break; 1675 } 1676 default: 1677 AssertMsgFailed(("Invalid trace point type %d\n", enmTpType)); 1678 } 1679 1680 if (RT_SUCCESS(rc)) 1681 { 1682 rc = dbgcBpAdd(&pThis->Dbgc, iBp, NULL /*pszCmd*/); 1683 if (RT_SUCCESS(rc)) 1684 rc = dbgcGdbStubCtxReplySendOk(pThis); 1685 else 1686 { 1687 DBGFR3BpClear(pThis->Dbgc.pUVM, iBp); 1688 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1689 } 1690 } 1691 else 1692 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1693 } 1694 else 1695 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1696 break; 1697 } 1698 case 'z': /* Remove a breakpoint/watchpoint. */ 1699 { 1700 GDBSTUBTPTYPE enmTpType = GDBSTUBTPTYPE_INVALID; 1701 uint64_t GdbTgtTpAddr = 0; 1702 uint64_t uKind = 0; 1703 1704 rc = dbgcGdbStubCtxParseTpPktArgs(&pThis->pbPktBuf[2], pThis->cbPkt - 1, &enmTpType, &GdbTgtTpAddr, &uKind); 1705 if (RT_SUCCESS(rc)) 1706 { 1707 DBGFADDRESS BpAddr; 1708 DBGFR3AddrFromFlat(pThis->Dbgc.pUVM, &BpAddr, GdbTgtTpAddr); 1709 1710 uint32_t iBp = 0; /** @todo Need to keep track which breakpoint number belongs to which breakpoint. */ 1711 int rc2 = DBGFR3BpClear(pThis->Dbgc.pUVM, iBp); 1712 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 1713 dbgcBpDelete(&pThis->Dbgc, iBp); 1714 1715 if (RT_SUCCESS(rc2)) 1716 rc = dbgcGdbStubCtxReplySendOk(pThis); 1717 else 1718 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1719 } 1720 else 1721 rc = dbgcGdbStubCtxReplySendErrSts(pThis, rc); 1722 break; 1723 } 1724 case 'q': /* Query packet */ 1725 { 1726 rc = dbgcGdbStubCtxPktProcessQuery(pThis, &pThis->pbPktBuf[2], pThis->cbPkt - 1); 1727 break; 1728 } 1729 case 'v': /* Multiletter identifier (verbose?) */ 1730 { 1731 rc = dbgcGdbStubCtxPktProcessV(pThis, &pThis->pbPktBuf[2], pThis->cbPkt - 1); 1732 break; 1733 } 1734 case 'R': /* Restart target. */ 1735 { 1736 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0); 1737 break; 1738 } 1739 case 'k': /* Kill target. */ 1740 { 1741 /* This is what the 'harakiri' command is doing. */ 1742 for (;;) 1743 exit(126); 1744 break; 1745 } 1746 default: 1747 /* Not supported, send empty reply. */ 1748 rc = dbgcGdbStubCtxReplySend(pThis, NULL, 0); 1749 } 1750 } 1751 1752 return rc; 1753 } 1754 1755 1756 /** 1757 * Resets the packet buffer. 1758 * 1759 * @returns nothing. 1760 * @param pThis The GDB stub context. 1761 */ 1762 static void dbgcGdbStubCtxPktBufReset(PGDBSTUBCTX pThis) 1763 { 1764 pThis->offPktBuf = 0; 1765 pThis->cbPkt = 0; 1766 pThis->cbChksumRecvLeft = 2; 1767 } 1768 1769 1770 /** 1771 * Resets the given GDB stub context to the initial state. 1772 * 1773 * @returns nothing. 1774 * @param pThis The GDB stub context. 1775 */ 1776 static void dbgcGdbStubCtxReset(PGDBSTUBCTX pThis) 1777 { 1778 pThis->enmState = GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START; 1779 dbgcGdbStubCtxPktBufReset(pThis); 1780 } 1781 1782 1783 /** 1784 * Searches for the start character in the current data buffer. 1785 * 1786 * @returns Status code. 1787 * @param pThis The GDB stub context. 1788 * @param cbData Number of new bytes in the packet buffer. 1789 * @param pcbProcessed Where to store the amount of bytes processed. 1790 */ 1791 static int dbgcGdbStubCtxPktBufSearchStart(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed) 1792 { 1793 int rc = VINF_SUCCESS; 1794 const uint8_t *pbStart = (const uint8_t *)memchr(pThis->pbPktBuf, GDBSTUB_PKT_START, cbData); 1795 if (pbStart) 1796 { 1797 /* Found the start character, align the start to the beginning of the packet buffer and advance the state machine. */ 1798 memmove(pThis->pbPktBuf, pbStart, cbData - (pbStart - pThis->pbPktBuf)); 1799 pThis->enmState = GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY; 1800 *pcbProcessed = (uintptr_t)(pbStart - pThis->pbPktBuf); 1801 pThis->offPktBuf = 0; 1802 } 1803 else 1804 { 1805 /* Check for out of band characters. */ 1806 if (memchr(pThis->pbPktBuf, GDBSTUB_OOB_INTERRUPT, cbData) != NULL) 1807 { 1808 /* Stop target and send packet to indicate the target has stopped. */ 1809 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM)) 1810 rc = DBGFR3Halt(pThis->Dbgc.pUVM); 1811 /* The reply will be send in the event loop. */ 1812 } 1813 1814 /* Not found, ignore the received data and reset the packet buffer. */ 1815 dbgcGdbStubCtxPktBufReset(pThis); 1816 *pcbProcessed = cbData; 1817 } 1818 1819 return rc; 1820 } 1821 1822 1823 /** 1824 * Searches for the end character in the current data buffer. 1825 * 1826 * @returns Status code. 1827 * @param pThis The GDB stub context. 1828 * @param cbData Number of new bytes in the packet buffer. 1829 * @param pcbProcessed Where to store the amount of bytes processed. 1830 */ 1831 static int dbgcGdbStubCtxPktBufSearchEnd(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed) 1832 { 1833 const uint8_t *pbEnd = (const uint8_t *)memchr(&pThis->pbPktBuf[pThis->offPktBuf], GDBSTUB_PKT_END, cbData); 1834 if (pbEnd) 1835 { 1836 /* Found the end character, next comes the checksum. */ 1837 pThis->enmState = GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM; 1838 1839 *pcbProcessed = (uintptr_t)(pbEnd - &pThis->pbPktBuf[pThis->offPktBuf]) + 1; 1840 pThis->offPktBuf += *pcbProcessed; 1841 pThis->cbPkt = pThis->offPktBuf - 1; /* Don't account for the start and end character. */ 1842 } 1843 else 1844 { 1845 /* Not found, still in the middle of a packet. */ 1846 /** @todo Look for out of band characters. */ 1847 *pcbProcessed = cbData; 1848 pThis->offPktBuf += cbData; 1849 } 1850 1851 return VINF_SUCCESS; 1852 } 1853 1854 1855 /** 1856 * Processes the checksum. 1857 * 1858 * @returns Status code. 1859 * @param pThis The GDB stub context. 1860 * @param cbData Number of new bytes in the packet buffer. 1861 * @param pcbProcessed Where to store the amount of bytes processed. 1862 */ 1863 static int dbgcGdbStubCtxPktBufProcessChksum(PGDBSTUBCTX pThis, size_t cbData, size_t *pcbProcessed) 1864 { 1865 int rc = VINF_SUCCESS; 1866 size_t cbChksumProcessed = (cbData < pThis->cbChksumRecvLeft) ? cbData : pThis->cbChksumRecvLeft; 1867 1868 pThis->cbChksumRecvLeft -= cbChksumProcessed; 1869 if (!pThis->cbChksumRecvLeft) 1870 { 1871 /* Verify checksum of the whole packet. */ 1872 uint8_t uChkSum = dbgcGdbStubCtxChrToHex(pThis->pbPktBuf[pThis->offPktBuf]) << 4 1873 | dbgcGdbStubCtxChrToHex(pThis->pbPktBuf[pThis->offPktBuf + 1]); 1874 1875 uint8_t uSum = 0; 1876 for (uint32_t i = 1; i < pThis->cbPkt; i++) 1877 uSum += pThis->pbPktBuf[i]; 1878 1879 if (uSum == uChkSum) 1880 { 1881 /* Checksum matches, send acknowledge and continue processing the complete payload. */ 1882 char chAck = '+'; 1883 rc = dbgcGdbStubCtxWrite(pThis, &chAck, sizeof(chAck)); 1884 if (RT_SUCCESS(rc)) 1885 rc = dbgcGdbStubCtxPktProcess(pThis); 1886 } 1887 else 1888 { 1889 /* Send NACK and reset for the next packet. */ 1890 char chAck = '-'; 1891 rc = dbgcGdbStubCtxWrite(pThis, &chAck, sizeof(chAck)); 1892 } 1893 1894 dbgcGdbStubCtxReset(pThis); 1895 } 1896 1897 *pcbProcessed += cbChksumProcessed; 1898 return rc; 1899 } 1900 1901 1902 /** 1903 * Process read data in the packet buffer based on the current state. 1904 * 1905 * @returns Status code. 1906 * @param pThis The GDB stub context. 1907 * @param cbData Number of new bytes in the packet buffer. 1908 */ 1909 static int dbgcGdbStubCtxPktBufProcess(PGDBSTUBCTX pThis, size_t cbData) 1910 { 1911 int rc = VINF_SUCCESS; 1912 1913 while ( cbData 1914 && RT_SUCCESS(rc)) 1915 { 1916 size_t cbProcessed = 0; 1917 1918 switch (pThis->enmState) 1919 { 1920 case GDBSTUBRECVSTATE_PACKET_WAIT_FOR_START: 1921 { 1922 rc = dbgcGdbStubCtxPktBufSearchStart(pThis, cbData, &cbProcessed); 1923 break; 1924 } 1925 case GDBSTUBRECVSTATE_PACKET_RECEIVE_BODY: 1926 { 1927 rc = dbgcGdbStubCtxPktBufSearchEnd(pThis, cbData, &cbProcessed); 1928 break; 1929 } 1930 case GDBSTUBRECVSTATE_PACKET_RECEIVE_CHECKSUM: 1931 { 1932 rc = dbgcGdbStubCtxPktBufProcessChksum(pThis, cbData, &cbProcessed); 1933 break; 1934 } 1935 default: 1936 /* Should never happen. */ 1937 rc = VERR_INTERNAL_ERROR; 1938 } 1939 1940 cbData -= cbProcessed; 1941 } 1942 1943 return rc; 1944 } 1945 1946 1947 /** 1948 * Receive data and processes complete packets. 1949 * 1950 * @returns Status code. 1951 * @param pThis The GDB stub context. 1952 */ 1953 static int dbgcGdbStubCtxRecv(PGDBSTUBCTX pThis) 1954 { 1955 /* 1956 * Read in 32 bytes chunks for now (need some peek API to get the amount of bytes actually available 1957 * to make it a bit more optimized). 1958 */ 1959 int rc = dbgcGdbStubCtxEnsurePktBufSpace(pThis, 32); 1960 if (RT_SUCCESS(rc)) 1961 { 1962 size_t cbThisRead = 32; 1963 rc = pThis->Dbgc.pBack->pfnRead(pThis->Dbgc.pBack, &pThis->pbPktBuf[pThis->offPktBuf], cbThisRead, &cbThisRead); 1964 if (RT_SUCCESS(rc)) 1965 rc = dbgcGdbStubCtxPktBufProcess(pThis, cbThisRead); 1966 } 1967 1968 return rc; 1969 } 1970 1971 1972 /** 1973 * Processes debugger events. 1974 * 1975 * @returns VBox status code. 1976 * @param pThis The GDB stub context data. 1977 * @param pEvent Pointer to event data. 1978 */ 1979 static int dbgcGdbStubCtxProcessEvent(PGDBSTUBCTX pThis, PCDBGFEVENT pEvent) 1980 { 1981 /* 1982 * Process the event. 1983 */ 1984 pThis->Dbgc.pszScratch = &pThis->Dbgc.achInput[0]; 1985 pThis->Dbgc.iArg = 0; 1986 int rc = VINF_SUCCESS; 1987 switch (pEvent->enmType) 1988 { 1989 /* 1990 * The first part is events we have initiated with commands. 1991 */ 1992 case DBGFEVENT_HALT_DONE: 1993 { 1994 rc = dbgcGdbStubCtxReplySendSigTrap(pThis); 1995 break; 1996 } 1997 1998 1999 #if 0 2000 /* 2001 * The second part is events which can occur at any time. 2002 */ 2003 case DBGFEVENT_FATAL_ERROR: 2004 { 2005 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n", 2006 dbgcGetEventCtx(pEvent->enmCtx)); 2007 if (RT_SUCCESS(rc)) 2008 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2009 break; 2010 } 2011 #endif 2012 2013 case DBGFEVENT_BREAKPOINT: 2014 case DBGFEVENT_BREAKPOINT_IO: 2015 case DBGFEVENT_BREAKPOINT_MMIO: 2016 case DBGFEVENT_BREAKPOINT_HYPER: 2017 { 2018 rc = dbgcGdbStubCtxReplySendSigTrap(pThis); 2019 break; 2020 } 2021 2022 case DBGFEVENT_STEPPED: 2023 case DBGFEVENT_STEPPED_HYPER: 2024 { 2025 rc = dbgcGdbStubCtxReplySendSigTrap(pThis); 2026 break; 2027 } 2028 2029 #if 0 2030 case DBGFEVENT_ASSERTION_HYPER: 2031 { 2032 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2033 "\ndbgf event: Hypervisor Assertion! (%s)\n" 2034 "%s" 2035 "%s" 2036 "\n", 2037 dbgcGetEventCtx(pEvent->enmCtx), 2038 pEvent->u.Assert.pszMsg1, 2039 pEvent->u.Assert.pszMsg2); 2040 if (RT_SUCCESS(rc)) 2041 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2042 break; 2043 } 2044 2045 case DBGFEVENT_DEV_STOP: 2046 { 2047 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2048 "\n" 2049 "dbgf event: DBGFSTOP (%s)\n" 2050 "File: %s\n" 2051 "Line: %d\n" 2052 "Function: %s\n", 2053 dbgcGetEventCtx(pEvent->enmCtx), 2054 pEvent->u.Src.pszFile, 2055 pEvent->u.Src.uLine, 2056 pEvent->u.Src.pszFunction); 2057 if (RT_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage) 2058 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, 2059 "Message: %s\n", 2060 pEvent->u.Src.pszMessage); 2061 if (RT_SUCCESS(rc)) 2062 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r"); 2063 break; 2064 } 2065 2066 2067 case DBGFEVENT_INVALID_COMMAND: 2068 { 2069 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n"); 2070 break; 2071 } 2072 #endif 2073 2074 case DBGFEVENT_POWERING_OFF: 2075 { 2076 pThis->Dbgc.fReady = false; 2077 pThis->Dbgc.pBack->pfnSetReady(pThis->Dbgc.pBack, false); 2078 rc = VERR_GENERAL_FAILURE; 2079 break; 2080 } 2081 2082 #if 0 2083 default: 2084 { 2085 /* 2086 * Probably a generic event. Look it up to find its name. 2087 */ 2088 PCDBGCSXEVT pEvtDesc = dbgcEventLookup(pEvent->enmType); 2089 if (pEvtDesc) 2090 { 2091 if (pEvtDesc->enmKind == kDbgcSxEventKind_Interrupt) 2092 { 2093 Assert(pEvtDesc->pszDesc); 2094 Assert(pEvent->u.Generic.cArgs == 1); 2095 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s no %#llx! (%s)\n", 2096 pEvtDesc->pszDesc, pEvent->u.Generic.auArgs[0], pEvtDesc->pszName); 2097 } 2098 else if (pEvtDesc->fFlags & DBGCSXEVT_F_BUGCHECK) 2099 { 2100 Assert(pEvent->u.Generic.cArgs >= 5); 2101 char szDetails[512]; 2102 DBGFR3FormatBugCheck(pDbgc->pUVM, szDetails, sizeof(szDetails), pEvent->u.Generic.auArgs[0], 2103 pEvent->u.Generic.auArgs[1], pEvent->u.Generic.auArgs[2], 2104 pEvent->u.Generic.auArgs[3], pEvent->u.Generic.auArgs[4]); 2105 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s %s%s!\n%s", pEvtDesc->pszName, 2106 pEvtDesc->pszDesc ? "- " : "", pEvtDesc->pszDesc ? pEvtDesc->pszDesc : "", 2107 szDetails); 2108 } 2109 else if ( (pEvtDesc->fFlags & DBGCSXEVT_F_TAKE_ARG) 2110 || pEvent->u.Generic.cArgs > 1 2111 || ( pEvent->u.Generic.cArgs == 1 2112 && pEvent->u.Generic.auArgs[0] != 0)) 2113 { 2114 if (pEvtDesc->pszDesc) 2115 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!", 2116 pEvtDesc->pszName, pEvtDesc->pszDesc); 2117 else 2118 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!", pEvtDesc->pszName); 2119 if (pEvent->u.Generic.cArgs <= 1) 2120 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " arg=%#llx\n", pEvent->u.Generic.auArgs[0]); 2121 else 2122 { 2123 for (uint32_t i = 0; i < pEvent->u.Generic.cArgs; i++) 2124 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " args[%u]=%#llx", i, pEvent->u.Generic.auArgs[i]); 2125 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n"); 2126 } 2127 } 2128 else 2129 { 2130 if (pEvtDesc->pszDesc) 2131 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s - %s!\n", 2132 pEvtDesc->pszName, pEvtDesc->pszDesc); 2133 else 2134 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: %s!\n", pEvtDesc->pszName); 2135 } 2136 } 2137 else 2138 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType); 2139 break; 2140 } 2141 } 2142 2143 /* 2144 * Prompt, anyone? 2145 */ 2146 if (fPrintPrompt && RT_SUCCESS(rc)) 2147 { 2148 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); 2149 pDbgc->fReady = true; 2150 if (RT_SUCCESS(rc)) 2151 pDbgc->pBack->pfnSetReady(pDbgc->pBack, true); 2152 pDbgc->cMultiStepsLeft = 0; 2153 } 2154 #else 2155 default: 2156 break; 2157 } 2158 #endif 2159 2160 return rc; 2161 } 2162 2163 2164 /** 2165 * Run the debugger console. 2166 * 2167 * @returns VBox status code. 2168 * @param pDbgc Pointer to the debugger console instance data. 2169 */ 2170 int dbgcGdbStubRun(PGDBSTUBCTX pThis) 2171 { 2172 /* 2173 * We're ready for commands now. 2174 */ 2175 pThis->Dbgc.fReady = true; 2176 pThis->Dbgc.pBack->pfnSetReady(pThis->Dbgc.pBack, true); 2177 2178 /* 2179 * Main Debugger Loop. 2180 * 2181 * This loop will either block on waiting for input or on waiting on 2182 * debug events. If we're forwarding the log we cannot wait for long 2183 * before we must flush the log. 2184 */ 2185 int rc; 2186 for (;;) 2187 { 2188 rc = VERR_SEM_OUT_OF_TURN; 2189 if (pThis->Dbgc.pUVM) 2190 rc = DBGFR3QueryWaitable(pThis->Dbgc.pUVM); 2191 2192 if (RT_SUCCESS(rc)) 2193 { 2194 /* 2195 * Wait for a debug event. 2196 */ 2197 PCDBGFEVENT pEvent; 2198 rc = DBGFR3EventWait(pThis->Dbgc.pUVM, 32, &pEvent); 2199 if (RT_SUCCESS(rc)) 2200 { 2201 rc = dbgcGdbStubCtxProcessEvent(pThis, pEvent); 2202 if (RT_FAILURE(rc)) 2203 break; 2204 } 2205 else if (rc != VERR_TIMEOUT) 2206 break; 2207 2208 /* 2209 * Check for input. 2210 */ 2211 if (pThis->Dbgc.pBack->pfnInput(pThis->Dbgc.pBack, 0)) 2212 { 2213 rc = dbgcGdbStubCtxRecv(pThis); 2214 if (RT_FAILURE(rc)) 2215 break; 2216 } 2217 } 2218 else if (rc == VERR_SEM_OUT_OF_TURN) 2219 { 2220 /* 2221 * Wait for input. 2222 */ 2223 if (pThis->Dbgc.pBack->pfnInput(pThis->Dbgc.pBack, 1000)) 2224 { 2225 rc = dbgcGdbStubCtxRecv(pThis); 2226 if (RT_FAILURE(rc)) 2227 break; 2228 } 2229 } 2230 else 2231 break; 2232 } 2233 2234 return rc; 2235 } 2236 2237 2238 /** 2239 * Creates a GDB stub context instance with the given backend. 2240 * 2241 * @returns VBox status code. 2242 * @param ppGdbStubCtx Where to store the pointer to the GDB stub context instance on success. 2243 * @param pBack The backend to use for I/O. 2244 * @param fFlags Flags controlling the behavior. 2245 */ 2246 static int dbgcGdbStubCtxCreate(PPGDBSTUBCTX ppGdbStubCtx, PDBGCBACK pBack, unsigned fFlags) 2247 { 2248 /* 2249 * Validate input. 2250 */ 2251 AssertPtrReturn(pBack, VERR_INVALID_POINTER); 2252 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER); 2253 2254 /* 2255 * Allocate and initialize. 2256 */ 2257 PGDBSTUBCTX pThis = (PGDBSTUBCTX)RTMemAllocZ(sizeof(*pThis)); 2258 if (!pThis) 2259 return VERR_NO_MEMORY; 2260 2261 dbgcInitCmdHlp(&pThis->Dbgc); 2262 /* 2263 * This is compied from the native debug console (will be used for monitor commands) 2264 * in DBGCConsole.cpp. Try to keep both functions in sync. 2265 */ 2266 pThis->Dbgc.pBack = pBack; 2267 pThis->Dbgc.pVM = NULL; 2268 pThis->Dbgc.pUVM = NULL; 2269 pThis->Dbgc.idCpu = 0; 2270 pThis->Dbgc.hDbgAs = DBGF_AS_GLOBAL; 2271 pThis->Dbgc.pszEmulation = "CodeView/WinDbg"; 2272 pThis->Dbgc.paEmulationCmds = &g_aCmdsCodeView[0]; 2273 pThis->Dbgc.cEmulationCmds = g_cCmdsCodeView; 2274 pThis->Dbgc.paEmulationFuncs = &g_aFuncsCodeView[0]; 2275 pThis->Dbgc.cEmulationFuncs = g_cFuncsCodeView; 2276 //pThis->Dbgc.fLog = false; 2277 pThis->Dbgc.fRegTerse = true; 2278 pThis->Dbgc.fStepTraceRegs = true; 2279 //pThis->Dbgc.cPagingHierarchyDumps = 0; 2280 //pThis->Dbgc.DisasmPos = {0}; 2281 //pThis->Dbgc.SourcePos = {0}; 2282 //pThis->Dbgc.DumpPos = {0}; 2283 pThis->Dbgc.pLastPos = &pThis->Dbgc.DisasmPos; 2284 //pThis->Dbgc.cbDumpElement = 0; 2285 //pThis->Dbgc.cVars = 0; 2286 //pThis->Dbgc.paVars = NULL; 2287 //pThis->Dbgc.pPlugInHead = NULL; 2288 //pThis->Dbgc.pFirstBp = NULL; 2289 //pThis->Dbgc.abSearch = {0}; 2290 //pThis->Dbgc.cbSearch = 0; 2291 pThis->Dbgc.cbSearchUnit = 1; 2292 pThis->Dbgc.cMaxSearchHits = 1; 2293 //pThis->Dbgc.SearchAddr = {0}; 2294 //pThis->Dbgc.cbSearchRange = 0; 2295 2296 //pThis->Dbgc.uInputZero = 0; 2297 //pThis->Dbgc.iRead = 0; 2298 //pThis->Dbgc.iWrite = 0; 2299 //pThis->Dbgc.cInputLines = 0; 2300 //pThis->Dbgc.fInputOverflow = false; 2301 pThis->Dbgc.fReady = true; 2302 pThis->Dbgc.pszScratch = &pThis->Dbgc.achScratch[0]; 2303 //pThis->Dbgc.iArg = 0; 2304 //pThis->Dbgc.rcOutput = 0; 2305 //pThis->Dbgc.rcCmd = 0; 2306 2307 //pThis->Dbgc.pszHistoryFile = NULL; 2308 //pThis->Dbgc.pszGlobalInitScript = NULL; 2309 //pThis->Dbgc.pszLocalInitScript = NULL; 2310 2311 dbgcEvalInit(); 2312 2313 /* Init the GDB stub specific parts. */ 2314 pThis->cbPktBufMax = 0; 2315 pThis->pbPktBuf = NULL; 2316 pThis->fFeatures = GDBSTUBCTX_FEATURES_F_TGT_DESC; 2317 pThis->pachTgtXmlDesc = NULL; 2318 pThis->cbTgtXmlDesc = 0; 2319 pThis->fExtendedMode = false; 2320 dbgcGdbStubCtxReset(pThis); 2321 2322 *ppGdbStubCtx = pThis; 2323 return VINF_SUCCESS; 2324 } 2325 2326 2327 /** 2328 * Destroys the given GDB stub context. 2329 * 2330 * @returns nothing. 2331 * @param pThis The GDB stub context to destroy. 2332 */ 2333 static void dbgcGdbStubDestroy(PGDBSTUBCTX pThis) 2334 { 2335 AssertPtr(pThis); 2336 2337 /* Detach from the VM. */ 2338 if (pThis->Dbgc.pUVM) 2339 DBGFR3Detach(pThis->Dbgc.pUVM); 2340 2341 /* Free config strings. */ 2342 RTStrFree(pThis->Dbgc.pszGlobalInitScript); 2343 pThis->Dbgc.pszGlobalInitScript = NULL; 2344 RTStrFree(pThis->Dbgc.pszLocalInitScript); 2345 pThis->Dbgc.pszLocalInitScript = NULL; 2346 RTStrFree(pThis->Dbgc.pszHistoryFile); 2347 pThis->Dbgc.pszHistoryFile = NULL; 2348 2349 /* Finally, free the instance memory. */ 2350 RTMemFree(pThis); 2351 } 2352 2353 2354 DECLHIDDEN(int) dbgcGdbStubCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags) 2355 { 2356 /* 2357 * Validate input. 2358 */ 2359 AssertPtrNullReturn(pUVM, VERR_INVALID_VM_HANDLE); 2360 PVM pVM = NULL; 2361 if (pUVM) 2362 { 2363 pVM = VMR3GetVM(pUVM); 2364 AssertPtrReturn(pVM, VERR_INVALID_VM_HANDLE); 2365 } 2366 2367 /* 2368 * Allocate and initialize instance data 2369 */ 2370 PGDBSTUBCTX pThis; 2371 int rc = dbgcGdbStubCtxCreate(&pThis, pBack, fFlags); 2372 if (RT_FAILURE(rc)) 2373 return rc; 2374 if (!HMR3IsEnabled(pUVM) && !NEMR3IsEnabled(pUVM)) 2375 pThis->Dbgc.hDbgAs = DBGF_AS_RC_AND_GC_GLOBAL; 2376 2377 /* 2378 * Attach to the specified VM. 2379 */ 2380 if (RT_SUCCESS(rc) && pUVM) 2381 { 2382 rc = DBGFR3Attach(pUVM); 2383 if (RT_SUCCESS(rc)) 2384 { 2385 pThis->Dbgc.pVM = pVM; 2386 pThis->Dbgc.pUVM = pUVM; 2387 pThis->Dbgc.idCpu = 0; 2388 } 2389 else 2390 rc = pThis->Dbgc.CmdHlp.pfnVBoxError(&pThis->Dbgc.CmdHlp, rc, "When trying to attach to VM %p\n", pThis->Dbgc.pVM); 2391 } 2392 2393 /* 2394 * Load plugins. 2395 */ 2396 if (RT_SUCCESS(rc)) 2397 { 2398 if (pVM) 2399 DBGFR3PlugInLoadAll(pThis->Dbgc.pUVM); 2400 dbgcEventInit(&pThis->Dbgc); 2401 //dbgcRunInitScripts(pDbgc); Not yet 2402 2403 if (!DBGFR3IsHalted(pThis->Dbgc.pUVM)) 2404 rc = DBGFR3Halt(pThis->Dbgc.pUVM); 2405 2406 /* 2407 * Run the debugger main loop. 2408 */ 2409 rc = dbgcGdbStubRun(pThis); 2410 dbgcEventTerm(&pThis->Dbgc); 2411 } 2412 2413 /* 2414 * Cleanup console debugger session. 2415 */ 2416 dbgcGdbStubDestroy(pThis); 2417 return rc == VERR_DBGC_QUIT ? VINF_SUCCESS : rc; 2418 } 2419 -
trunk/src/VBox/Debugger/DBGCInternal.h
r83088 r84627 588 588 589 589 590 DECLHIDDEN(int) dbgcGdbStubCreate(PUVM pUVM, PDBGCBACK pBack, unsigned fFlags); 591 592 590 593 /******************************************************************************* 591 594 * Global Variables * -
trunk/src/VBox/Debugger/DBGCTcp.cpp
r82968 r84627 30 30 31 31 #include <iprt/string.h> 32 33 #include "DBGCInternal.h" 32 34 33 35 … … 168 170 } 169 171 172 /** 173 * Write (output) - raw version not converting any newlines. 174 * 175 * @returns VBox status code. 176 * @param pBack Pointer to the backend structure supplied by 177 * the backend. The backend can use this to find 178 * it's instance data. 179 * @param pvBuf What to write. 180 * @param cbBuf Number of bytes to write. 181 * @param pcbWritten Where to store the number of bytes actually written. 182 * If NULL the entire buffer must be successfully written. 183 */ 184 static DECLCALLBACK(int) dbgcTcpBackWriteRaw(PDBGCBACK pBack, const void *pvBuf, size_t cbBuf, size_t *pcbWritten) 185 { 186 PDBGCTCP pDbgcTcp = DBGCTCP_BACK2DBGCTCP(pBack); 187 if (!pDbgcTcp->fAlive) 188 return VERR_INVALID_HANDLE; 189 190 int rc = RTTcpWrite(pDbgcTcp->Sock, pvBuf, cbBuf); 191 if (RT_FAILURE(rc)) 192 pDbgcTcp->fAlive = false; 193 194 if (pcbWritten) 195 *pcbWritten = cbBuf; 196 197 return rc; 198 } 199 170 200 /** @copydoc FNDBGCBACKSETREADY */ 171 201 static DECLCALLBACK(void) dbgcTcpBackSetReady(PDBGCBACK pBack, bool fReady) … … 191 221 LogFlow(("dbgcTcpConnection: connection! Sock=%d pvUser=%p\n", Sock, pvUser)); 192 222 223 PUVM pUVM = (PUVM)pvUser; 224 PCFGMNODE pKey = CFGMR3GetChild(CFGMR3GetRootU(pUVM), "DBGC"); 225 bool fGdbStub = false; 226 int rc = CFGMR3QueryBoolDef(pKey, "GdbStub", &fGdbStub, false); 227 if (RT_FAILURE(rc)) 228 return VM_SET_ERROR_U(pUVM, rc, "Configuration error: Failed querying \"DBGC/GdbStub\""); 229 193 230 /* 194 231 * Start the console. 195 232 */ 196 233 DBGCTCP DbgcTcp; 197 DbgcTcp.Back.pfnInput = dbgcTcpBackInput; 198 DbgcTcp.Back.pfnRead = dbgcTcpBackRead; 199 DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite; 200 DbgcTcp.Back.pfnSetReady = dbgcTcpBackSetReady; 234 DbgcTcp.Back.pfnInput = dbgcTcpBackInput; 235 DbgcTcp.Back.pfnRead = dbgcTcpBackRead; 236 if (fGdbStub) 237 DbgcTcp.Back.pfnWrite = dbgcTcpBackWriteRaw; 238 else 239 DbgcTcp.Back.pfnWrite = dbgcTcpBackWrite; 240 DbgcTcp.Back.pfnSetReady = dbgcTcpBackSetReady; 201 241 DbgcTcp.fAlive = true; 202 242 DbgcTcp.Sock = Sock; 203 int rc = DBGCCreate((PUVM)pvUser, &DbgcTcp.Back, 0); 243 if (fGdbStub) 244 rc = dbgcGdbStubCreate(pUVM, &DbgcTcp.Back, 0); 245 else 246 rc = DBGCCreate(pUVM, &DbgcTcp.Back, 0); 204 247 LogFlow(("dbgcTcpConnection: disconnect rc=%Rrc\n", rc)); 205 248 return rc; -
trunk/src/VBox/Debugger/DBGConsole.cpp
r83088 r84627 1034 1034 "HistoryFile|" 1035 1035 "LocalInitScript|" 1036 "GlobalInitScript", 1036 "GlobalInitScript|" 1037 "GdbStub", 1037 1038 "", "DBGC", 0); 1038 1039 AssertRCReturn(rc, rc);
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器