vbox的更動 59072 路徑 trunk/src/VBox/Debugger
- 時間撮記:
- 2015-12-9 下午10:58:30 (9 年 以前)
- 位置:
- trunk/src/VBox/Debugger
- 檔案:
-
- 修改 4 筆資料
圖例:
- 未更動
- 新增
- 刪除
-
trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
r59062 r59072 288 288 { 0, 1, DBGCVAR_CAT_STRING, 0, "-c", "The -c option, requires <cmds>." }, 289 289 { 0, 1, DBGCVAR_CAT_STRING, DBGCVD_FLAGS_DEP_PREV, "cmds", "Command to execute on this event." }, 290 { 1,~0U, DBGCVAR_CAT_STRING, 0, "event", "One or more events, 'all' refering to all events." },290 { 0 /*weird*/, ~0U, DBGCVAR_CAT_STRING, 0, "event", "One or more events, 'all' refering to all events." }, 291 291 }; 292 292 … … 382 382 { "su", 2, ~0U, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType),0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for an unicode string." }, 383 383 { "sw", 2, ~0U, &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType),0, dbgcCmdSearchMemType, "<range> <pattern>", "Search memory for one or more words." }, 384 { "sx", 0, 0,&g_aArgEventCtrlOpt[0], RT_ELEMENTS(g_aArgEventCtrlOpt), 0, dbgcCmdEventCtrlList, "[<event> [..]]", "Lists settings for exceptions, exits and other events. All if no filter is specified." },385 { "sx-", 2, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "-c <cmd> <event> [..]", "Modifies the command for one or more exceptions, exits or other event. 'all' addresses all." },386 { "sxe", 2, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Enable: Break into the debugger on the specified exceptions, exits and other events. 'all' addresses all." },387 { "sxn", 2, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Notify: Display info in the debugger and continue on the specified exceptions, exits and other events. 'all' addresses all." },388 { "sxi", 2, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Ignore: Ignore the specified exceptions, exits and other events ('all' = all of them). Without the -c option, the guest runs like normal." },384 { "sx", 0, ~0U, &g_aArgEventCtrlOpt[0], RT_ELEMENTS(g_aArgEventCtrlOpt), 0, dbgcCmdEventCtrlList, "[<event> [..]]", "Lists settings for exceptions, exits and other events. All if no filter is specified." }, 385 { "sx-", 3, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "-c <cmd> <event> [..]", "Modifies the command for one or more exceptions, exits or other event. 'all' addresses all." }, 386 { "sxe", 1, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Enable: Break into the debugger on the specified exceptions, exits and other events. 'all' addresses all." }, 387 { "sxn", 1, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Notify: Display info in the debugger and continue on the specified exceptions, exits and other events. 'all' addresses all." }, 388 { "sxi", 1, ~0U, &g_aArgEventCtrl[0], RT_ELEMENTS(g_aArgEventCtrl), 0, dbgcCmdEventCtrl, "[-c <cmd>] <event> [..]", "Ignore: Ignore the specified exceptions, exits and other events ('all' = all of them). Without the -c option, the guest runs like normal." }, 389 389 { "sxr", 0, 0, &g_aArgEventCtrlOpt[0], RT_ELEMENTS(g_aArgEventCtrlOpt), 0, dbgcCmdEventCtrlReset, "", "Reset the settings to default for exceptions, exits and other events. All if no filter is specified." }, 390 390 { "t", 0, 0, NULL, 0, 0, dbgcCmdTrace, "", "Instruction trace (step into)." }, … … 400 400 401 401 402 403 404 /** 405 * @callback_method_impl{FNDBGCCMD, The 'go' command.} 406 */ 407 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 408 { 409 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 410 411 /* 412 * Check if the VM is halted or not before trying to resume it. 413 */ 414 if (!DBGFR3IsHalted(pUVM)) 415 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The VM is already running"); 416 417 int rc = DBGFR3Resume(pUVM); 418 if (RT_FAILURE(rc)) 419 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3Resume"); 420 421 NOREF(paArgs); NOREF(cArgs); 422 return VINF_SUCCESS; 423 } 424 425 426 /** 427 * @callback_method_impl{FNDBGCCMD, The 'ba' command.} 428 */ 429 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 430 { 431 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 432 433 /* 434 * Interpret access type. 435 */ 436 if ( !strchr("xrwi", paArgs[0].u.pszString[0]) 437 || paArgs[0].u.pszString[1]) 438 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'", 439 paArgs[0].u.pszString, pCmd->pszCmd); 440 uint8_t fType = 0; 441 switch (paArgs[0].u.pszString[0]) 442 { 443 case 'x': fType = X86_DR7_RW_EO; break; 444 case 'r': fType = X86_DR7_RW_RW; break; 445 case 'w': fType = X86_DR7_RW_WO; break; 446 case 'i': fType = X86_DR7_RW_IO; break; 447 } 448 449 /* 450 * Validate size. 451 */ 452 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1) 453 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access size %RX64 for '%s'. 'x' access type requires size 1!", 454 paArgs[1].u.u64Number, pCmd->pszCmd); 455 switch (paArgs[1].u.u64Number) 456 { 457 case 1: 458 case 2: 459 case 4: 460 break; 461 /*case 8: - later*/ 462 default: 463 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access size %RX64 for '%s'. 1, 2 or 4!", 464 paArgs[1].u.u64Number, pCmd->pszCmd); 465 } 466 uint8_t cb = (uint8_t)paArgs[1].u.u64Number; 467 468 /* 469 * Convert the pointer to a DBGF address. 470 */ 471 DBGFADDRESS Address; 472 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address); 473 if (RT_FAILURE(rc)) 474 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,%DV,)", &paArgs[2]); 475 476 /* 477 * Pick out the optional arguments. 478 */ 479 uint64_t iHitTrigger = 0; 480 uint64_t iHitDisable = ~0; 481 const char *pszCmds = NULL; 482 unsigned iArg = 3; 483 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 484 { 485 iHitTrigger = paArgs[iArg].u.u64Number; 486 iArg++; 487 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 488 { 489 iHitDisable = paArgs[iArg].u.u64Number; 490 iArg++; 491 } 492 } 493 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 494 { 495 pszCmds = paArgs[iArg].u.pszString; 496 iArg++; 497 } 498 499 /* 500 * Try set the breakpoint. 501 */ 502 uint32_t iBp; 503 rc = DBGFR3BpSetReg(pUVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp); 504 if (RT_SUCCESS(rc)) 505 { 506 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 507 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 508 if (RT_SUCCESS(rc)) 509 return DBGCCmdHlpPrintf(pCmdHlp, "Set access breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 510 if (rc == VERR_DBGC_BP_EXISTS) 511 { 512 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 513 if (RT_SUCCESS(rc)) 514 return DBGCCmdHlpPrintf(pCmdHlp, "Updated access breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 515 } 516 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 517 AssertRC(rc2); 518 } 519 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set access breakpoint at %RGv", Address.FlatPtr); 520 } 521 522 523 /** 524 * @callback_method_impl{FNDBGCCMD, The 'bc' command.} 525 */ 526 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 527 { 528 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 529 530 /* 531 * Enumerate the arguments. 532 */ 533 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 534 int rc = VINF_SUCCESS; 535 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 536 { 537 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 538 { 539 /* one */ 540 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 541 if (iBp == paArgs[iArg].u.u64Number) 542 { 543 int rc2 = DBGFR3BpClear(pUVM, iBp); 544 if (RT_FAILURE(rc2)) 545 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpClear(,%#x)", iBp); 546 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 547 dbgcBpDelete(pDbgc, iBp); 548 } 549 else 550 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 551 } 552 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 553 { 554 /* all */ 555 PDBGCBP pBp = pDbgc->pFirstBp; 556 while (pBp) 557 { 558 uint32_t iBp = pBp->iBp; 559 pBp = pBp->pNext; 560 561 int rc2 = DBGFR3BpClear(pUVM, iBp); 562 if (RT_FAILURE(rc2)) 563 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpClear(,%#x)", iBp); 564 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 565 dbgcBpDelete(pDbgc, iBp); 566 } 567 } 568 else 569 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 570 } 571 return rc; 572 } 573 574 575 /** 576 * @callback_method_impl{FNDBGCCMD, The 'bd' command.} 577 */ 578 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 579 { 580 /* 581 * Enumerate the arguments. 582 */ 583 int rc = VINF_SUCCESS; 584 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 585 { 586 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 587 { 588 /* one */ 589 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 590 if (iBp == paArgs[iArg].u.u64Number) 591 { 592 rc = DBGFR3BpDisable(pUVM, iBp); 593 if (RT_FAILURE(rc)) 594 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpDisable failed for breakpoint %#x", iBp); 595 } 596 else 597 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 598 } 599 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 600 { 601 /* all */ 602 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 603 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 604 { 605 int rc2 = DBGFR3BpDisable(pUVM, pBp->iBp); 606 if (RT_FAILURE(rc2)) 607 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpDisable failed for breakpoint %#x", pBp->iBp); 608 } 609 } 610 else 611 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 612 } 613 return rc; 614 } 615 616 617 /** 618 * @callback_method_impl{FNDBGCCMD, The 'be' command.} 619 */ 620 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 621 { 622 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 623 624 /* 625 * Enumerate the arguments. 626 */ 627 int rc = VINF_SUCCESS; 628 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 629 { 630 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 631 { 632 /* one */ 633 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 634 if (iBp == paArgs[iArg].u.u64Number) 635 { 636 rc = DBGFR3BpEnable(pUVM, iBp); 637 if (RT_FAILURE(rc)) 638 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpEnable failed for breakpoint %#x", iBp); 639 } 640 else 641 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 642 } 643 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 644 { 645 /* all */ 646 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 647 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 648 { 649 int rc2 = DBGFR3BpEnable(pUVM, pBp->iBp); 650 if (RT_FAILURE(rc2)) 651 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpEnable failed for breakpoint %#x", pBp->iBp); 652 } 653 } 654 else 655 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 656 } 657 return rc; 658 } 659 660 661 /** 662 * Breakpoint enumeration callback function. 402 /** 403 * Selectable debug event descriptors. 663 404 * 664 * @returns VBox status code. Any failure will stop the enumeration. 665 * @param pUVM The user mode VM handle. 666 * @param pvUser The user argument. 667 * @param pBp Pointer to the breakpoint information. (readonly) 668 */ 669 static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PUVM pUVM, void *pvUser, PCDBGFBP pBp) 670 { 671 PDBGC pDbgc = (PDBGC)pvUser; 672 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp); 673 674 /* 675 * BP type and size. 676 */ 677 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%#4x %c ", pBp->iBp, pBp->fEnabled ? 'e' : 'd'); 678 bool fHasAddress = false; 679 switch (pBp->enmType) 680 { 681 case DBGFBPTYPE_INT3: 682 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " p %RGv", pBp->u.Int3.GCPtr); 683 fHasAddress = true; 684 break; 685 case DBGFBPTYPE_REG: 686 { 687 char chType; 688 switch (pBp->u.Reg.fType) 689 { 690 case X86_DR7_RW_EO: chType = 'x'; break; 691 case X86_DR7_RW_WO: chType = 'w'; break; 692 case X86_DR7_RW_IO: chType = 'i'; break; 693 case X86_DR7_RW_RW: chType = 'r'; break; 694 default: chType = '?'; break; 695 696 } 697 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%d %c %RGv", pBp->u.Reg.cb, chType, pBp->u.Reg.GCPtr); 698 fHasAddress = true; 699 break; 700 } 701 702 case DBGFBPTYPE_REM: 703 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " r %RGv", pBp->u.Rem.GCPtr); 704 fHasAddress = true; 705 break; 706 707 /** @todo realign the list when I/O and MMIO breakpoint command have been added and it's possible to test this code. */ 708 case DBGFBPTYPE_PORT_IO: 709 case DBGFBPTYPE_MMIO: 710 { 711 uint32_t fAccess = pBp->enmType == DBGFBPTYPE_PORT_IO ? pBp->u.PortIo.fAccess : pBp->u.Mmio.fAccess; 712 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, pBp->enmType == DBGFBPTYPE_PORT_IO ? " i" : " m"); 713 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %c%c%c%c%c%c", 714 fAccess & DBGFBPIOACCESS_READ_MASK ? 'r' : '-', 715 fAccess & DBGFBPIOACCESS_READ_BYTE ? '1' : '-', 716 fAccess & DBGFBPIOACCESS_READ_WORD ? '2' : '-', 717 fAccess & DBGFBPIOACCESS_READ_DWORD ? '4' : '-', 718 fAccess & DBGFBPIOACCESS_READ_QWORD ? '8' : '-', 719 fAccess & DBGFBPIOACCESS_READ_OTHER ? '+' : '-'); 720 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %c%c%c%c%c%c", 721 fAccess & DBGFBPIOACCESS_WRITE_MASK ? 'w' : '-', 722 fAccess & DBGFBPIOACCESS_WRITE_BYTE ? '1' : '-', 723 fAccess & DBGFBPIOACCESS_WRITE_WORD ? '2' : '-', 724 fAccess & DBGFBPIOACCESS_WRITE_DWORD ? '4' : '-', 725 fAccess & DBGFBPIOACCESS_WRITE_QWORD ? '8' : '-', 726 fAccess & DBGFBPIOACCESS_WRITE_OTHER ? '+' : '-'); 727 if (pBp->enmType == DBGFBPTYPE_PORT_IO) 728 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04x-%04x", 729 pBp->u.PortIo.uPort, pBp->u.PortIo.uPort + pBp->u.PortIo.cPorts - 1); 730 else 731 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%RGp LB %03x", pBp->u.Mmio.PhysAddr, pBp->u.Mmio.cb); 732 break; 733 } 734 735 default: 736 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " unknown type %d!!", pBp->enmType); 737 AssertFailed(); 738 break; 739 740 } 741 if (pBp->iHitDisable == ~(uint64_t)0) 742 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04RX64 (%04RX64 to ~0) ", pBp->cHits, pBp->iHitTrigger); 743 else 744 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04RX64 (%04RX64 to %04RX64)", pBp->cHits, pBp->iHitTrigger, pBp->iHitDisable); 745 746 /* 747 * Try resolve the address if it has one. 748 */ 749 if (fHasAddress) 750 { 751 RTDBGSYMBOL Sym; 752 RTINTPTR off; 753 DBGFADDRESS Addr; 754 int rc = DBGFR3AsSymbolByAddr(pUVM, pDbgc->hDbgAs, DBGFR3AddrFromFlat(pDbgc->pUVM, &Addr, pBp->u.GCPtr), 755 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &off, &Sym, NULL); 756 if (RT_SUCCESS(rc)) 757 { 758 if (!off) 759 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s", Sym.szName); 760 else if (off > 0) 761 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s+%RGv", Sym.szName, off); 762 else 763 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s-%RGv", Sym.szName, -off); 764 } 765 } 766 767 /* 768 * The commands. 769 */ 770 if (pDbgcBp) 771 { 772 if (pDbgcBp->cchCmd) 773 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "\n cmds: '%s'\n", pDbgcBp->szCmd); 774 else 775 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "\n"); 776 } 777 else 778 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " [unknown bp]\n"); 779 780 return VINF_SUCCESS; 781 } 782 783 784 /** 785 * @callback_method_impl{FNDBGCCMD, The 'bl' command.} 786 */ 787 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 788 { 789 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 790 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, -1, cArgs == 0); 791 NOREF(paArgs); 792 793 /* 794 * Enumerate the breakpoints. 795 */ 796 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 797 int rc = DBGFR3BpEnum(pUVM, dbgcEnumBreakpointsCallback, pDbgc); 798 if (RT_FAILURE(rc)) 799 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpEnum"); 800 return rc; 801 } 802 803 804 /** 805 * @callback_method_impl{FNDBGCCMD, The 'bp' command.} 806 */ 807 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 808 { 809 /* 810 * Convert the pointer to a DBGF address. 811 */ 812 DBGFADDRESS Address; 813 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 814 if (RT_FAILURE(rc)) 815 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,'%DV',)", &paArgs[0]); 816 817 /* 818 * Pick out the optional arguments. 819 */ 820 uint64_t iHitTrigger = 0; 821 uint64_t iHitDisable = ~0; 822 const char *pszCmds = NULL; 823 unsigned iArg = 1; 824 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 825 { 826 iHitTrigger = paArgs[iArg].u.u64Number; 827 iArg++; 828 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 829 { 830 iHitDisable = paArgs[iArg].u.u64Number; 831 iArg++; 832 } 833 } 834 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 835 { 836 pszCmds = paArgs[iArg].u.pszString; 837 iArg++; 838 } 839 840 /* 841 * Try set the breakpoint. 842 */ 843 uint32_t iBp; 844 rc = DBGFR3BpSet(pUVM, &Address, iHitTrigger, iHitDisable, &iBp); 845 if (RT_SUCCESS(rc)) 846 { 847 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 848 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 849 if (RT_SUCCESS(rc)) 850 return DBGCCmdHlpPrintf(pCmdHlp, "Set breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 851 if (rc == VERR_DBGC_BP_EXISTS) 852 { 853 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 854 if (RT_SUCCESS(rc)) 855 return DBGCCmdHlpPrintf(pCmdHlp, "Updated breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 856 } 857 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 858 AssertRC(rc2); 859 } 860 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set breakpoint at %RGv", Address.FlatPtr); 861 } 862 863 864 /** 865 * @callback_method_impl{FNDBGCCMD, The 'br' command.} 866 */ 867 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 868 { 869 /* 870 * Convert the pointer to a DBGF address. 871 */ 872 DBGFADDRESS Address; 873 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 874 if (RT_FAILURE(rc)) 875 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,'%DV',)", &paArgs[0]); 876 877 /* 878 * Pick out the optional arguments. 879 */ 880 uint64_t iHitTrigger = 0; 881 uint64_t iHitDisable = ~0; 882 const char *pszCmds = NULL; 883 unsigned iArg = 1; 884 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 885 { 886 iHitTrigger = paArgs[iArg].u.u64Number; 887 iArg++; 888 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 889 { 890 iHitDisable = paArgs[iArg].u.u64Number; 891 iArg++; 892 } 893 } 894 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 895 { 896 pszCmds = paArgs[iArg].u.pszString; 897 iArg++; 898 } 899 900 /* 901 * Try set the breakpoint. 902 */ 903 uint32_t iBp; 904 rc = DBGFR3BpSetREM(pUVM, &Address, iHitTrigger, iHitDisable, &iBp); 905 if (RT_SUCCESS(rc)) 906 { 907 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 908 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 909 if (RT_SUCCESS(rc)) 910 return DBGCCmdHlpPrintf(pCmdHlp, "Set REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 911 if (rc == VERR_DBGC_BP_EXISTS) 912 { 913 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 914 if (RT_SUCCESS(rc)) 915 return DBGCCmdHlpPrintf(pCmdHlp, "Updated REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 916 } 917 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 918 AssertRC(rc2); 919 } 920 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set REM breakpoint at %RGv", Address.FlatPtr); 921 } 922 923 924 /** 925 * Helps the unassmble ('u') command display symbols it starts at and passes. 926 * 927 * @param pUVM The user mode VM handle. 928 * @param pCmdHlp The command helpers for printing via. 929 * @param hDbgAs The address space to look up addresses in. 930 * @param pAddress The current address. 931 * @param pcbCallAgain Where to return the distance to the next check (in 932 * instruction bytes). 933 */ 934 static void dbgcCmdUnassambleHelpListNear(PUVM pUVM, PDBGCCMDHLP pCmdHlp, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, 935 PRTUINTPTR pcbCallAgain) 936 { 937 RTDBGSYMBOL Symbol; 938 RTGCINTPTR offDispSym; 939 int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &offDispSym, &Symbol, NULL); 940 if (RT_FAILURE(rc) || offDispSym > _1G) 941 rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL, &offDispSym, &Symbol, NULL); 942 if (RT_SUCCESS(rc) && offDispSym < _1G) 943 { 944 if (!offDispSym) 945 { 946 DBGCCmdHlpPrintf(pCmdHlp, "%s:\n", Symbol.szName); 947 *pcbCallAgain = !Symbol.cb ? 64 : Symbol.cb; 948 } 949 else if (offDispSym > 0) 950 { 951 DBGCCmdHlpPrintf(pCmdHlp, "%s+%#llx:\n", Symbol.szName, (uint64_t)offDispSym); 952 *pcbCallAgain = !Symbol.cb ? 64 : Symbol.cb > (RTGCUINTPTR)offDispSym ? Symbol.cb - (RTGCUINTPTR)offDispSym : 1; 953 } 954 else 955 { 956 DBGCCmdHlpPrintf(pCmdHlp, "%s-%#llx:\n", Symbol.szName, (uint64_t)-offDispSym); 957 *pcbCallAgain = !Symbol.cb ? 64 : (RTGCUINTPTR)-offDispSym + Symbol.cb; 958 } 959 } 960 else 961 *pcbCallAgain = UINT32_MAX; 962 } 963 964 965 /** 966 * @callback_method_impl{FNDBGCCMD, The 'u' command.} 967 */ 968 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 969 { 970 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 971 972 /* 973 * Validate input. 974 */ 975 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 976 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, -1, cArgs <= 1); 977 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 0 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 978 979 if (!cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 980 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Don't know where to start disassembling"); 981 982 /* 983 * Check the desired mode. 984 */ 985 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS | DBGF_DISAS_FLAGS_UNPATCHED_BYTES | DBGF_DISAS_FLAGS_ANNOTATE_PATCHED; 986 switch (pCmd->pszCmd[1]) 987 { 988 default: AssertFailed(); 989 case '\0': fFlags |= DBGF_DISAS_FLAGS_DEFAULT_MODE; break; 990 case '6': fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break; 991 case '3': fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break; 992 case '1': fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE; break; 993 case 'v': fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE; break; 994 } 995 996 /** @todo should use DBGFADDRESS for everything */ 997 998 /* 999 * Find address. 1000 */ 1001 if (!cArgs) 1002 { 1003 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 1004 { 1005 /** @todo Batch query CS, RIP, CPU mode and flags. */ 1006 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 1007 if ( pDbgc->fRegCtxGuest 1008 && CPUMIsGuestIn64BitCode(pVCpu)) 1009 { 1010 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FLAT; 1011 pDbgc->SourcePos.u.GCFlat = CPUMGetGuestRIP(pVCpu); 1012 } 1013 else 1014 { 1015 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR; 1016 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu); 1017 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu); 1018 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE 1019 && pDbgc->fRegCtxGuest 1020 && (CPUMGetGuestEFlags(pVCpu) & X86_EFL_VM)) 1021 { 1022 fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK; 1023 fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE; 1024 } 1025 } 1026 1027 if (pDbgc->fRegCtxGuest) 1028 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST; 1029 else 1030 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER | DBGF_DISAS_FLAGS_HYPER; 1031 } 1032 else if ((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE && pDbgc->fDisasm) 1033 { 1034 fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK; 1035 fFlags |= pDbgc->fDisasm & (DBGF_DISAS_FLAGS_MODE_MASK | DBGF_DISAS_FLAGS_HYPER); 1036 } 1037 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE; 1038 } 1039 else 1040 pDbgc->DisasmPos = paArgs[0]; 1041 pDbgc->pLastPos = &pDbgc->DisasmPos; 1042 1043 /* 1044 * Range. 1045 */ 1046 switch (pDbgc->DisasmPos.enmRangeType) 1047 { 1048 case DBGCVAR_RANGE_NONE: 1049 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 1050 pDbgc->DisasmPos.u64Range = 10; 1051 break; 1052 1053 case DBGCVAR_RANGE_ELEMENTS: 1054 if (pDbgc->DisasmPos.u64Range > 2048) 1055 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Too many lines requested. Max is 2048 lines"); 1056 break; 1057 1058 case DBGCVAR_RANGE_BYTES: 1059 if (pDbgc->DisasmPos.u64Range > 65536) 1060 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The requested range is too big. Max is 64KB"); 1061 break; 1062 1063 default: 1064 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Unknown range type %d", pDbgc->DisasmPos.enmRangeType); 1065 } 1066 1067 /* 1068 * Convert physical and host addresses to guest addresses. 1069 */ 1070 RTDBGAS hDbgAs = pDbgc->hDbgAs; 1071 int rc; 1072 switch (pDbgc->DisasmPos.enmType) 1073 { 1074 case DBGCVAR_TYPE_GC_FLAT: 1075 case DBGCVAR_TYPE_GC_FAR: 1076 break; 1077 case DBGCVAR_TYPE_GC_PHYS: 1078 hDbgAs = DBGF_AS_PHYS; 1079 case DBGCVAR_TYPE_HC_FLAT: 1080 case DBGCVAR_TYPE_HC_PHYS: 1081 { 1082 DBGCVAR VarTmp; 1083 rc = DBGCCmdHlpEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos); 1084 if (RT_FAILURE(rc)) 1085 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "failed to evaluate '%%(%Dv)'", &pDbgc->DisasmPos); 1086 pDbgc->DisasmPos = VarTmp; 1087 break; 1088 } 1089 default: AssertFailed(); break; 1090 } 1091 1092 DBGFADDRESS CurAddr; 1093 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE 1094 && pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FAR) 1095 DBGFR3AddrFromFlat(pUVM, &CurAddr, ((uint32_t)pDbgc->DisasmPos.u.GCFar.sel << 4) + pDbgc->DisasmPos.u.GCFar.off); 1096 else 1097 { 1098 rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->DisasmPos, &CurAddr); 1099 if (RT_FAILURE(rc)) 1100 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr failed on '%Dv'", &pDbgc->DisasmPos); 1101 } 1102 1103 if (CurAddr.fFlags & DBGFADDRESS_FLAGS_HMA) 1104 fFlags |= DBGF_DISAS_FLAGS_HYPER; /* This crap is due to not using DBGFADDRESS as DBGFR3Disas* input. */ 1105 pDbgc->fDisasm = fFlags; 1106 1107 /* 1108 * Figure out where we are and display it. Also calculate when we need to 1109 * check for a new symbol if possible. 1110 */ 1111 RTGCUINTPTR cbCheckSymbol; 1112 dbgcCmdUnassambleHelpListNear(pUVM, pCmdHlp, hDbgAs, &CurAddr, &cbCheckSymbol); 1113 1114 /* 1115 * Do the disassembling. 1116 */ 1117 unsigned cTries = 32; 1118 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range; 1119 if (iRangeLeft == 0) /* kludge for 'r'. */ 1120 iRangeLeft = -1; 1121 for (;;) 1122 { 1123 /* 1124 * Disassemble the instruction. 1125 */ 1126 char szDis[256]; 1127 uint32_t cbInstr = 1; 1128 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT) 1129 rc = DBGFR3DisasInstrEx(pUVM, pDbgc->idCpu, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, 1130 &szDis[0], sizeof(szDis), &cbInstr); 1131 else 1132 rc = DBGFR3DisasInstrEx(pUVM, pDbgc->idCpu, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, 1133 &szDis[0], sizeof(szDis), &cbInstr); 1134 if (RT_SUCCESS(rc)) 1135 { 1136 /* print it */ 1137 rc = DBGCCmdHlpPrintf(pCmdHlp, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]); 1138 if (RT_FAILURE(rc)) 1139 return rc; 1140 } 1141 else 1142 { 1143 /* bitch. */ 1144 int rc2 = DBGCCmdHlpPrintf(pCmdHlp, "Failed to disassemble instruction, skipping one byte.\n"); 1145 if (RT_FAILURE(rc2)) 1146 return rc2; 1147 if (cTries-- > 0) 1148 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Too many disassembly failures. Giving up"); 1149 cbInstr = 1; 1150 } 1151 1152 /* advance */ 1153 if (iRangeLeft < 0) /* 'r' */ 1154 break; 1155 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS) 1156 iRangeLeft--; 1157 else 1158 iRangeLeft -= cbInstr; 1159 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr); 1160 if (RT_FAILURE(rc)) 1161 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpEval(,,'(%Dv) + %x')", &pDbgc->DisasmPos, cbInstr); 1162 if (iRangeLeft <= 0) 1163 break; 1164 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER); 1165 1166 /* Print next symbol? */ 1167 if (cbCheckSymbol <= cbInstr) 1168 { 1169 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE 1170 && pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FAR) 1171 DBGFR3AddrFromFlat(pUVM, &CurAddr, ((uint32_t)pDbgc->DisasmPos.u.GCFar.sel << 4) + pDbgc->DisasmPos.u.GCFar.off); 1172 else 1173 rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->DisasmPos, &CurAddr); 1174 if (RT_SUCCESS(rc)) 1175 dbgcCmdUnassambleHelpListNear(pUVM, pCmdHlp, hDbgAs, &CurAddr, &cbCheckSymbol); 1176 else 1177 cbCheckSymbol = UINT32_MAX; 1178 } 1179 else 1180 cbCheckSymbol -= cbInstr; 1181 } 1182 1183 NOREF(pCmd); 1184 return VINF_SUCCESS; 1185 } 1186 1187 1188 /** 1189 * @callback_method_impl{FNDBGCCMD, The 'ls' command.} 1190 */ 1191 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1192 { 1193 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1194 1195 /* 1196 * Validate input. 1197 */ 1198 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 1199 if (cArgs == 1) 1200 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 1201 if (!pUVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType)) 1202 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Don't know where to start listing..."); 1203 if (!pUVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType)) 1204 return DBGCCmdHlpFail(pCmdHlp, pCmd, "GC address but no VM"); 1205 1206 /* 1207 * Find address. 1208 */ 1209 if (!cArgs) 1210 { 1211 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType)) 1212 { 1213 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 1214 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR; 1215 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu); 1216 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu); 1217 } 1218 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE; 1219 } 1220 else 1221 pDbgc->SourcePos = paArgs[0]; 1222 pDbgc->pLastPos = &pDbgc->SourcePos; 1223 1224 /* 1225 * Ensure the source address is flat GC. 1226 */ 1227 switch (pDbgc->SourcePos.enmType) 1228 { 1229 case DBGCVAR_TYPE_GC_FLAT: 1230 break; 1231 case DBGCVAR_TYPE_GC_PHYS: 1232 case DBGCVAR_TYPE_GC_FAR: 1233 case DBGCVAR_TYPE_HC_FLAT: 1234 case DBGCVAR_TYPE_HC_PHYS: 1235 { 1236 int rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos); 1237 if (RT_FAILURE(rc)) 1238 return DBGCCmdHlpPrintf(pCmdHlp, "error: Invalid address or address type. (rc=%d)\n", rc); 1239 break; 1240 } 1241 default: AssertFailed(); break; 1242 } 1243 1244 /* 1245 * Range. 1246 */ 1247 switch (pDbgc->SourcePos.enmRangeType) 1248 { 1249 case DBGCVAR_RANGE_NONE: 1250 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 1251 pDbgc->SourcePos.u64Range = 10; 1252 break; 1253 1254 case DBGCVAR_RANGE_ELEMENTS: 1255 if (pDbgc->SourcePos.u64Range > 2048) 1256 return DBGCCmdHlpPrintf(pCmdHlp, "error: Too many lines requested. Max is 2048 lines.\n"); 1257 break; 1258 1259 case DBGCVAR_RANGE_BYTES: 1260 if (pDbgc->SourcePos.u64Range > 65536) 1261 return DBGCCmdHlpPrintf(pCmdHlp, "error: The requested range is too big. Max is 64KB.\n"); 1262 break; 1263 1264 default: 1265 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType); 1266 } 1267 1268 /* 1269 * Do the disassembling. 1270 */ 1271 bool fFirst = 1; 1272 RTDBGLINE LinePrev = { 0, 0, 0, 0, 0, "" }; 1273 int iRangeLeft = (int)pDbgc->SourcePos.u64Range; 1274 if (iRangeLeft == 0) /* kludge for 'r'. */ 1275 iRangeLeft = -1; 1276 for (;;) 1277 { 1278 /* 1279 * Get line info. 1280 */ 1281 RTDBGLINE Line; 1282 RTGCINTPTR off; 1283 DBGFADDRESS SourcePosAddr; 1284 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->SourcePos, &SourcePosAddr); 1285 if (RT_FAILURE(rc)) 1286 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,%Dv)", &pDbgc->SourcePos); 1287 rc = DBGFR3AsLineByAddr(pUVM, pDbgc->hDbgAs, &SourcePosAddr, &off, &Line, NULL); 1288 if (RT_FAILURE(rc)) 1289 return VINF_SUCCESS; 1290 1291 unsigned cLines = 0; 1292 if (memcmp(&Line, &LinePrev, sizeof(Line))) 1293 { 1294 /* 1295 * Print filenamename 1296 */ 1297 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename)) 1298 fFirst = true; 1299 if (fFirst) 1300 { 1301 rc = DBGCCmdHlpPrintf(pCmdHlp, "[%s @ %d]\n", Line.szFilename, Line.uLineNo); 1302 if (RT_FAILURE(rc)) 1303 return rc; 1304 } 1305 1306 /* 1307 * Try open the file and read the line. 1308 */ 1309 FILE *phFile = fopen(Line.szFilename, "r"); 1310 if (phFile) 1311 { 1312 /* Skip ahead to the desired line. */ 1313 char szLine[4096]; 1314 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1; 1315 if (cBefore > 7) 1316 cBefore = 0; 1317 unsigned cLeft = Line.uLineNo - cBefore; 1318 while (cLeft > 0) 1319 { 1320 szLine[0] = '\0'; 1321 if (!fgets(szLine, sizeof(szLine), phFile)) 1322 break; 1323 cLeft--; 1324 } 1325 if (!cLeft) 1326 { 1327 /* print the before lines */ 1328 for (;;) 1329 { 1330 size_t cch = strlen(szLine); 1331 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || RT_C_IS_SPACE(szLine[cch - 1])) ) 1332 szLine[--cch] = '\0'; 1333 if (cBefore-- <= 0) 1334 break; 1335 1336 rc = DBGCCmdHlpPrintf(pCmdHlp, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine); 1337 szLine[0] = '\0'; 1338 (void)fgets(szLine, sizeof(szLine), phFile); 1339 cLines++; 1340 } 1341 /* print the actual line */ 1342 rc = DBGCCmdHlpPrintf(pCmdHlp, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine); 1343 } 1344 fclose(phFile); 1345 if (RT_FAILURE(rc)) 1346 return rc; 1347 fFirst = false; 1348 } 1349 else 1350 return DBGCCmdHlpPrintf(pCmdHlp, "Warning: couldn't open source file '%s'\n", Line.szFilename); 1351 1352 LinePrev = Line; 1353 } 1354 1355 1356 /* 1357 * Advance 1358 */ 1359 if (iRangeLeft < 0) /* 'r' */ 1360 break; 1361 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS) 1362 iRangeLeft -= cLines; 1363 else 1364 iRangeLeft -= 1; 1365 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1); 1366 if (RT_FAILURE(rc)) 1367 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1); 1368 if (iRangeLeft <= 0) 1369 break; 1370 } 1371 1372 NOREF(pCmd); 1373 return 0; 1374 } 1375 1376 1377 /** 1378 * @callback_method_impl{FNDBGCCMD, The 'r' command.} 1379 */ 1380 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1381 { 1382 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1383 if (!pDbgc->fRegCtxGuest) 1384 return dbgcCmdRegHyper(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 1385 return dbgcCmdRegGuest(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 1386 } 1387 1388 1389 /** 1390 * @callback_method_impl{FNDBGCCMD, Common worker for the dbgcCmdReg*() 1391 * commands.} 1392 */ 1393 static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs, 1394 const char *pszPrefix) 1395 { 1396 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1397 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1 || cArgs == 2 || cArgs == 3); 1398 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_STRING 1399 || paArgs[0].enmType == DBGCVAR_TYPE_SYMBOL); 1400 1401 /* 1402 * Parse the register name and kind. 1403 */ 1404 const char *pszReg = paArgs[0].u.pszString; 1405 if (*pszReg == '@') 1406 pszReg++; 1407 VMCPUID idCpu = pDbgc->idCpu; 1408 if (*pszPrefix) 1409 idCpu |= DBGFREG_HYPER_VMCPUID; 1410 if (*pszReg == '.') 1411 { 1412 pszReg++; 1413 idCpu |= DBGFREG_HYPER_VMCPUID; 1414 } 1415 const char * const pszActualPrefix = idCpu & DBGFREG_HYPER_VMCPUID ? "." : ""; 1416 1417 /* 1418 * Query the register type & value (the setter needs the type). 1419 */ 1420 DBGFREGVALTYPE enmType; 1421 DBGFREGVAL Value; 1422 int rc = DBGFR3RegNmQuery(pUVM, idCpu, pszReg, &Value, &enmType); 1423 if (RT_FAILURE(rc)) 1424 { 1425 if (rc == VERR_DBGF_REGISTER_NOT_FOUND) 1426 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown register: '%s%s'.\n", 1427 pszActualPrefix, pszReg); 1428 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegNmQuery failed querying '%s%s': %Rrc.\n", 1429 pszActualPrefix, pszReg, rc); 1430 } 1431 if (cArgs == 1) 1432 { 1433 /* 1434 * Show the register. 1435 */ 1436 char szValue[160]; 1437 rc = DBGFR3RegFormatValue(szValue, sizeof(szValue), &Value, enmType, true /*fSpecial*/); 1438 if (RT_SUCCESS(rc)) 1439 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s%s=%s\n", pszActualPrefix, pszReg, szValue); 1440 else 1441 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegFormatValue failed: %Rrc.\n", rc); 1442 } 1443 else 1444 { 1445 DBGCVAR NewValueTmp; 1446 PCDBGCVAR pNewValue; 1447 if (cArgs == 3) 1448 { 1449 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 1, paArgs[1].enmType == DBGCVAR_TYPE_STRING); 1450 if (strcmp(paArgs[1].u.pszString, "=")) 1451 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Second argument must be '='."); 1452 pNewValue = &paArgs[2]; 1453 } 1454 else 1455 { 1456 /* Not possible to convince the parser to support both codeview and 1457 windbg syntax and make the equal sign optional. Try help it. */ 1458 /** @todo make DBGCCmdHlpConvert do more with strings. */ 1459 rc = DBGCCmdHlpConvert(pCmdHlp, &paArgs[1], DBGCVAR_TYPE_NUMBER, true /*fConvSyms*/, &NewValueTmp); 1460 if (RT_FAILURE(rc)) 1461 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "The last argument must be a value or valid symbol."); 1462 pNewValue = &NewValueTmp; 1463 } 1464 1465 /* 1466 * Modify the register. 1467 */ 1468 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 1, pNewValue->enmType == DBGCVAR_TYPE_NUMBER); 1469 if (enmType != DBGFREGVALTYPE_DTR) 1470 { 1471 enmType = DBGFREGVALTYPE_U64; 1472 rc = DBGCCmdHlpVarToNumber(pCmdHlp, pNewValue, &Value.u64); 1473 } 1474 else 1475 { 1476 enmType = DBGFREGVALTYPE_DTR; 1477 rc = DBGCCmdHlpVarToNumber(pCmdHlp, pNewValue, &Value.dtr.u64Base); 1478 if (RT_SUCCESS(rc) && pNewValue->enmRangeType != DBGCVAR_RANGE_NONE) 1479 Value.dtr.u32Limit = (uint32_t)pNewValue->u64Range; 1480 } 1481 if (RT_SUCCESS(rc)) 1482 { 1483 rc = DBGFR3RegNmSet(pUVM, idCpu, pszReg, &Value, enmType); 1484 if (RT_FAILURE(rc)) 1485 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegNmSet failed settings '%s%s': %Rrc\n", 1486 pszActualPrefix, pszReg, rc); 1487 if (rc != VINF_SUCCESS) 1488 DBGCCmdHlpPrintf(pCmdHlp, "%s: warning: %Rrc\n", pCmd->pszCmd, rc); 1489 } 1490 else 1491 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegFormatValue failed: %Rrc.\n", rc); 1492 } 1493 return rc; 1494 } 1495 1496 1497 /** 1498 * @callback_method_impl{FNDBGCCMD, 1499 * The 'rg'\, 'rg64' and 'rg32' commands\, worker for 'r'.} 1500 */ 1501 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1502 { 1503 /* 1504 * Show all registers our selves. 1505 */ 1506 if (cArgs == 0) 1507 { 1508 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1509 bool const f64BitMode = !strcmp(pCmd->pszCmd, "rg64") 1510 || ( strcmp(pCmd->pszCmd, "rg32") != 0 1511 && DBGFR3CpuIsIn64BitCode(pUVM, pDbgc->idCpu)); 1512 char szDisAndRegs[8192]; 1513 int rc; 1514 1515 if (pDbgc->fRegTerse) 1516 { 1517 if (f64BitMode) 1518 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs), 1519 "u %016VR{rip} L 0\n" 1520 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n" 1521 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n" 1522 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n" 1523 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n" 1524 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n" 1525 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss} rflags=%08VR{rflags}\n"); 1526 else 1527 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs), 1528 "u %04VR{cs}:%08VR{eip} L 0\n" 1529 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n" 1530 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n" 1531 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss} eflags=%08VR{eflags}\n"); 1532 } 1533 else 1534 { 1535 if (f64BitMode) 1536 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs), 1537 "u %016VR{rip} L 0\n" 1538 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n" 1539 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n" 1540 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n" 1541 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n" 1542 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n" 1543 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n" 1544 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n" 1545 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n" 1546 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n" 1547 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n" 1548 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n" 1549 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n" 1550 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n" 1551 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n" 1552 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n" 1553 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n" 1554 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n" 1555 " efer=%016VR{efer}\n" 1556 " pat=%016VR{pat}\n" 1557 " sf_mask=%016VR{sf_mask}\n" 1558 "krnl_gs_base=%016VR{krnl_gs_base}\n" 1559 " lstar=%016VR{lstar}\n" 1560 " star=%016VR{star} cstar=%016VR{cstar}\n" 1561 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n" 1562 ); 1563 else 1564 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs), 1565 "u %04VR{cs}:%08VR{eip} L 0\n" 1566 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n" 1567 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n" 1568 "cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} dr0=%08VR{dr0} dr1=%08VR{dr1}\n" 1569 "ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} dr2=%08VR{dr2} dr3=%08VR{dr3}\n" 1570 "es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} dr6=%08VR{dr6} dr7=%08VR{dr7}\n" 1571 "fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr0=%08VR{cr0} cr2=%08VR{cr2}\n" 1572 "gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr3=%08VR{cr3} cr4=%08VR{cr4}\n" 1573 "ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}} cr8=%08VR{cr8}\n" 1574 "gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim} idtr=%08VR{idtr_base}:%04VR{idtr_lim} eflags=%08VR{eflags}\n" 1575 "ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n" 1576 "tr ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n" 1577 "sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n" 1578 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n" 1579 ); 1580 } 1581 if (RT_FAILURE(rc)) 1582 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed"); 1583 char *pszRegs = strchr(szDisAndRegs, '\n'); 1584 *pszRegs++ = '\0'; 1585 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs); 1586 1587 /* 1588 * Disassemble one instruction at cs:[r|e]ip. 1589 */ 1590 if (!f64BitMode && strstr(pszRegs, " vm ")) /* a big ugly... */ 1591 return pCmdHlp->pfnExec(pCmdHlp, "uv86 %s", szDisAndRegs + 2); 1592 return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs); 1593 } 1594 return dbgcCmdRegCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, ""); 1595 } 1596 1597 1598 /** 1599 * @callback_method_impl{FNDBGCCMD, The 'rh' command.} 1600 */ 1601 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1602 { 1603 /* 1604 * Show all registers our selves. 1605 */ 1606 if (cArgs == 0) 1607 { 1608 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1609 char szDisAndRegs[8192]; 1610 int rc; 1611 1612 if (pDbgc->fRegTerse) 1613 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu | DBGFREG_HYPER_VMCPUID, szDisAndRegs, sizeof(szDisAndRegs), 1614 "u %VR{cs}:%VR{eip} L 0\n" 1615 ".eax=%08VR{eax} .ebx=%08VR{ebx} .ecx=%08VR{ecx} .edx=%08VR{edx} .esi=%08VR{esi} .edi=%08VR{edi}\n" 1616 ".eip=%08VR{eip} .esp=%08VR{esp} .ebp=%08VR{ebp} .%VRF{eflags}\n" 1617 ".cs=%04VR{cs} .ds=%04VR{ds} .es=%04VR{es} .fs=%04VR{fs} .gs=%04VR{gs} .ss=%04VR{ss} .eflags=%08VR{eflags}\n"); 1618 else 1619 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu | DBGFREG_HYPER_VMCPUID, szDisAndRegs, sizeof(szDisAndRegs), 1620 "u %04VR{cs}:%08VR{eip} L 0\n" 1621 ".eax=%08VR{eax} .ebx=%08VR{ebx} .ecx=%08VR{ecx} .edx=%08VR{edx} .esi=%08VR{esi} .edi=%08VR{edi}\n" 1622 ".eip=%08VR{eip} .esp=%08VR{esp} .ebp=%08VR{ebp} .%VRF{eflags}\n" 1623 ".cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} .dr0=%08VR{dr0} .dr1=%08VR{dr1}\n" 1624 ".ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} .dr2=%08VR{dr2} .dr3=%08VR{dr3}\n" 1625 ".es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} .dr6=%08VR{dr6} .dr6=%08VR{dr6}\n" 1626 ".fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} .cr3=%016VR{cr3}\n" 1627 ".gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}}\n" 1628 ".ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n" 1629 ".gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim} .idtr=%08VR{idtr_base}:%04VR{idtr_lim} .eflags=%08VR{eflags}\n" 1630 ".ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n" 1631 ".tr ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n" 1632 ); 1633 if (RT_FAILURE(rc)) 1634 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed"); 1635 char *pszRegs = strchr(szDisAndRegs, '\n'); 1636 *pszRegs++ = '\0'; 1637 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs); 1638 1639 /* 1640 * Disassemble one instruction at cs:[r|e]ip. 1641 */ 1642 return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs); 1643 } 1644 return dbgcCmdRegCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, "."); 1645 } 1646 1647 1648 /** 1649 * @callback_method_impl{FNDBGCCMD, The 'rt' command.} 1650 */ 1651 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1652 { 1653 NOREF(pCmd); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs); 1654 1655 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1656 pDbgc->fRegTerse = !pDbgc->fRegTerse; 1657 return DBGCCmdHlpPrintf(pCmdHlp, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n"); 1658 } 1659 1660 1661 /** 1662 * @callback_method_impl{FNDBGCCMD, The 't' command.} 1663 */ 1664 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1665 { 1666 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1667 1668 int rc = DBGFR3Step(pUVM, pDbgc->idCpu); 1669 if (RT_SUCCESS(rc)) 1670 pDbgc->fReady = false; 1671 else 1672 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM); 1673 1674 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); 1675 return rc; 1676 } 1677 1678 1679 /** 1680 * @callback_method_impl{FNDBGCCMD, The 'k'\, 'kg' and 'kh' commands.} 1681 */ 1682 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1683 { 1684 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1685 1686 /* 1687 * Figure which context we're called for and start walking that stack. 1688 */ 1689 int rc; 1690 PCDBGFSTACKFRAME pFirstFrame; 1691 bool const fGuest = pCmd->pszCmd[1] == 'g' 1692 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest); 1693 rc = DBGFR3StackWalkBegin(pUVM, pDbgc->idCpu, fGuest ? DBGFCODETYPE_GUEST : DBGFCODETYPE_HYPER, &pFirstFrame); 1694 if (RT_FAILURE(rc)) 1695 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to begin stack walk, rc=%Rrc\n", rc); 1696 1697 /* 1698 * Print header. 1699 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol 1700 */ 1701 uint32_t fBitFlags = 0; 1702 for (PCDBGFSTACKFRAME pFrame = pFirstFrame; 1703 pFrame; 1704 pFrame = DBGFR3StackWalkNext(pFrame)) 1705 { 1706 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT); 1707 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT) 1708 { 1709 if (fCurBitFlags != fBitFlags) 1710 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n"); 1711 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32", 1712 pFrame->AddrFrame.Sel, 1713 (uint16_t)pFrame->AddrFrame.off, 1714 pFrame->AddrReturnFrame.Sel, 1715 (uint16_t)pFrame->AddrReturnFrame.off, 1716 (uint32_t)pFrame->AddrReturnPC.Sel, 1717 (uint32_t)pFrame->AddrReturnPC.off, 1718 pFrame->Args.au32[0], 1719 pFrame->Args.au32[1], 1720 pFrame->Args.au32[2], 1721 pFrame->Args.au32[3]); 1722 } 1723 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT) 1724 { 1725 if (fCurBitFlags != fBitFlags) 1726 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n"); 1727 rc = DBGCCmdHlpPrintf(pCmdHlp, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32", 1728 (uint32_t)pFrame->AddrFrame.off, 1729 (uint32_t)pFrame->AddrReturnFrame.off, 1730 (uint32_t)pFrame->AddrReturnPC.Sel, 1731 (uint32_t)pFrame->AddrReturnPC.off, 1732 pFrame->Args.au32[0], 1733 pFrame->Args.au32[1], 1734 pFrame->Args.au32[2], 1735 pFrame->Args.au32[3]); 1736 } 1737 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT) 1738 { 1739 if (fCurBitFlags != fBitFlags) 1740 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n"); 1741 rc = DBGCCmdHlpPrintf(pCmdHlp, "%016RX64 %04RX16:%016RX64 %016RX64", 1742 (uint64_t)pFrame->AddrFrame.off, 1743 pFrame->AddrReturnFrame.Sel, 1744 (uint64_t)pFrame->AddrReturnFrame.off, 1745 (uint64_t)pFrame->AddrReturnPC.off); 1746 } 1747 if (RT_FAILURE(rc)) 1748 break; 1749 if (!pFrame->pSymPC) 1750 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1751 fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT 1752 ? " %RTsel:%016RGv" 1753 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT 1754 ? " %RTsel:%08RGv" 1755 : " %RTsel:%04RGv" 1756 , pFrame->AddrPC.Sel, pFrame->AddrPC.off); 1757 else 1758 { 1759 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */ 1760 if (offDisp > 0) 1761 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp); 1762 else if (offDisp < 0) 1763 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp); 1764 else 1765 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s", pFrame->pSymPC->szName); 1766 } 1767 if (RT_SUCCESS(rc) && pFrame->pLinePC) 1768 rc = DBGCCmdHlpPrintf(pCmdHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo); 1769 if (RT_SUCCESS(rc)) 1770 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 1771 if (RT_FAILURE(rc)) 1772 break; 1773 1774 fBitFlags = fCurBitFlags; 1775 } 1776 1777 DBGFR3StackWalkEnd(pFirstFrame); 1778 1779 NOREF(paArgs); NOREF(cArgs); 1780 return rc; 1781 } 1782 1783 1784 static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP pCmdHlp, PCX86DESC64 pDesc, unsigned iEntry, bool fHyper, bool *pfDblEntry) 1785 { 1786 /* GUEST64 */ 1787 int rc; 1788 1789 const char *pszHyper = fHyper ? " HYPER" : ""; 1790 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP"; 1791 if (pDesc->Gen.u1DescType) 1792 { 1793 static const char * const s_apszTypes[] = 1794 { 1795 "DataRO", /* 0 Read-Only */ 1796 "DataRO", /* 1 Read-Only - Accessed */ 1797 "DataRW", /* 2 Read/Write */ 1798 "DataRW", /* 3 Read/Write - Accessed */ 1799 "DownRO", /* 4 Expand-down, Read-Only */ 1800 "DownRO", /* 5 Expand-down, Read-Only - Accessed */ 1801 "DownRW", /* 6 Expand-down, Read/Write */ 1802 "DownRW", /* 7 Expand-down, Read/Write - Accessed */ 1803 "CodeEO", /* 8 Execute-Only */ 1804 "CodeEO", /* 9 Execute-Only - Accessed */ 1805 "CodeER", /* A Execute/Readable */ 1806 "CodeER", /* B Execute/Readable - Accessed */ 1807 "ConfE0", /* C Conforming, Execute-Only */ 1808 "ConfE0", /* D Conforming, Execute-Only - Accessed */ 1809 "ConfER", /* E Conforming, Execute/Readable */ 1810 "ConfER" /* F Conforming, Execute/Readable - Accessed */ 1811 }; 1812 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA"; 1813 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 1814 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 1815 uint32_t u32Base = X86DESC_BASE(pDesc); 1816 uint32_t cbLimit = X86DESC_LIMIT_G(pDesc); 1817 1818 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n", 1819 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 1820 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig, 1821 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper); 1822 } 1823 else 1824 { 1825 static const char * const s_apszTypes[] = 1826 { 1827 "Ill-0 ", /* 0 0000 Reserved (Illegal) */ 1828 "Ill-1 ", /* 1 0001 Available 16-bit TSS */ 1829 "LDT ", /* 2 0010 LDT */ 1830 "Ill-3 ", /* 3 0011 Busy 16-bit TSS */ 1831 "Ill-4 ", /* 4 0100 16-bit Call Gate */ 1832 "Ill-5 ", /* 5 0101 Task Gate */ 1833 "Ill-6 ", /* 6 0110 16-bit Interrupt Gate */ 1834 "Ill-7 ", /* 7 0111 16-bit Trap Gate */ 1835 "Ill-8 ", /* 8 1000 Reserved (Illegal) */ 1836 "Tss64A", /* 9 1001 Available 32-bit TSS */ 1837 "Ill-A ", /* A 1010 Reserved (Illegal) */ 1838 "Tss64B", /* B 1011 Busy 32-bit TSS */ 1839 "Call64", /* C 1100 32-bit Call Gate */ 1840 "Ill-D ", /* D 1101 Reserved (Illegal) */ 1841 "Int64 ", /* E 1110 32-bit Interrupt Gate */ 1842 "Trap64" /* F 1111 32-bit Trap Gate */ 1843 }; 1844 switch (pDesc->Gen.u4Type) 1845 { 1846 /* raw */ 1847 case X86_SEL_TYPE_SYS_UNDEFINED: 1848 case X86_SEL_TYPE_SYS_UNDEFINED2: 1849 case X86_SEL_TYPE_SYS_UNDEFINED4: 1850 case X86_SEL_TYPE_SYS_UNDEFINED3: 1851 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 1852 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 1853 case X86_SEL_TYPE_SYS_286_CALL_GATE: 1854 case X86_SEL_TYPE_SYS_286_INT_GATE: 1855 case X86_SEL_TYPE_SYS_286_TRAP_GATE: 1856 case X86_SEL_TYPE_SYS_TASK_GATE: 1857 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s %.8Rhxs DPL=%d %s%s\n", 1858 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc, 1859 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 1860 break; 1861 1862 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 1863 case X86_SEL_TYPE_SYS_386_TSS_BUSY: 1864 case X86_SEL_TYPE_SYS_LDT: 1865 { 1866 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB"; 1867 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 1868 const char *pszLong = pDesc->Gen.u1Long ? "LONG" : " "; 1869 1870 uint64_t u64Base = X86DESC64_BASE(pDesc); 1871 uint32_t cbLimit = X86DESC_LIMIT_G(pDesc); 1872 1873 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%016RX64 Lim=%08x DPL=%d %s %s %s %sAVL=%d R=%d%s\n", 1874 iEntry, s_apszTypes[pDesc->Gen.u4Type], u64Base, cbLimit, 1875 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszLong, pszBig, 1876 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1), 1877 pszHyper); 1878 if (pfDblEntry) 1879 *pfDblEntry = true; 1880 break; 1881 } 1882 1883 case X86_SEL_TYPE_SYS_386_CALL_GATE: 1884 { 1885 unsigned cParams = pDesc->au8[4] & 0x1f; 1886 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC"; 1887 RTSEL sel = pDesc->au16[1]; 1888 uint64_t off = pDesc->au16[0] 1889 | ((uint64_t)pDesc->au16[3] << 16) 1890 | ((uint64_t)pDesc->Gen.u32BaseHigh3 << 32); 1891 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%016RX64 DPL=%d %s %s=%d%s\n", 1892 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 1893 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper); 1894 if (pfDblEntry) 1895 *pfDblEntry = true; 1896 break; 1897 } 1898 1899 case X86_SEL_TYPE_SYS_386_INT_GATE: 1900 case X86_SEL_TYPE_SYS_386_TRAP_GATE: 1901 { 1902 RTSEL sel = pDesc->Gate.u16Sel; 1903 uint64_t off = pDesc->Gate.u16OffsetLow 1904 | ((uint64_t)pDesc->Gate.u16OffsetHigh << 16) 1905 | ((uint64_t)pDesc->Gate.u32OffsetTop << 32); 1906 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%016RX64 DPL=%u %s IST=%u%s\n", 1907 iEntry, s_apszTypes[pDesc->Gate.u4Type], sel, off, 1908 pDesc->Gate.u2Dpl, pszPresent, pDesc->Gate.u3IST, pszHyper); 1909 if (pfDblEntry) 1910 *pfDblEntry = true; 1911 break; 1912 } 1913 1914 /* impossible, just it's necessary to keep gcc happy. */ 1915 default: 1916 return VINF_SUCCESS; 1917 } 1918 } 1919 return VINF_SUCCESS; 1920 } 1921 1922 1923 /** 1924 * Worker function that displays one descriptor entry (GDT, LDT, IDT). 1925 * 1926 * @returns pfnPrintf status code. 1927 * @param pCmdHlp The DBGC command helpers. 1928 * @param pDesc The descriptor to display. 1929 * @param iEntry The descriptor entry number. 1930 * @param fHyper Whether the selector belongs to the hypervisor or not. 1931 */ 1932 static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper) 1933 { 1934 int rc; 1935 1936 const char *pszHyper = fHyper ? " HYPER" : ""; 1937 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP"; 1938 if (pDesc->Gen.u1DescType) 1939 { 1940 static const char * const s_apszTypes[] = 1941 { 1942 "DataRO", /* 0 Read-Only */ 1943 "DataRO", /* 1 Read-Only - Accessed */ 1944 "DataRW", /* 2 Read/Write */ 1945 "DataRW", /* 3 Read/Write - Accessed */ 1946 "DownRO", /* 4 Expand-down, Read-Only */ 1947 "DownRO", /* 5 Expand-down, Read-Only - Accessed */ 1948 "DownRW", /* 6 Expand-down, Read/Write */ 1949 "DownRW", /* 7 Expand-down, Read/Write - Accessed */ 1950 "CodeEO", /* 8 Execute-Only */ 1951 "CodeEO", /* 9 Execute-Only - Accessed */ 1952 "CodeER", /* A Execute/Readable */ 1953 "CodeER", /* B Execute/Readable - Accessed */ 1954 "ConfE0", /* C Conforming, Execute-Only */ 1955 "ConfE0", /* D Conforming, Execute-Only - Accessed */ 1956 "ConfER", /* E Conforming, Execute/Readable */ 1957 "ConfER" /* F Conforming, Execute/Readable - Accessed */ 1958 }; 1959 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA"; 1960 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 1961 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 1962 uint32_t u32Base = pDesc->Gen.u16BaseLow 1963 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16) 1964 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24); 1965 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16); 1966 if (pDesc->Gen.u1Granularity) 1967 cbLimit <<= PAGE_SHIFT; 1968 1969 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n", 1970 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 1971 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig, 1972 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper); 1973 } 1974 else 1975 { 1976 static const char * const s_apszTypes[] = 1977 { 1978 "Ill-0 ", /* 0 0000 Reserved (Illegal) */ 1979 "Tss16A", /* 1 0001 Available 16-bit TSS */ 1980 "LDT ", /* 2 0010 LDT */ 1981 "Tss16B", /* 3 0011 Busy 16-bit TSS */ 1982 "Call16", /* 4 0100 16-bit Call Gate */ 1983 "TaskG ", /* 5 0101 Task Gate */ 1984 "Int16 ", /* 6 0110 16-bit Interrupt Gate */ 1985 "Trap16", /* 7 0111 16-bit Trap Gate */ 1986 "Ill-8 ", /* 8 1000 Reserved (Illegal) */ 1987 "Tss32A", /* 9 1001 Available 32-bit TSS */ 1988 "Ill-A ", /* A 1010 Reserved (Illegal) */ 1989 "Tss32B", /* B 1011 Busy 32-bit TSS */ 1990 "Call32", /* C 1100 32-bit Call Gate */ 1991 "Ill-D ", /* D 1101 Reserved (Illegal) */ 1992 "Int32 ", /* E 1110 32-bit Interrupt Gate */ 1993 "Trap32" /* F 1111 32-bit Trap Gate */ 1994 }; 1995 switch (pDesc->Gen.u4Type) 1996 { 1997 /* raw */ 1998 case X86_SEL_TYPE_SYS_UNDEFINED: 1999 case X86_SEL_TYPE_SYS_UNDEFINED2: 2000 case X86_SEL_TYPE_SYS_UNDEFINED4: 2001 case X86_SEL_TYPE_SYS_UNDEFINED3: 2002 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s %.8Rhxs DPL=%d %s%s\n", 2003 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc, 2004 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2005 break; 2006 2007 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 2008 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 2009 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 2010 case X86_SEL_TYPE_SYS_386_TSS_BUSY: 2011 case X86_SEL_TYPE_SYS_LDT: 2012 { 2013 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 2014 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB"; 2015 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 2016 uint32_t u32Base = pDesc->Gen.u16BaseLow 2017 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16) 2018 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24); 2019 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16); 2020 if (pDesc->Gen.u1Granularity) 2021 cbLimit <<= PAGE_SHIFT; 2022 2023 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n", 2024 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 2025 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig, 2026 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1), 2027 pszHyper); 2028 break; 2029 } 2030 2031 case X86_SEL_TYPE_SYS_TASK_GATE: 2032 { 2033 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s TSS=%04x DPL=%d %s%s\n", 2034 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1], 2035 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2036 break; 2037 } 2038 2039 case X86_SEL_TYPE_SYS_286_CALL_GATE: 2040 case X86_SEL_TYPE_SYS_386_CALL_GATE: 2041 { 2042 unsigned cParams = pDesc->au8[4] & 0x1f; 2043 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC"; 2044 RTSEL sel = pDesc->au16[1]; 2045 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16); 2046 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n", 2047 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 2048 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper); 2049 break; 2050 } 2051 2052 case X86_SEL_TYPE_SYS_286_INT_GATE: 2053 case X86_SEL_TYPE_SYS_386_INT_GATE: 2054 case X86_SEL_TYPE_SYS_286_TRAP_GATE: 2055 case X86_SEL_TYPE_SYS_386_TRAP_GATE: 2056 { 2057 RTSEL sel = pDesc->au16[1]; 2058 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16); 2059 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n", 2060 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 2061 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2062 break; 2063 } 2064 2065 /* impossible, just it's necessary to keep gcc happy. */ 2066 default: 2067 return VINF_SUCCESS; 2068 } 2069 } 2070 return rc; 2071 } 2072 2073 2074 /** 2075 * @callback_method_impl{FNDBGCCMD, The 'dg'\, 'dga'\, 'dl' and 'dla' commands.} 2076 */ 2077 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2078 { 2079 /* 2080 * Validate input. 2081 */ 2082 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2083 2084 /* 2085 * Get the CPU mode, check which command variation this is 2086 * and fix a default parameter if needed. 2087 */ 2088 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2089 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 2090 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu); 2091 bool fGdt = pCmd->pszCmd[1] == 'g'; 2092 bool fAll = pCmd->pszCmd[2] == 'a'; 2093 RTSEL SelTable = fGdt ? 0 : X86_SEL_LDT; 2094 2095 DBGCVAR Var; 2096 if (!cArgs) 2097 { 2098 cArgs = 1; 2099 paArgs = &Var; 2100 Var.enmType = DBGCVAR_TYPE_NUMBER; 2101 Var.u.u64Number = 0; 2102 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 2103 Var.u64Range = 1024; 2104 } 2105 2106 /* 2107 * Process the arguments. 2108 */ 2109 for (unsigned i = 0; i < cArgs; i++) 2110 { 2111 /* 2112 * Retrieve the selector value from the argument. 2113 * The parser may confuse pointers and numbers if more than one 2114 * argument is given, that that into account. 2115 */ 2116 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, i, paArgs[i].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[i].enmType)); 2117 uint64_t u64; 2118 unsigned cSels = 1; 2119 switch (paArgs[i].enmType) 2120 { 2121 case DBGCVAR_TYPE_NUMBER: 2122 u64 = paArgs[i].u.u64Number; 2123 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE) 2124 cSels = RT_MIN(paArgs[i].u64Range, 1024); 2125 break; 2126 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break; 2127 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break; 2128 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break; 2129 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break; 2130 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break; 2131 default: u64 = _64K; break; 2132 } 2133 if (u64 < _64K) 2134 { 2135 unsigned Sel = (RTSEL)u64; 2136 2137 /* 2138 * Dump the specified range. 2139 */ 2140 bool fSingle = cSels == 1; 2141 while ( cSels-- > 0 2142 && Sel < _64K) 2143 { 2144 DBGFSELINFO SelInfo; 2145 int rc = DBGFR3SelQueryInfo(pUVM, pDbgc->idCpu, Sel | SelTable, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo); 2146 if (RT_SUCCESS(rc)) 2147 { 2148 if (SelInfo.fFlags & DBGFSELINFO_FLAGS_REAL_MODE) 2149 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x RealM Bas=%04x Lim=%04x\n", 2150 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit); 2151 else if ( fAll 2152 || fSingle 2153 || SelInfo.u.Raw.Gen.u1Present) 2154 { 2155 if (enmMode == CPUMMODE_PROTECTED) 2156 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &SelInfo.u.Raw, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER)); 2157 else 2158 { 2159 bool fDblSkip = false; 2160 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &SelInfo.u.Raw64, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER), &fDblSkip); 2161 if (fDblSkip) 2162 Sel += 4; 2163 } 2164 } 2165 } 2166 else 2167 { 2168 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %Rrc\n", Sel, rc); 2169 if (!fAll) 2170 return rc; 2171 } 2172 if (RT_FAILURE(rc)) 2173 return rc; 2174 2175 /* next */ 2176 Sel += 8; 2177 } 2178 } 2179 else 2180 DBGCCmdHlpPrintf(pCmdHlp, "error: %llx is out of bounds\n", u64); 2181 } 2182 2183 return VINF_SUCCESS; 2184 } 2185 2186 2187 /** 2188 * @callback_method_impl{FNDBGCCMD, The 'di' and 'dia' commands.} 2189 */ 2190 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2191 { 2192 /* 2193 * Validate input. 2194 */ 2195 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2196 2197 /* 2198 * Establish some stuff like the current IDTR and CPU mode, 2199 * and fix a default parameter. 2200 */ 2201 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2202 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 2203 uint16_t cbLimit; 2204 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVCpu, &cbLimit); 2205 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu); 2206 unsigned cbEntry; 2207 switch (enmMode) 2208 { 2209 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break; 2210 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break; 2211 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break; 2212 default: 2213 return DBGCCmdHlpPrintf(pCmdHlp, "error: Invalid CPU mode %d.\n", enmMode); 2214 } 2215 2216 bool fAll = pCmd->pszCmd[2] == 'a'; 2217 DBGCVAR Var; 2218 if (!cArgs) 2219 { 2220 cArgs = 1; 2221 paArgs = &Var; 2222 Var.enmType = DBGCVAR_TYPE_NUMBER; 2223 Var.u.u64Number = 0; 2224 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 2225 Var.u64Range = 256; 2226 } 2227 2228 /* 2229 * Process the arguments. 2230 */ 2231 for (unsigned i = 0; i < cArgs; i++) 2232 { 2233 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, i, paArgs[i].enmType == DBGCVAR_TYPE_NUMBER); 2234 if (paArgs[i].u.u64Number < 256) 2235 { 2236 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number; 2237 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE 2238 ? paArgs[i].u64Range 2239 : 1; 2240 bool fSingle = cInts == 1; 2241 while ( cInts-- > 0 2242 && iInt < 256) 2243 { 2244 /* 2245 * Try read it. 2246 */ 2247 union 2248 { 2249 RTFAR16 Real; 2250 X86DESC Prot; 2251 X86DESC64 Long; 2252 } u; 2253 if (iInt * cbEntry + (cbEntry - 1) > cbLimit) 2254 { 2255 DBGCCmdHlpPrintf(pCmdHlp, "%04x not within the IDT\n", (unsigned)iInt); 2256 if (!fAll && !fSingle) 2257 return VINF_SUCCESS; 2258 } 2259 DBGCVAR AddrVar; 2260 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT; 2261 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry; 2262 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE; 2263 int rc = pCmdHlp->pfnMemRead(pCmdHlp, &u, cbEntry, &AddrVar, NULL); 2264 if (RT_FAILURE(rc)) 2265 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt); 2266 2267 /* 2268 * Display it. 2269 */ 2270 switch (enmMode) 2271 { 2272 case CPUMMODE_REAL: 2273 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %RTfp16\n", (unsigned)iInt, u.Real); 2274 /** @todo resolve 16:16 IDTE to a symbol */ 2275 break; 2276 case CPUMMODE_PROTECTED: 2277 if (fAll || fSingle || u.Prot.Gen.u1Present) 2278 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false); 2279 break; 2280 case CPUMMODE_LONG: 2281 if (fAll || fSingle || u.Long.Gen.u1Present) 2282 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL); 2283 break; 2284 default: break; /* to shut up gcc */ 2285 } 2286 if (RT_FAILURE(rc)) 2287 return rc; 2288 2289 /* next */ 2290 iInt++; 2291 } 2292 } 2293 else 2294 DBGCCmdHlpPrintf(pCmdHlp, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number); 2295 } 2296 2297 return VINF_SUCCESS; 2298 } 2299 2300 2301 /** 2302 * @callback_method_impl{FNDBGCCMD, 2303 * The 'da'\, 'dq'\, 'dd'\, 'dw' and 'db' commands.} 2304 */ 2305 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2306 { 2307 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2308 2309 /* 2310 * Validate input. 2311 */ 2312 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 2313 if (cArgs == 1) 2314 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2315 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2316 2317 /* 2318 * Figure out the element size. 2319 */ 2320 unsigned cbElement; 2321 bool fAscii = false; 2322 switch (pCmd->pszCmd[1]) 2323 { 2324 default: 2325 case 'b': cbElement = 1; break; 2326 case 'w': cbElement = 2; break; 2327 case 'd': cbElement = 4; break; 2328 case 'q': cbElement = 8; break; 2329 case 'a': 2330 cbElement = 1; 2331 fAscii = true; 2332 break; 2333 case '\0': 2334 fAscii = !!(pDbgc->cbDumpElement & 0x80000000); 2335 cbElement = pDbgc->cbDumpElement & 0x7fffffff; 2336 if (!cbElement) 2337 cbElement = 1; 2338 break; 2339 } 2340 2341 /* 2342 * Find address. 2343 */ 2344 if (!cArgs) 2345 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE; 2346 else 2347 pDbgc->DumpPos = paArgs[0]; 2348 2349 /* 2350 * Range. 2351 */ 2352 switch (pDbgc->DumpPos.enmRangeType) 2353 { 2354 case DBGCVAR_RANGE_NONE: 2355 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES; 2356 pDbgc->DumpPos.u64Range = 0x60; 2357 break; 2358 2359 case DBGCVAR_RANGE_ELEMENTS: 2360 if (pDbgc->DumpPos.u64Range > 2048) 2361 return DBGCCmdHlpPrintf(pCmdHlp, "error: Too many elements requested. Max is 2048 elements.\n"); 2362 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES; 2363 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range; 2364 break; 2365 2366 case DBGCVAR_RANGE_BYTES: 2367 if (pDbgc->DumpPos.u64Range > 65536) 2368 return DBGCCmdHlpPrintf(pCmdHlp, "error: The requested range is too big. Max is 64KB.\n"); 2369 break; 2370 2371 default: 2372 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType); 2373 } 2374 2375 pDbgc->pLastPos = &pDbgc->DumpPos; 2376 2377 /* 2378 * Do the dumping. 2379 */ 2380 pDbgc->cbDumpElement = cbElement | (fAscii << 31); 2381 int cbLeft = (int)pDbgc->DumpPos.u64Range; 2382 uint8_t u8Prev = '\0'; 2383 for (;;) 2384 { 2385 /* 2386 * Read memory. 2387 */ 2388 char achBuffer[16]; 2389 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft); 2390 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft); 2391 int rc = pCmdHlp->pfnMemRead(pCmdHlp, &achBuffer, cbReq, &pDbgc->DumpPos, &cb); 2392 if (RT_FAILURE(rc)) 2393 { 2394 if (u8Prev && u8Prev != '\n') 2395 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2396 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos); 2397 } 2398 2399 /* 2400 * Display it. 2401 */ 2402 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb); 2403 if (!fAscii) 2404 { 2405 DBGCCmdHlpPrintf(pCmdHlp, "%DV:", &pDbgc->DumpPos); 2406 unsigned i; 2407 for (i = 0; i < cb; i += cbElement) 2408 { 2409 const char *pszSpace = " "; 2410 if (cbElement <= 2 && i == 8 && !fAscii) 2411 pszSpace = "-"; 2412 switch (cbElement) 2413 { 2414 case 1: DBGCCmdHlpPrintf(pCmdHlp, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break; 2415 case 2: DBGCCmdHlpPrintf(pCmdHlp, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break; 2416 case 4: DBGCCmdHlpPrintf(pCmdHlp, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break; 2417 case 8: DBGCCmdHlpPrintf(pCmdHlp, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break; 2418 } 2419 } 2420 2421 /* chars column */ 2422 if (pDbgc->cbDumpElement == 1) 2423 { 2424 while (i++ < sizeof(achBuffer)) 2425 DBGCCmdHlpPrintf(pCmdHlp, " "); 2426 DBGCCmdHlpPrintf(pCmdHlp, " "); 2427 for (i = 0; i < cb; i += cbElement) 2428 { 2429 uint8_t u8 = *(uint8_t *)&achBuffer[i]; 2430 if (RT_C_IS_PRINT(u8) && u8 < 127 && u8 >= 32) 2431 DBGCCmdHlpPrintf(pCmdHlp, "%c", u8); 2432 else 2433 DBGCCmdHlpPrintf(pCmdHlp, "."); 2434 } 2435 } 2436 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2437 } 2438 else 2439 { 2440 /* 2441 * We print up to the first zero and stop there. 2442 * Only printables + '\t' and '\n' are printed. 2443 */ 2444 if (!u8Prev) 2445 DBGCCmdHlpPrintf(pCmdHlp, "%DV:\n", &pDbgc->DumpPos); 2446 uint8_t u8 = '\0'; 2447 unsigned i; 2448 for (i = 0; i < cb; i++) 2449 { 2450 u8Prev = u8; 2451 u8 = *(uint8_t *)&achBuffer[i]; 2452 if ( u8 < 127 2453 && ( (RT_C_IS_PRINT(u8) && u8 >= 32) 2454 || u8 == '\t' 2455 || u8 == '\n')) 2456 DBGCCmdHlpPrintf(pCmdHlp, "%c", u8); 2457 else if (!u8) 2458 break; 2459 else 2460 DBGCCmdHlpPrintf(pCmdHlp, "\\x%x", u8); 2461 } 2462 if (u8 == '\0') 2463 cb = cbLeft = i + 1; 2464 if (cbLeft - cb <= 0 && u8Prev != '\n') 2465 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2466 } 2467 2468 /* 2469 * Advance 2470 */ 2471 cbLeft -= (int)cb; 2472 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb); 2473 if (RT_FAILURE(rc)) 2474 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb); 2475 if (cbLeft <= 0) 2476 break; 2477 } 2478 2479 NOREF(pCmd); 2480 return VINF_SUCCESS; 2481 } 2482 2483 2484 /** 2485 * Best guess at which paging mode currently applies to the guest 2486 * paging structures. 2487 * 2488 * This have to come up with a decent answer even when the guest 2489 * is in non-paged protected mode or real mode. 2490 * 2491 * @returns cr3. 2492 * @param pDbgc The DBGC instance. 2493 * @param pfPAE Where to store the page address extension indicator. 2494 * @param pfLME Where to store the long mode enabled indicator. 2495 * @param pfPSE Where to store the page size extension indicator. 2496 * @param pfPGE Where to store the page global enabled indicator. 2497 * @param pfNXE Where to store the no-execution enabled indicator. 2498 */ 2499 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 2500 { 2501 PVMCPU pVCpu = VMMR3GetCpuByIdU(pDbgc->pUVM, pDbgc->idCpu); 2502 RTGCUINTREG cr4 = CPUMGetGuestCR4(pVCpu); 2503 *pfPSE = !!(cr4 & X86_CR4_PSE); 2504 *pfPGE = !!(cr4 & X86_CR4_PGE); 2505 if (cr4 & X86_CR4_PAE) 2506 { 2507 *pfPSE = true; 2508 *pfPAE = true; 2509 } 2510 else 2511 *pfPAE = false; 2512 2513 *pfLME = CPUMGetGuestMode(pVCpu) == CPUMMODE_LONG; 2514 *pfNXE = false; /* GUEST64 GUESTNX */ 2515 return CPUMGetGuestCR3(pVCpu); 2516 } 2517 2518 2519 /** 2520 * Determine the shadow paging mode. 2521 * 2522 * @returns cr3. 2523 * @param pDbgc The DBGC instance. 2524 * @param pfPAE Where to store the page address extension indicator. 2525 * @param pfLME Where to store the long mode enabled indicator. 2526 * @param pfPSE Where to store the page size extension indicator. 2527 * @param pfPGE Where to store the page global enabled indicator. 2528 * @param pfNXE Where to store the no-execution enabled indicator. 2529 */ 2530 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 2531 { 2532 PVMCPU pVCpu = VMMR3GetCpuByIdU(pDbgc->pUVM, pDbgc->idCpu); 2533 2534 *pfPSE = true; 2535 *pfPGE = false; 2536 switch (PGMGetShadowMode(pVCpu)) 2537 { 2538 default: 2539 case PGMMODE_32_BIT: 2540 *pfPAE = *pfLME = *pfNXE = false; 2541 break; 2542 case PGMMODE_PAE: 2543 *pfLME = *pfNXE = false; 2544 *pfPAE = true; 2545 break; 2546 case PGMMODE_PAE_NX: 2547 *pfLME = false; 2548 *pfPAE = *pfNXE = true; 2549 break; 2550 case PGMMODE_AMD64: 2551 *pfNXE = false; 2552 *pfPAE = *pfLME = true; 2553 break; 2554 case PGMMODE_AMD64_NX: 2555 *pfPAE = *pfLME = *pfNXE = true; 2556 break; 2557 } 2558 return PGMGetHyperCR3(pVCpu); 2559 } 2560 2561 2562 /** 2563 * @callback_method_impl{FNDBGCCMD, 2564 * The 'dpd'\, 'dpda'\, 'dpdb'\, 'dpdg' and 'dpdh' commands.} 2565 */ 2566 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2567 { 2568 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2569 2570 /* 2571 * Validate input. 2572 */ 2573 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 2574 if (cArgs == 1 && pCmd->pszCmd[3] == 'a') 2575 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2576 if (cArgs == 1 && pCmd->pszCmd[3] != 'a') 2577 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2578 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2579 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2580 2581 /* 2582 * Guest or shadow page directories? Get the paging parameters. 2583 */ 2584 bool fGuest = pCmd->pszCmd[3] != 'h'; 2585 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a') 2586 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2587 ? pDbgc->fRegCtxGuest 2588 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 2589 2590 bool fPAE, fLME, fPSE, fPGE, fNXE; 2591 uint64_t cr3 = fGuest 2592 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 2593 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 2594 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 2595 2596 /* 2597 * Setup default argument if none was specified. 2598 * Fix address / index confusion. 2599 */ 2600 DBGCVAR VarDefault; 2601 if (!cArgs) 2602 { 2603 if (pCmd->pszCmd[3] == 'a') 2604 { 2605 if (fLME || fPAE) 2606 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n"); 2607 if (fGuest) 2608 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3); 2609 else 2610 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3); 2611 } 2612 else 2613 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0); 2614 paArgs = &VarDefault; 2615 cArgs = 1; 2616 } 2617 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER) 2618 { 2619 /* If it's a number (not an address), it's an index, so convert it to an address. */ 2620 Assert(pCmd->pszCmd[3] != 'a'); 2621 VarDefault = paArgs[0]; 2622 if (fPAE) 2623 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n"); 2624 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry) 2625 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1); 2626 VarDefault.u.u64Number <<= X86_PD_SHIFT; 2627 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT; 2628 paArgs = &VarDefault; 2629 } 2630 2631 /* 2632 * Locate the PDE to start displaying at. 2633 * 2634 * The 'dpda' command takes the address of a PDE, while the others are guest 2635 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple 2636 * while the others require us to do all the tedious walking thru the paging 2637 * hierarchy to find the intended PDE. 2638 */ 2639 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */ 2640 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */ 2641 DBGCVAR VarPDEAddr; /* The address of the current PDE. */ 2642 unsigned cEntries; /* The number of entries to display. */ 2643 unsigned cEntriesMax; /* The max number of entries to display. */ 2644 int rc; 2645 if (pCmd->pszCmd[3] == 'a') 2646 { 2647 VarPDEAddr = paArgs[0]; 2648 switch (VarPDEAddr.enmRangeType) 2649 { 2650 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break; 2651 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break; 2652 default: cEntries = 10; break; 2653 } 2654 cEntriesMax = PAGE_SIZE / cbEntry; 2655 } 2656 else 2657 { 2658 /* 2659 * Determine the range. 2660 */ 2661 switch (paArgs[0].enmRangeType) 2662 { 2663 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 2664 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 2665 default: cEntries = 10; break; 2666 } 2667 2668 /* 2669 * Normalize the input address, it must be a flat GC address. 2670 */ 2671 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 2672 if (RT_FAILURE(rc)) 2673 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 2674 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 2675 { 2676 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 2677 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 2678 } 2679 if (fPAE) 2680 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1); 2681 else 2682 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1); 2683 2684 /* 2685 * Do the paging walk until we get to the page directory. 2686 */ 2687 DBGCVAR VarCur; 2688 if (fGuest) 2689 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 2690 else 2691 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 2692 if (fLME) 2693 { 2694 /* Page Map Level 4 Lookup. */ 2695 /* Check if it's a valid address first? */ 2696 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 2697 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 2698 X86PML4E Pml4e; 2699 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 2700 if (RT_FAILURE(rc)) 2701 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 2702 if (!Pml4e.n.u1Present) 2703 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 2704 2705 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 2706 Assert(fPAE); 2707 } 2708 if (fPAE) 2709 { 2710 /* Page directory pointer table. */ 2711 X86PDPE Pdpe; 2712 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe); 2713 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 2714 if (RT_FAILURE(rc)) 2715 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 2716 if (!Pdpe.n.u1Present) 2717 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 2718 2719 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK; 2720 VarPDEAddr = VarCur; 2721 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 2722 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE); 2723 } 2724 else 2725 { 2726 /* 32-bit legacy - CR3 == page directory. */ 2727 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK; 2728 VarPDEAddr = VarCur; 2729 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE); 2730 } 2731 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 2732 } 2733 2734 /* adjust cEntries */ 2735 cEntries = RT_MAX(1, cEntries); 2736 cEntries = RT_MIN(cEntries, cEntriesMax); 2737 2738 /* 2739 * The display loop. 2740 */ 2741 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n", 2742 &VarPDEAddr, iEntry); 2743 do 2744 { 2745 /* 2746 * Read. 2747 */ 2748 X86PDEPAE Pde; 2749 Pde.u = 0; 2750 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, cbEntry, &VarPDEAddr, NULL); 2751 if (RT_FAILURE(rc)) 2752 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr); 2753 2754 /* 2755 * Display. 2756 */ 2757 if (iEntry != ~0U) 2758 { 2759 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 2760 iEntry++; 2761 } 2762 if (fPSE && Pde.b.u1Size) 2763 DBGCCmdHlpPrintf(pCmdHlp, 2764 fPAE 2765 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 2766 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 2767 Pde.u, 2768 Pde.u & X86_PDE_PAE_PG_MASK, 2769 Pde.b.u1Present ? "p " : "np", 2770 Pde.b.u1Write ? "w" : "r", 2771 Pde.b.u1User ? "u" : "s", 2772 Pde.b.u1Accessed ? "a " : "na", 2773 Pde.b.u1Dirty ? "d " : "nd", 2774 Pde.b.u3Available, 2775 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ", 2776 Pde.b.u1WriteThru ? "pwt" : " ", 2777 Pde.b.u1CacheDisable ? "pcd" : " ", 2778 Pde.b.u1PAT ? "pat" : "", 2779 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 2780 else 2781 DBGCCmdHlpPrintf(pCmdHlp, 2782 fPAE 2783 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s" 2784 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s", 2785 Pde.u, 2786 Pde.u & X86_PDE_PAE_PG_MASK, 2787 Pde.n.u1Present ? "p " : "np", 2788 Pde.n.u1Write ? "w" : "r", 2789 Pde.n.u1User ? "u" : "s", 2790 Pde.n.u1Accessed ? "a " : "na", 2791 Pde.u & RT_BIT(6) ? "6 " : " ", 2792 Pde.n.u3Available, 2793 Pde.u & RT_BIT(8) ? "8" : " ", 2794 Pde.n.u1WriteThru ? "pwt" : " ", 2795 Pde.n.u1CacheDisable ? "pcd" : " ", 2796 Pde.u & RT_BIT(7) ? "7" : "", 2797 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 2798 if (Pde.u & UINT64_C(0x7fff000000000000)) 2799 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000))); 2800 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2801 if (RT_FAILURE(rc)) 2802 return rc; 2803 2804 /* 2805 * Advance. 2806 */ 2807 VarPDEAddr.u.u64Number += cbEntry; 2808 if (iEntry != ~0U) 2809 VarGCPtr.u.GCFlat += fPAE ? RT_BIT_32(X86_PD_PAE_SHIFT) : RT_BIT_32(X86_PD_SHIFT); 2810 } while (cEntries-- > 0); 2811 2812 return VINF_SUCCESS; 2813 } 2814 2815 2816 /** 2817 * @callback_method_impl{FNDBGCCMD, The 'dpdb' command.} 2818 */ 2819 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2820 { 2821 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2822 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]); 2823 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]); 2824 if (RT_FAILURE(rc1)) 2825 return rc1; 2826 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); 2827 return rc2; 2828 } 2829 2830 2831 /** 2832 * @callback_method_impl{FNDBGCCMD, The 'dph*' commands and main part of 'm'.} 2833 */ 2834 static DECLCALLBACK(int) dbgcCmdDumpPageHierarchy(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2835 { 2836 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2837 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2838 2839 /* 2840 * Figure the context and base flags. 2841 */ 2842 uint32_t fFlags = DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_PRINT_CR3; 2843 if (pCmd->pszCmd[0] == 'm') 2844 fFlags |= DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW; 2845 else if (pCmd->pszCmd[3] == '\0') 2846 fFlags |= pDbgc->fRegCtxGuest ? DBGFPGDMP_FLAGS_GUEST : DBGFPGDMP_FLAGS_SHADOW; 2847 else if (pCmd->pszCmd[3] == 'g') 2848 fFlags |= DBGFPGDMP_FLAGS_GUEST; 2849 else if (pCmd->pszCmd[3] == 'h') 2850 fFlags |= DBGFPGDMP_FLAGS_SHADOW; 2851 else 2852 AssertFailed(); 2853 2854 if (pDbgc->cPagingHierarchyDumps == 0) 2855 fFlags |= DBGFPGDMP_FLAGS_HEADER; 2856 pDbgc->cPagingHierarchyDumps = (pDbgc->cPagingHierarchyDumps + 1) % 42; 2857 2858 /* 2859 * Get the range. 2860 */ 2861 PCDBGCVAR pRange = cArgs > 0 ? &paArgs[0] : pDbgc->pLastPos; 2862 RTGCPTR GCPtrFirst = NIL_RTGCPTR; 2863 int rc = DBGCCmdHlpVarToFlatAddr(pCmdHlp, pRange, &GCPtrFirst); 2864 if (RT_FAILURE(rc)) 2865 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to convert %DV to a flat address: %Rrc", pRange, rc); 2866 2867 uint64_t cbRange; 2868 rc = DBGCCmdHlpVarGetRange(pCmdHlp, pRange, PAGE_SIZE, PAGE_SIZE * 8, &cbRange); 2869 if (RT_FAILURE(rc)) 2870 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to obtain the range of %DV: %Rrc", pRange, rc); 2871 2872 RTGCPTR GCPtrLast = RTGCPTR_MAX - GCPtrFirst; 2873 if (cbRange >= GCPtrLast) 2874 GCPtrLast = RTGCPTR_MAX; 2875 else if (!cbRange) 2876 GCPtrLast = GCPtrFirst; 2877 else 2878 GCPtrLast = GCPtrFirst + cbRange - 1; 2879 2880 /* 2881 * Do we have a CR3? 2882 */ 2883 uint64_t cr3 = 0; 2884 if (cArgs > 1) 2885 { 2886 if ((fFlags & (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) == (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) 2887 return DBGCCmdHlpFail(pCmdHlp, pCmd, "No CR3 or mode arguments when dumping both context, please."); 2888 if (paArgs[1].enmType != DBGCVAR_TYPE_NUMBER) 2889 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The CR3 argument is not a number: %DV", &paArgs[1]); 2890 cr3 = paArgs[1].u.u64Number; 2891 } 2892 else 2893 fFlags |= DBGFPGDMP_FLAGS_CURRENT_CR3; 2894 2895 /* 2896 * Do we have a mode? 2897 */ 2898 if (cArgs > 2) 2899 { 2900 if (paArgs[2].enmType != DBGCVAR_TYPE_STRING) 2901 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The mode argument is not a string: %DV", &paArgs[2]); 2902 static const struct MODETOFLAGS 2903 { 2904 const char *pszName; 2905 uint32_t fFlags; 2906 } s_aModeToFlags[] = 2907 { 2908 { "ept", DBGFPGDMP_FLAGS_EPT }, 2909 { "legacy", 0 }, 2910 { "legacy-np", DBGFPGDMP_FLAGS_NP }, 2911 { "pse", DBGFPGDMP_FLAGS_PSE }, 2912 { "pse-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_NP }, 2913 { "pae", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE }, 2914 { "pae-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NP }, 2915 { "pae-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE }, 2916 { "pae-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP }, 2917 { "long", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME }, 2918 { "long-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NP }, 2919 { "long-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE }, 2920 { "long-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP } 2921 }; 2922 int i = RT_ELEMENTS(s_aModeToFlags); 2923 while (i-- > 0) 2924 if (!strcmp(s_aModeToFlags[i].pszName, paArgs[2].u.pszString)) 2925 { 2926 fFlags |= s_aModeToFlags[i].fFlags; 2927 break; 2928 } 2929 if (i < 0) 2930 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Unknown mode: \"%s\"", paArgs[2].u.pszString); 2931 } 2932 else 2933 fFlags |= DBGFPGDMP_FLAGS_CURRENT_MODE; 2934 2935 /* 2936 * Call the worker. 2937 */ 2938 rc = DBGFR3PagingDumpEx(pUVM, pDbgc->idCpu, fFlags, cr3, GCPtrFirst, GCPtrLast, 99 /*cMaxDepth*/, 2939 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp)); 2940 if (RT_FAILURE(rc)) 2941 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3PagingDumpEx: %Rrc\n", rc); 2942 return VINF_SUCCESS; 2943 } 2944 2945 2946 2947 /** 2948 * @callback_method_impl{FNDBGCCMD, The 'dpg*' commands.} 2949 */ 2950 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2951 { 2952 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2953 2954 /* 2955 * Validate input. 2956 */ 2957 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1); 2958 if (pCmd->pszCmd[3] == 'a') 2959 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2960 else 2961 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2962 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2963 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2964 2965 /* 2966 * Guest or shadow page tables? Get the paging parameters. 2967 */ 2968 bool fGuest = pCmd->pszCmd[3] != 'h'; 2969 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a') 2970 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2971 ? pDbgc->fRegCtxGuest 2972 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 2973 2974 bool fPAE, fLME, fPSE, fPGE, fNXE; 2975 uint64_t cr3 = fGuest 2976 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 2977 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 2978 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 2979 2980 /* 2981 * Locate the PTE to start displaying at. 2982 * 2983 * The 'dpta' command takes the address of a PTE, while the others are guest 2984 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple 2985 * while the others require us to do all the tedious walking thru the paging 2986 * hierarchy to find the intended PTE. 2987 */ 2988 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */ 2989 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */ 2990 DBGCVAR VarPTEAddr; /* The address of the current PTE. */ 2991 unsigned cEntries; /* The number of entries to display. */ 2992 unsigned cEntriesMax; /* The max number of entries to display. */ 2993 int rc; 2994 if (pCmd->pszCmd[3] == 'a') 2995 { 2996 VarPTEAddr = paArgs[0]; 2997 switch (VarPTEAddr.enmRangeType) 2998 { 2999 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break; 3000 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break; 3001 default: cEntries = 10; break; 3002 } 3003 cEntriesMax = PAGE_SIZE / cbEntry; 3004 } 3005 else 3006 { 3007 /* 3008 * Determine the range. 3009 */ 3010 switch (paArgs[0].enmRangeType) 3011 { 3012 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 3013 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 3014 default: cEntries = 10; break; 3015 } 3016 3017 /* 3018 * Normalize the input address, it must be a flat GC address. 3019 */ 3020 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 3021 if (RT_FAILURE(rc)) 3022 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3023 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 3024 { 3025 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 3026 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 3027 } 3028 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK; 3029 3030 /* 3031 * Do the paging walk until we get to the page table. 3032 */ 3033 DBGCVAR VarCur; 3034 if (fGuest) 3035 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 3036 else 3037 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 3038 if (fLME) 3039 { 3040 /* Page Map Level 4 Lookup. */ 3041 /* Check if it's a valid address first? */ 3042 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 3043 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 3044 X86PML4E Pml4e; 3045 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 3046 if (RT_FAILURE(rc)) 3047 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 3048 if (!Pml4e.n.u1Present) 3049 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 3050 3051 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 3052 Assert(fPAE); 3053 } 3054 if (fPAE) 3055 { 3056 /* Page directory pointer table. */ 3057 X86PDPE Pdpe; 3058 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe); 3059 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 3060 if (RT_FAILURE(rc)) 3061 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 3062 if (!Pdpe.n.u1Present) 3063 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 3064 3065 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 3066 3067 /* Page directory (PAE). */ 3068 X86PDEPAE Pde; 3069 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde); 3070 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL); 3071 if (RT_FAILURE(rc)) 3072 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3073 if (!Pde.n.u1Present) 3074 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3075 if (fPSE && Pde.n.u1Size) 3076 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3077 3078 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK; 3079 VarPTEAddr = VarCur; 3080 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK; 3081 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE); 3082 } 3083 else 3084 { 3085 /* Page directory (legacy). */ 3086 X86PDE Pde; 3087 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde); 3088 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL); 3089 if (RT_FAILURE(rc)) 3090 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3091 if (!Pde.n.u1Present) 3092 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3093 if (fPSE && Pde.n.u1Size) 3094 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3095 3096 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK; 3097 VarPTEAddr = VarCur; 3098 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK; 3099 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE); 3100 } 3101 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 3102 } 3103 3104 /* adjust cEntries */ 3105 cEntries = RT_MAX(1, cEntries); 3106 cEntries = RT_MIN(cEntries, cEntriesMax); 3107 3108 /* 3109 * The display loop. 3110 */ 3111 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", 3112 &VarPTEAddr, &VarGCPtr, iEntry); 3113 do 3114 { 3115 /* 3116 * Read. 3117 */ 3118 X86PTEPAE Pte; 3119 Pte.u = 0; 3120 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pte, cbEntry, &VarPTEAddr, NULL); 3121 if (RT_FAILURE(rc)) 3122 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr); 3123 3124 /* 3125 * Display. 3126 */ 3127 if (iEntry != ~0U) 3128 { 3129 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 3130 iEntry++; 3131 } 3132 DBGCCmdHlpPrintf(pCmdHlp, 3133 fPAE 3134 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 3135 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 3136 Pte.u, 3137 Pte.u & X86_PTE_PAE_PG_MASK, 3138 Pte.n.u1Present ? "p " : "np", 3139 Pte.n.u1Write ? "w" : "r", 3140 Pte.n.u1User ? "u" : "s", 3141 Pte.n.u1Accessed ? "a " : "na", 3142 Pte.n.u1Dirty ? "d " : "nd", 3143 Pte.n.u3Available, 3144 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ", 3145 Pte.n.u1WriteThru ? "pwt" : " ", 3146 Pte.n.u1CacheDisable ? "pcd" : " ", 3147 Pte.n.u1PAT ? "pat" : " ", 3148 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " " 3149 ); 3150 if (Pte.u & UINT64_C(0x7fff000000000000)) 3151 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000))); 3152 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 3153 if (RT_FAILURE(rc)) 3154 return rc; 3155 3156 /* 3157 * Advance. 3158 */ 3159 VarPTEAddr.u.u64Number += cbEntry; 3160 if (iEntry != ~0U) 3161 VarGCPtr.u.GCFlat += PAGE_SIZE; 3162 } while (cEntries-- > 0); 3163 3164 return VINF_SUCCESS; 3165 } 3166 3167 3168 /** 3169 * @callback_method_impl{FNDBGCCMD, The 'dptb' command.} 3170 */ 3171 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3172 { 3173 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3174 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]); 3175 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]); 3176 if (RT_FAILURE(rc1)) 3177 return rc1; 3178 NOREF(pCmd); NOREF(cArgs); 3179 return rc2; 3180 } 3181 3182 3183 /** 3184 * @callback_method_impl{FNDBGCCMD, The 'dt' command.} 3185 */ 3186 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3187 { 3188 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3189 int rc; 3190 3191 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3192 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 3193 if (cArgs == 1) 3194 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType != DBGCVAR_TYPE_STRING 3195 && paArgs[0].enmType != DBGCVAR_TYPE_SYMBOL); 3196 3197 /* 3198 * Check if the command indicates the type. 3199 */ 3200 enum { kTss16, kTss32, kTss64, kTssToBeDetermined } enmTssType = kTssToBeDetermined; 3201 if (!strcmp(pCmd->pszCmd, "dt16")) 3202 enmTssType = kTss16; 3203 else if (!strcmp(pCmd->pszCmd, "dt32")) 3204 enmTssType = kTss32; 3205 else if (!strcmp(pCmd->pszCmd, "dt64")) 3206 enmTssType = kTss64; 3207 3208 /* 3209 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer. 3210 */ 3211 uint32_t SelTss = UINT32_MAX; 3212 DBGCVAR VarTssAddr; 3213 if (cArgs == 0) 3214 { 3215 /** @todo consider querying the hidden bits instead (missing API). */ 3216 uint16_t SelTR; 3217 rc = DBGFR3RegCpuQueryU16(pUVM, pDbgc->idCpu, DBGFREG_TR, &SelTR); 3218 if (RT_FAILURE(rc)) 3219 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query TR, rc=%Rrc\n", rc); 3220 DBGCVAR_INIT_GC_FAR(&VarTssAddr, SelTR, 0); 3221 SelTss = SelTR; 3222 } 3223 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER) 3224 { 3225 if (paArgs[0].u.u64Number < 0xffff) 3226 DBGCVAR_INIT_GC_FAR(&VarTssAddr, (RTSEL)paArgs[0].u.u64Number, 0); 3227 else 3228 { 3229 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_ELEMENTS) 3230 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Element count doesn't combine with a TSS address.\n"); 3231 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, paArgs[0].u.u64Number); 3232 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_BYTES) 3233 { 3234 VarTssAddr.enmRangeType = paArgs[0].enmRangeType; 3235 VarTssAddr.u64Range = paArgs[0].u64Range; 3236 } 3237 } 3238 } 3239 else 3240 VarTssAddr = paArgs[0]; 3241 3242 /* 3243 * Deal with TSS:ign by means of the GDT. 3244 */ 3245 if (VarTssAddr.enmType == DBGCVAR_TYPE_GC_FAR) 3246 { 3247 SelTss = VarTssAddr.u.GCFar.sel; 3248 DBGFSELINFO SelInfo; 3249 rc = DBGFR3SelQueryInfo(pUVM, pDbgc->idCpu, VarTssAddr.u.GCFar.sel, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo); 3250 if (RT_FAILURE(rc)) 3251 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3SelQueryInfo(,%u,%d,,) -> %Rrc.\n", 3252 pDbgc->idCpu, VarTssAddr.u.GCFar.sel, rc); 3253 3254 if (SelInfo.u.Raw.Gen.u1DescType) 3255 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (!sys)\n", VarTssAddr.u.GCFar.sel); 3256 3257 switch (SelInfo.u.Raw.Gen.u4Type) 3258 { 3259 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 3260 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 3261 if (enmTssType == kTssToBeDetermined) 3262 enmTssType = kTss16; 3263 break; 3264 3265 case X86_SEL_TYPE_SYS_386_TSS_BUSY: /* AMD64 too */ 3266 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 3267 if (enmTssType == kTssToBeDetermined) 3268 enmTssType = SelInfo.fFlags & DBGFSELINFO_FLAGS_LONG_MODE ? kTss64 : kTss32; 3269 break; 3270 3271 default: 3272 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (type=%x)\n", 3273 VarTssAddr.u.GCFar.sel, SelInfo.u.Raw.Gen.u4Type); 3274 } 3275 3276 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, SelInfo.GCPtrBase); 3277 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, RT_MAX(SelInfo.cbLimit + 1, SelInfo.cbLimit)); 3278 } 3279 3280 /* 3281 * Determine the TSS type if none is currently given. 3282 */ 3283 if (enmTssType == kTssToBeDetermined) 3284 { 3285 if ( VarTssAddr.u64Range > 0 3286 && VarTssAddr.u64Range < sizeof(X86TSS32) - 4) 3287 enmTssType = kTss16; 3288 else 3289 { 3290 uint64_t uEfer; 3291 rc = DBGFR3RegCpuQueryU64(pUVM, pDbgc->idCpu, DBGFREG_MSR_K6_EFER, &uEfer); 3292 if ( RT_FAILURE(rc) 3293 || !(uEfer & MSR_K6_EFER_LMA) ) 3294 enmTssType = kTss32; 3295 else 3296 enmTssType = kTss64; 3297 } 3298 } 3299 3300 /* 3301 * Figure the min/max sizes. 3302 * ASSUMES max TSS size is 64 KB. 3303 */ 3304 uint32_t cbTssMin; 3305 uint32_t cbTssMax; 3306 switch (enmTssType) 3307 { 3308 case kTss16: 3309 cbTssMin = cbTssMax = sizeof(X86TSS16); 3310 break; 3311 case kTss32: 3312 cbTssMin = RT_OFFSETOF(X86TSS32, IntRedirBitmap); 3313 cbTssMax = _64K; 3314 break; 3315 case kTss64: 3316 cbTssMin = RT_OFFSETOF(X86TSS64, IntRedirBitmap); 3317 cbTssMax = _64K; 3318 break; 3319 default: 3320 AssertFailedReturn(VERR_INTERNAL_ERROR); 3321 } 3322 uint32_t cbTss = VarTssAddr.enmRangeType == DBGCVAR_RANGE_BYTES ? (uint32_t)VarTssAddr.u64Range : 0; 3323 if (cbTss == 0) 3324 cbTss = cbTssMin; 3325 else if (cbTss < cbTssMin) 3326 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Minimum TSS size is %u bytes, you specified %llu (%llx) bytes.\n", 3327 cbTssMin, VarTssAddr.u64Range, VarTssAddr.u64Range); 3328 else if (cbTss > cbTssMax) 3329 cbTss = cbTssMax; 3330 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, cbTss); 3331 3332 /* 3333 * Read the TSS into a temporary buffer. 3334 */ 3335 uint8_t abBuf[_64K]; 3336 size_t cbTssRead; 3337 rc = DBGCCmdHlpMemRead(pCmdHlp, abBuf, cbTss, &VarTssAddr, &cbTssRead); 3338 if (RT_FAILURE(rc)) 3339 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read TSS at %Dv: %Rrc\n", &VarTssAddr, rc); 3340 if (cbTssRead < cbTssMin) 3341 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read essential parts of the TSS (read %zu, min %zu).\n", 3342 cbTssRead, cbTssMin); 3343 if (cbTssRead < cbTss) 3344 memset(&abBuf[cbTssRead], 0xff, cbTss - cbTssRead); 3345 3346 3347 /* 3348 * Format the TSS. 3349 */ 3350 uint16_t offIoBitmap; 3351 switch (enmTssType) 3352 { 3353 case kTss16: 3354 { 3355 PCX86TSS16 pTss = (PCX86TSS16)&abBuf[0]; 3356 if (SelTss != UINT32_MAX) 3357 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS16 at %Dv\n", SelTss, &VarTssAddr); 3358 else 3359 DBGCCmdHlpPrintf(pCmdHlp, "TSS16 at %Dv\n", &VarTssAddr); 3360 DBGCCmdHlpPrintf(pCmdHlp, 3361 "ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x\n" 3362 "ip=%04x sp=%04x bp=%04x\n" 3363 "cs=%04x ss=%04x ds=%04x es=%04x flags=%04x\n" 3364 "ss:sp0=%04x:%04x ss:sp1=%04x:%04x ss:sp2=%04x:%04x\n" 3365 "prev=%04x ldtr=%04x\n" 3366 , 3367 pTss->ax, pTss->bx, pTss->cx, pTss->dx, pTss->si, pTss->di, 3368 pTss->ip, pTss->sp, pTss->bp, 3369 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->flags, 3370 pTss->ss0, pTss->sp0, pTss->ss1, pTss->sp1, pTss->ss2, pTss->sp2, 3371 pTss->selPrev, pTss->selLdt); 3372 if (pTss->cs != 0) 3373 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%04x L 0", pTss->cs, pTss->ip); 3374 offIoBitmap = 0; 3375 break; 3376 } 3377 3378 case kTss32: 3379 { 3380 PCX86TSS32 pTss = (PCX86TSS32)&abBuf[0]; 3381 if (SelTss != UINT32_MAX) 3382 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS32 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin); 3383 else 3384 DBGCCmdHlpPrintf(pCmdHlp, "TSS32 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin); 3385 DBGCCmdHlpPrintf(pCmdHlp, 3386 "eax=%08x bx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n" 3387 "eip=%08x esp=%08x ebp=%08x\n" 3388 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n" 3389 "ss:esp0=%04x:%08x ss:esp1=%04x:%08x ss:esp2=%04x:%08x\n" 3390 "prev=%04x ldtr=%04x cr3=%08x debug=%u iomap=%04x\n" 3391 , 3392 pTss->eax, pTss->ebx, pTss->ecx, pTss->edx, pTss->esi, pTss->edi, 3393 pTss->eip, pTss->esp, pTss->ebp, 3394 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->fs, pTss->gs, pTss->eflags, 3395 pTss->ss0, pTss->esp0, pTss->ss1, pTss->esp1, pTss->ss2, pTss->esp2, 3396 pTss->selPrev, pTss->selLdt, pTss->cr3, pTss->fDebugTrap, pTss->offIoBitmap); 3397 if (pTss->cs != 0) 3398 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pTss->cs, pTss->eip); 3399 offIoBitmap = pTss->offIoBitmap; 3400 break; 3401 } 3402 3403 case kTss64: 3404 { 3405 PCX86TSS64 pTss = (PCX86TSS64)&abBuf[0]; 3406 if (SelTss != UINT32_MAX) 3407 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS64 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin); 3408 else 3409 DBGCCmdHlpPrintf(pCmdHlp, "TSS64 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin); 3410 DBGCCmdHlpPrintf(pCmdHlp, 3411 "rsp0=%016RX16 rsp1=%016RX16 rsp2=%016RX16\n" 3412 "ist1=%016RX16 ist2=%016RX16\n" 3413 "ist3=%016RX16 ist4=%016RX16\n" 3414 "ist5=%016RX16 ist6=%016RX16\n" 3415 "ist7=%016RX16 iomap=%04x\n" 3416 , 3417 pTss->rsp0, pTss->rsp1, pTss->rsp2, 3418 pTss->ist1, pTss->ist2, 3419 pTss->ist3, pTss->ist4, 3420 pTss->ist5, pTss->ist6, 3421 pTss->ist7, pTss->offIoBitmap); 3422 offIoBitmap = pTss->offIoBitmap; 3423 break; 3424 } 3425 3426 default: 3427 AssertFailedReturn(VERR_INTERNAL_ERROR); 3428 } 3429 3430 /* 3431 * Dump the interrupt redirection bitmap. 3432 */ 3433 if (enmTssType != kTss16) 3434 { 3435 if ( offIoBitmap > cbTssMin 3436 && offIoBitmap < cbTss) /** @todo check exactly what the edge cases are here. */ 3437 { 3438 if (offIoBitmap - cbTssMin >= 32) 3439 { 3440 DBGCCmdHlpPrintf(pCmdHlp, "Interrupt redirection:\n"); 3441 uint8_t const *pbIntRedirBitmap = &abBuf[offIoBitmap - 32]; 3442 uint32_t iStart = 0; 3443 bool fPrev = ASMBitTest(pbIntRedirBitmap, 0); /* LE/BE issue */ 3444 for (uint32_t i = 0; i < 256; i++) 3445 { 3446 bool fThis = ASMBitTest(pbIntRedirBitmap, i); 3447 if (fThis != fPrev) 3448 { 3449 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, i - 1, fPrev ? "Protected mode" : "Redirected"); 3450 fPrev = fThis; 3451 iStart = i; 3452 } 3453 } 3454 if (iStart != 255) 3455 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, 255, fPrev ? "Protected mode" : "Redirected"); 3456 } 3457 else 3458 DBGCCmdHlpPrintf(pCmdHlp, "Invalid interrupt redirection bitmap size: %u (%#x), expected 32 bytes.\n", 3459 offIoBitmap - cbTssMin, offIoBitmap - cbTssMin); 3460 } 3461 else if (offIoBitmap > 0) 3462 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap (-%#x)\n", cbTssMin - offIoBitmap); 3463 else 3464 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap\n"); 3465 } 3466 3467 /* 3468 * Dump the I/O permission bitmap if present. The IOPM cannot start below offset 0x64 3469 * (that applies to both 32-bit and 64-bit TSSs since their size is the same). 3470 */ 3471 if (enmTssType != kTss16) 3472 { 3473 if (offIoBitmap < cbTss && offIoBitmap >= 0x64) 3474 { 3475 uint32_t cPorts = RT_MIN((cbTss - offIoBitmap) * 8, _64K); 3476 DBGCVAR VarAddr; 3477 DBGCCmdHlpEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarTssAddr, offIoBitmap); 3478 DBGCCmdHlpPrintf(pCmdHlp, "I/O bitmap at %DV - %#x ports:\n", &VarAddr, cPorts); 3479 3480 uint8_t const *pbIoBitmap = &abBuf[offIoBitmap]; 3481 uint32_t iStart = 0; 3482 bool fPrev = ASMBitTest(pbIoBitmap, 0); 3483 uint32_t cLine = 0; 3484 for (uint32_t i = 1; i < cPorts; i++) 3485 { 3486 bool fThis = ASMBitTest(pbIoBitmap, i); 3487 if (fThis != fPrev) 3488 { 3489 cLine++; 3490 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s%s", iStart, i-1, 3491 fPrev ? "GP" : "OK", (cLine % 6) == 0 ? "\n" : " "); 3492 fPrev = fThis; 3493 iStart = i; 3494 } 3495 } 3496 if (iStart != _64K-1) 3497 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s\n", iStart, _64K-1, fPrev ? "GP" : "OK"); 3498 } 3499 else if (offIoBitmap > 0) 3500 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap (-%#x)\n", cbTssMin - offIoBitmap); 3501 else 3502 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap\n"); 3503 } 3504 3505 return VINF_SUCCESS; 3506 } 3507 3508 3509 /** 3510 * @callback_method_impl{FNDBGCCMD, The 'm' command.} 3511 */ 3512 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3513 { 3514 DBGCCmdHlpPrintf(pCmdHlp, "Address: %DV\n", &paArgs[0]); 3515 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3516 return dbgcCmdDumpPageHierarchy(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 3517 } 3518 3519 3520 /** 3521 * Converts one or more variables into a byte buffer for a 3522 * given unit size. 3523 * 3524 * @returns VBox status codes: 3525 * @retval VERR_TOO_MUCH_DATA if the buffer is too small, bitched. 3526 * @retval VERR_INTERNAL_ERROR on bad variable type, bitched. 3527 * @retval VINF_SUCCESS on success. 3528 * 3529 * @param pvBuf The buffer to convert into. 3530 * @param pcbBuf The buffer size on input. The size of the result on output. 3531 * @param cbUnit The unit size to apply when converting. 3532 * The high bit is used to indicate unicode string. 3533 * @param paVars The array of variables to convert. 3534 * @param cVars The number of variables. 3535 */ 3536 int dbgcVarsToBytes(PDBGCCMDHLP pCmdHlp, void *pvBuf, uint32_t *pcbBuf, size_t cbUnit, PCDBGCVAR paVars, unsigned cVars) 3537 { 3538 union 3539 { 3540 uint8_t *pu8; 3541 uint16_t *pu16; 3542 uint32_t *pu32; 3543 uint64_t *pu64; 3544 } u, uEnd; 3545 u.pu8 = (uint8_t *)pvBuf; 3546 uEnd.pu8 = u.pu8 + *pcbBuf; 3547 3548 unsigned i; 3549 for (i = 0; i < cVars && u.pu8 < uEnd.pu8; i++) 3550 { 3551 switch (paVars[i].enmType) 3552 { 3553 case DBGCVAR_TYPE_GC_FAR: 3554 case DBGCVAR_TYPE_GC_FLAT: 3555 case DBGCVAR_TYPE_GC_PHYS: 3556 case DBGCVAR_TYPE_HC_FLAT: 3557 case DBGCVAR_TYPE_HC_PHYS: 3558 case DBGCVAR_TYPE_NUMBER: 3559 { 3560 uint64_t u64 = paVars[i].u.u64Number; 3561 switch (cbUnit & 0x1f) 3562 { 3563 case 1: 3564 do 3565 { 3566 *u.pu8++ = u64; 3567 u64 >>= 8; 3568 } while (u64); 3569 break; 3570 case 2: 3571 do 3572 { 3573 *u.pu16++ = u64; 3574 u64 >>= 16; 3575 } while (u64); 3576 break; 3577 case 4: 3578 *u.pu32++ = u64; 3579 u64 >>= 32; 3580 if (u64) 3581 *u.pu32++ = u64; 3582 break; 3583 case 8: 3584 *u.pu64++ = u64; 3585 break; 3586 } 3587 break; 3588 } 3589 3590 case DBGCVAR_TYPE_STRING: 3591 case DBGCVAR_TYPE_SYMBOL: 3592 { 3593 const char *psz = paVars[i].u.pszString; 3594 size_t cbString = strlen(psz); 3595 if (cbUnit & RT_BIT_32(31)) 3596 { 3597 /* Explode char to unit. */ 3598 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8) * (cbUnit & 0x1f)) 3599 { 3600 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3601 return VERR_TOO_MUCH_DATA; 3602 } 3603 while (*psz) 3604 { 3605 switch (cbUnit & 0x1f) 3606 { 3607 case 1: *u.pu8++ = *psz; break; 3608 case 2: *u.pu16++ = *psz; break; 3609 case 4: *u.pu32++ = *psz; break; 3610 case 8: *u.pu64++ = *psz; break; 3611 } 3612 psz++; 3613 } 3614 } 3615 else 3616 { 3617 /* Raw copy with zero padding if the size isn't aligned. */ 3618 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8)) 3619 { 3620 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3621 return VERR_TOO_MUCH_DATA; 3622 } 3623 3624 size_t cbCopy = cbString & ~(cbUnit - 1); 3625 memcpy(u.pu8, psz, cbCopy); 3626 u.pu8 += cbCopy; 3627 psz += cbCopy; 3628 3629 size_t cbReminder = cbString & (cbUnit - 1); 3630 if (cbReminder) 3631 { 3632 memcpy(u.pu8, psz, cbString & (cbUnit - 1)); 3633 memset(u.pu8 + cbReminder, 0, cbUnit - cbReminder); 3634 u.pu8 += cbUnit; 3635 } 3636 } 3637 break; 3638 } 3639 3640 default: 3641 *pcbBuf = u.pu8 - (uint8_t *)pvBuf; 3642 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INTERNAL_ERROR, 3643 "i=%d enmType=%d\n", i, paVars[i].enmType); 3644 return VERR_INTERNAL_ERROR; 3645 } 3646 } 3647 *pcbBuf = u.pu8 - (uint8_t *)pvBuf; 3648 if (i != cVars) 3649 { 3650 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3651 return VERR_TOO_MUCH_DATA; 3652 } 3653 return VINF_SUCCESS; 3654 } 3655 3656 3657 /** 3658 * @callback_method_impl{FNDBGCCMD, The 'eb'\, 'ew'\, 'ed' and 'eq' commands.} 3659 */ 3660 static DECLCALLBACK(int) dbgcCmdEditMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3661 { 3662 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3663 unsigned iArg; 3664 3665 /* 3666 * Validate input. 3667 */ 3668 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2); 3669 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 3670 for (iArg = 1; iArg < cArgs; iArg++) 3671 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER); 3672 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3673 3674 /* 3675 * Figure out the element size. 3676 */ 3677 unsigned cbElement; 3678 switch (pCmd->pszCmd[1]) 3679 { 3680 default: 3681 case 'b': cbElement = 1; break; 3682 case 'w': cbElement = 2; break; 3683 case 'd': cbElement = 4; break; 3684 case 'q': cbElement = 8; break; 3685 } 3686 3687 /* 3688 * Do setting. 3689 */ 3690 DBGCVAR Addr = paArgs[0]; 3691 for (iArg = 1;;) 3692 { 3693 size_t cbWritten; 3694 int rc = pCmdHlp->pfnMemWrite(pCmdHlp, &paArgs[iArg].u, cbElement, &Addr, &cbWritten); 3695 if (RT_FAILURE(rc)) 3696 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Writing memory at %DV.\n", &Addr); 3697 if (cbWritten != cbElement) 3698 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Only wrote %u out of %u bytes!\n", cbWritten, cbElement); 3699 3700 /* advance. */ 3701 iArg++; 3702 if (iArg >= cArgs) 3703 break; 3704 rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%Dv + %#x", &Addr, cbElement); 3705 if (RT_FAILURE(rc)) 3706 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3707 } 3708 3709 return VINF_SUCCESS; 3710 } 3711 3712 3713 /** 3714 * Executes the search. 3715 * 3716 * @returns VBox status code. 3717 * @param pCmdHlp The command helpers. 3718 * @param pUVM The user mode VM handle. 3719 * @param pAddress The address to start searching from. (undefined on output) 3720 * @param cbRange The address range to search. Must not wrap. 3721 * @param pabBytes The byte pattern to search for. 3722 * @param cbBytes The size of the pattern. 3723 * @param cbUnit The search unit. 3724 * @param cMaxHits The max number of hits. 3725 * @param pResult Where to store the result if it's a function invocation. 3726 */ 3727 static int dbgcCmdWorkerSearchMemDoIt(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR cbRange, 3728 const uint8_t *pabBytes, uint32_t cbBytes, 3729 uint32_t cbUnit, uint64_t cMaxHits, PDBGCVAR pResult) 3730 { 3731 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3732 3733 /* 3734 * Do the search. 3735 */ 3736 uint64_t cHits = 0; 3737 for (;;) 3738 { 3739 /* search */ 3740 DBGFADDRESS HitAddress; 3741 int rc = DBGFR3MemScan(pUVM, pDbgc->idCpu, pAddress, cbRange, 1, pabBytes, cbBytes, &HitAddress); 3742 if (RT_FAILURE(rc)) 3743 { 3744 if (rc != VERR_DBGF_MEM_NOT_FOUND) 3745 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3MemScan\n"); 3746 3747 /* update the current address so we can save it (later). */ 3748 pAddress->off += cbRange; 3749 pAddress->FlatPtr += cbRange; 3750 cbRange = 0; 3751 break; 3752 } 3753 3754 /* report result */ 3755 DBGCVAR VarCur; 3756 rc = DBGCCmdHlpVarFromDbgfAddr(pCmdHlp, &HitAddress, &VarCur); 3757 if (RT_FAILURE(rc)) 3758 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGCCmdHlpVarFromDbgfAddr\n"); 3759 if (!pResult) 3760 pCmdHlp->pfnExec(pCmdHlp, "db %DV LB 10", &VarCur); 3761 else 3762 DBGCVAR_ASSIGN(pResult, &VarCur); 3763 3764 /* advance */ 3765 cbRange -= HitAddress.FlatPtr - pAddress->FlatPtr; 3766 *pAddress = HitAddress; 3767 pAddress->FlatPtr += cbBytes; 3768 pAddress->off += cbBytes; 3769 if (cbRange <= cbBytes) 3770 { 3771 cbRange = 0; 3772 break; 3773 } 3774 cbRange -= cbBytes; 3775 3776 if (++cHits >= cMaxHits) 3777 { 3778 /// @todo save the search. 3779 break; 3780 } 3781 } 3782 3783 /* 3784 * Save the search so we can resume it... 3785 */ 3786 if (pDbgc->abSearch != pabBytes) 3787 { 3788 memcpy(pDbgc->abSearch, pabBytes, cbBytes); 3789 pDbgc->cbSearch = cbBytes; 3790 pDbgc->cbSearchUnit = cbUnit; 3791 } 3792 pDbgc->cMaxSearchHits = cMaxHits; 3793 pDbgc->SearchAddr = *pAddress; 3794 pDbgc->cbSearchRange = cbRange; 3795 3796 return cHits ? VINF_SUCCESS : VERR_DBGC_COMMAND_FAILED; 3797 } 3798 3799 3800 /** 3801 * Resumes the previous search. 3802 * 3803 * @returns VBox status code. 3804 * @param pCmdHlp Pointer to the command helper functions. 3805 * @param pUVM The user mode VM handle. 3806 * @param pResult Where to store the result of a function invocation. 3807 */ 3808 static int dbgcCmdWorkerSearchMemResume(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGCVAR pResult) 3809 { 3810 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3811 3812 /* 3813 * Make sure there is a previous command. 3814 */ 3815 if (!pDbgc->cbSearch) 3816 { 3817 DBGCCmdHlpPrintf(pCmdHlp, "Error: No previous search\n"); 3818 return VERR_DBGC_COMMAND_FAILED; 3819 } 3820 3821 /* 3822 * Make range and address adjustments. 3823 */ 3824 DBGFADDRESS Address = pDbgc->SearchAddr; 3825 if (Address.FlatPtr == ~(RTGCUINTPTR)0) 3826 { 3827 Address.FlatPtr -= Address.off; 3828 Address.off = 0; 3829 } 3830 3831 RTGCUINTPTR cbRange = pDbgc->cbSearchRange; 3832 if (!cbRange) 3833 cbRange = ~(RTGCUINTPTR)0; 3834 if (Address.FlatPtr + cbRange < pDbgc->SearchAddr.FlatPtr) 3835 cbRange = ~(RTGCUINTPTR)0 - pDbgc->SearchAddr.FlatPtr + !!pDbgc->SearchAddr.FlatPtr; 3836 3837 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, pDbgc->abSearch, pDbgc->cbSearch, 3838 pDbgc->cbSearchUnit, pDbgc->cMaxSearchHits, pResult); 3839 } 3840 3841 3842 /** 3843 * Search memory, worker for the 's' and 's?' functions. 3844 * 3845 * @returns VBox status code. 3846 * @param pCmdHlp Pointer to the command helper functions. 3847 * @param pUVM The user mode VM handle. 3848 * @param pAddress Where to start searching. If no range, search till end of address space. 3849 * @param cMaxHits The maximum number of hits. 3850 * @param chType The search type. 3851 * @param paPatArgs The pattern variable array. 3852 * @param cPatArgs Number of pattern variables. 3853 * @param pResult Where to store the result of a function invocation. 3854 */ 3855 static int dbgcCmdWorkerSearchMem(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR pAddress, uint64_t cMaxHits, char chType, 3856 PCDBGCVAR paPatArgs, unsigned cPatArgs, PDBGCVAR pResult) 3857 { 3858 if (pResult) 3859 DBGCVAR_INIT_GC_FLAT(pResult, 0); 3860 3861 /* 3862 * Convert the search pattern into bytes and DBGFR3MemScan can deal with. 3863 */ 3864 uint32_t cbUnit; 3865 switch (chType) 3866 { 3867 case 'a': 3868 case 'b': cbUnit = 1; break; 3869 case 'u': cbUnit = 2 | RT_BIT_32(31); break; 3870 case 'w': cbUnit = 2; break; 3871 case 'd': cbUnit = 4; break; 3872 case 'q': cbUnit = 8; break; 3873 default: 3874 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "chType=%c\n", chType); 3875 } 3876 uint8_t abBytes[RT_SIZEOFMEMB(DBGC, abSearch)]; 3877 uint32_t cbBytes = sizeof(abBytes); 3878 int rc = dbgcVarsToBytes(pCmdHlp, abBytes, &cbBytes, cbUnit, paPatArgs, cPatArgs); 3879 if (RT_FAILURE(rc)) 3880 return VERR_DBGC_COMMAND_FAILED; 3881 3882 /* 3883 * Make DBGF address and fix the range. 3884 */ 3885 DBGFADDRESS Address; 3886 rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pAddress, &Address); 3887 if (RT_FAILURE(rc)) 3888 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", pAddress); 3889 3890 RTGCUINTPTR cbRange; 3891 switch (pAddress->enmRangeType) 3892 { 3893 case DBGCVAR_RANGE_BYTES: 3894 cbRange = pAddress->u64Range; 3895 if (cbRange != pAddress->u64Range) 3896 cbRange = ~(RTGCUINTPTR)0; 3897 break; 3898 3899 case DBGCVAR_RANGE_ELEMENTS: 3900 cbRange = (RTGCUINTPTR)(pAddress->u64Range * cbUnit); 3901 if ( cbRange != pAddress->u64Range * cbUnit 3902 || cbRange < pAddress->u64Range) 3903 cbRange = ~(RTGCUINTPTR)0; 3904 break; 3905 3906 default: 3907 cbRange = ~(RTGCUINTPTR)0; 3908 break; 3909 } 3910 if (Address.FlatPtr + cbRange < Address.FlatPtr) 3911 cbRange = ~(RTGCUINTPTR)0 - Address.FlatPtr + !!Address.FlatPtr; 3912 3913 /* 3914 * Ok, do it. 3915 */ 3916 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, abBytes, cbBytes, cbUnit, cMaxHits, pResult); 3917 } 3918 3919 3920 /** 3921 * @callback_method_impl{FNDBGCCMD, The 's' command.} 3922 */ 3923 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3924 { 3925 /* check that the parser did what it's supposed to do. */ 3926 //if ( cArgs <= 2 3927 // && paArgs[0].enmType != DBGCVAR_TYPE_STRING) 3928 // return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n"); 3929 3930 /* 3931 * Repeat previous search? 3932 */ 3933 if (cArgs == 0) 3934 return dbgcCmdWorkerSearchMemResume(pCmdHlp, pUVM, NULL); 3935 3936 /* 3937 * Parse arguments. 3938 */ 3939 3940 return -1; 3941 } 3942 3943 3944 /** 3945 * @callback_method_impl{FNDBGCCMD, The 's?' command.} 3946 */ 3947 static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3948 { 3949 /* check that the parser did what it's supposed to do. */ 3950 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2 && DBGCVAR_ISGCPOINTER(paArgs[0].enmType)); 3951 return dbgcCmdWorkerSearchMem(pCmdHlp, pUVM, &paArgs[0], 25, pCmd->pszCmd[1], paArgs + 1, cArgs - 1, NULL); 3952 } 3953 3954 3955 typedef enum 3956 { 3957 kDbgcSxEventKind_Plain, 3958 kDbgcSxEventKind_Interrupt 3959 } DBGCSXEVENTKIND; 3960 static const struct 3961 { 3962 DBGFEVENTTYPE enmType; 3963 const char *pszName; 3964 DBGCSXEVENTKIND enmKind; 3965 bool fDefault; 3966 } g_aSxEvents[] = 3967 { 3968 { DBGFEVENT_INTERRUPT_HARDWARE, "hwint", kDbgcSxEventKind_Interrupt, false }, 3969 { DBGFEVENT_INTERRUPT_SOFTWARE, "swint", kDbgcSxEventKind_Interrupt, false }, 3970 { DBGFEVENT_TRIPLE_FAULT, "triplefault", kDbgcSxEventKind_Plain, true }, 3971 { DBGFEVENT_XCPT_DE, "de", kDbgcSxEventKind_Plain, false }, 3972 { DBGFEVENT_XCPT_DB, "db", kDbgcSxEventKind_Plain, false }, 3973 { DBGFEVENT_XCPT_02, "xcpt02", kDbgcSxEventKind_Plain, false }, 3974 { DBGFEVENT_XCPT_BP, "bp", kDbgcSxEventKind_Plain, false }, 3975 { DBGFEVENT_XCPT_OF, "of", kDbgcSxEventKind_Plain, false }, 3976 { DBGFEVENT_XCPT_BR, "br", kDbgcSxEventKind_Plain, false }, 3977 { DBGFEVENT_XCPT_UD, "ud", kDbgcSxEventKind_Plain, false }, 3978 { DBGFEVENT_XCPT_NM, "nm", kDbgcSxEventKind_Plain, false }, 3979 { DBGFEVENT_XCPT_DF, "df", kDbgcSxEventKind_Plain, false }, 3980 { DBGFEVENT_XCPT_09, "xcpt09", kDbgcSxEventKind_Plain, false }, 3981 { DBGFEVENT_XCPT_TS, "ts", kDbgcSxEventKind_Plain, false }, 3982 { DBGFEVENT_XCPT_NP, "np", kDbgcSxEventKind_Plain, false }, 3983 { DBGFEVENT_XCPT_SS, "ss", kDbgcSxEventKind_Plain, false }, 3984 { DBGFEVENT_XCPT_GP, "gp", kDbgcSxEventKind_Plain, false }, 3985 { DBGFEVENT_XCPT_PF, "pf", kDbgcSxEventKind_Plain, false }, 3986 { DBGFEVENT_XCPT_0f, "xcpt0f", kDbgcSxEventKind_Plain, false }, 3987 { DBGFEVENT_XCPT_MF, "mf", kDbgcSxEventKind_Plain, false }, 3988 { DBGFEVENT_XCPT_AC, "ac", kDbgcSxEventKind_Plain, false }, 3989 { DBGFEVENT_XCPT_MC, "mc", kDbgcSxEventKind_Plain, false }, 3990 { DBGFEVENT_XCPT_XF, "xf", kDbgcSxEventKind_Plain, false }, 3991 { DBGFEVENT_XCPT_VE, "ve", kDbgcSxEventKind_Plain, false }, 3992 { DBGFEVENT_XCPT_15, "xcpt15", kDbgcSxEventKind_Plain, false }, 3993 { DBGFEVENT_XCPT_16, "xcpt16", kDbgcSxEventKind_Plain, false }, 3994 { DBGFEVENT_XCPT_17, "xcpt17", kDbgcSxEventKind_Plain, false }, 3995 { DBGFEVENT_XCPT_18, "xcpt18", kDbgcSxEventKind_Plain, false }, 3996 { DBGFEVENT_XCPT_19, "xcpt19", kDbgcSxEventKind_Plain, false }, 3997 { DBGFEVENT_XCPT_1a, "xcpt1a", kDbgcSxEventKind_Plain, false }, 3998 { DBGFEVENT_XCPT_1b, "xcpt1b", kDbgcSxEventKind_Plain, false }, 3999 { DBGFEVENT_XCPT_1c, "xcpt1c", kDbgcSxEventKind_Plain, false }, 4000 { DBGFEVENT_XCPT_1d, "xcpt1d", kDbgcSxEventKind_Plain, false }, 4001 { DBGFEVENT_XCPT_SX, "sx", kDbgcSxEventKind_Plain, false }, 4002 { DBGFEVENT_XCPT_1f, "xcpt1f", kDbgcSxEventKind_Plain, false }, 4003 { DBGFEVENT_INSTR_HALT, "halt", kDbgcSxEventKind_Plain, false }, 405 * @remarks Sorted by DBGCSXEVT::enmType value. 406 */ 407 const DBGCSXEVT g_aDbgcSxEvents[] = 408 { 409 { DBGFEVENT_INTERRUPT_HARDWARE, "hwint", NULL, kDbgcSxEventKind_Interrupt, kDbgcEvtState_Disabled }, 410 { DBGFEVENT_INTERRUPT_SOFTWARE, "swint", NULL, kDbgcSxEventKind_Interrupt, kDbgcEvtState_Disabled }, 411 { DBGFEVENT_TRIPLE_FAULT, "triplefault", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Enabled }, 412 { DBGFEVENT_XCPT_DE, "xcpt_de", "de", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 413 { DBGFEVENT_XCPT_DB, "xcpt_db", "db", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 414 { DBGFEVENT_XCPT_02, "xcpt_02", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 415 { DBGFEVENT_XCPT_BP, "xcpt_bp", "bp", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 416 { DBGFEVENT_XCPT_OF, "xcpt_of", "of", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 417 { DBGFEVENT_XCPT_BR, "xcpt_br", "br", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 418 { DBGFEVENT_XCPT_UD, "xcpt_ud", "ud", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 419 { DBGFEVENT_XCPT_NM, "xcpt_nm", "nm", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 420 { DBGFEVENT_XCPT_DF, "xcpt_df", "df", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 421 { DBGFEVENT_XCPT_09, "xcpt_09", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 422 { DBGFEVENT_XCPT_TS, "xcpt_ts", "ts", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 423 { DBGFEVENT_XCPT_NP, "xcpt_np", "np", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 424 { DBGFEVENT_XCPT_SS, "xcpt_ss", "ss", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 425 { DBGFEVENT_XCPT_GP, "xcpt_gp", "gp", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 426 { DBGFEVENT_XCPT_PF, "xcpt_pf", "pf", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 427 { DBGFEVENT_XCPT_0f, "xcpt_0f", "xcpt0f", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 428 { DBGFEVENT_XCPT_MF, "xcpt_mf", "mf", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 429 { DBGFEVENT_XCPT_AC, "xcpt_ac", "ac", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 430 { DBGFEVENT_XCPT_MC, "xcpt_mc", "mc", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 431 { DBGFEVENT_XCPT_XF, "xcpt_xf", "xf", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 432 { DBGFEVENT_XCPT_VE, "xcpt_vd", "ve", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 433 { DBGFEVENT_XCPT_15, "xcpt_15", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 434 { DBGFEVENT_XCPT_16, "xcpt_16", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 435 { DBGFEVENT_XCPT_17, "xcpt_17", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 436 { DBGFEVENT_XCPT_18, "xcpt_18", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 437 { DBGFEVENT_XCPT_19, "xcpt_19", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 438 { DBGFEVENT_XCPT_1a, "xcpt_1a", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 439 { DBGFEVENT_XCPT_1b, "xcpt_1b", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 440 { DBGFEVENT_XCPT_1c, "xcpt_1c", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 441 { DBGFEVENT_XCPT_1d, "xcpt_1d", NULL, kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 442 { DBGFEVENT_XCPT_SX, "xcpt_sx", "sx", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 443 { DBGFEVENT_XCPT_1f, "xcpt_1f", "xcpt1f", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 444 { DBGFEVENT_INSTR_HALT, "instr_halt", "hlt", kDbgcSxEventKind_Plain, kDbgcEvtState_Disabled }, 4004 445 #if 0 /** @todo later */ 4005 446 { DBGFEVENT_INSTR_MWAIT, "", … … 4115 556 #endif 4116 557 }; 558 /** Number of entries in g_aDbgcSxEvents. */ 559 const uint32_t g_cDbgcSxEvents = RT_ELEMENTS(g_aDbgcSxEvents); 560 561 562 563 /** 564 * @callback_method_impl{FNDBGCCMD, The 'go' command.} 565 */ 566 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 567 { 568 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 569 570 /* 571 * Check if the VM is halted or not before trying to resume it. 572 */ 573 if (!DBGFR3IsHalted(pUVM)) 574 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The VM is already running"); 575 576 int rc = DBGFR3Resume(pUVM); 577 if (RT_FAILURE(rc)) 578 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3Resume"); 579 580 NOREF(paArgs); NOREF(cArgs); 581 return VINF_SUCCESS; 582 } 583 584 585 /** 586 * @callback_method_impl{FNDBGCCMD, The 'ba' command.} 587 */ 588 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 589 { 590 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 591 592 /* 593 * Interpret access type. 594 */ 595 if ( !strchr("xrwi", paArgs[0].u.pszString[0]) 596 || paArgs[0].u.pszString[1]) 597 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'", 598 paArgs[0].u.pszString, pCmd->pszCmd); 599 uint8_t fType = 0; 600 switch (paArgs[0].u.pszString[0]) 601 { 602 case 'x': fType = X86_DR7_RW_EO; break; 603 case 'r': fType = X86_DR7_RW_RW; break; 604 case 'w': fType = X86_DR7_RW_WO; break; 605 case 'i': fType = X86_DR7_RW_IO; break; 606 } 607 608 /* 609 * Validate size. 610 */ 611 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1) 612 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access size %RX64 for '%s'. 'x' access type requires size 1!", 613 paArgs[1].u.u64Number, pCmd->pszCmd); 614 switch (paArgs[1].u.u64Number) 615 { 616 case 1: 617 case 2: 618 case 4: 619 break; 620 /*case 8: - later*/ 621 default: 622 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid access size %RX64 for '%s'. 1, 2 or 4!", 623 paArgs[1].u.u64Number, pCmd->pszCmd); 624 } 625 uint8_t cb = (uint8_t)paArgs[1].u.u64Number; 626 627 /* 628 * Convert the pointer to a DBGF address. 629 */ 630 DBGFADDRESS Address; 631 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address); 632 if (RT_FAILURE(rc)) 633 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,%DV,)", &paArgs[2]); 634 635 /* 636 * Pick out the optional arguments. 637 */ 638 uint64_t iHitTrigger = 0; 639 uint64_t iHitDisable = ~0; 640 const char *pszCmds = NULL; 641 unsigned iArg = 3; 642 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 643 { 644 iHitTrigger = paArgs[iArg].u.u64Number; 645 iArg++; 646 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 647 { 648 iHitDisable = paArgs[iArg].u.u64Number; 649 iArg++; 650 } 651 } 652 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 653 { 654 pszCmds = paArgs[iArg].u.pszString; 655 iArg++; 656 } 657 658 /* 659 * Try set the breakpoint. 660 */ 661 uint32_t iBp; 662 rc = DBGFR3BpSetReg(pUVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp); 663 if (RT_SUCCESS(rc)) 664 { 665 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 666 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 667 if (RT_SUCCESS(rc)) 668 return DBGCCmdHlpPrintf(pCmdHlp, "Set access breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 669 if (rc == VERR_DBGC_BP_EXISTS) 670 { 671 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 672 if (RT_SUCCESS(rc)) 673 return DBGCCmdHlpPrintf(pCmdHlp, "Updated access breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 674 } 675 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 676 AssertRC(rc2); 677 } 678 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set access breakpoint at %RGv", Address.FlatPtr); 679 } 680 681 682 /** 683 * @callback_method_impl{FNDBGCCMD, The 'bc' command.} 684 */ 685 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 686 { 687 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 688 689 /* 690 * Enumerate the arguments. 691 */ 692 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 693 int rc = VINF_SUCCESS; 694 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 695 { 696 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 697 { 698 /* one */ 699 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 700 if (iBp == paArgs[iArg].u.u64Number) 701 { 702 int rc2 = DBGFR3BpClear(pUVM, iBp); 703 if (RT_FAILURE(rc2)) 704 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpClear(,%#x)", iBp); 705 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 706 dbgcBpDelete(pDbgc, iBp); 707 } 708 else 709 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 710 } 711 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 712 { 713 /* all */ 714 PDBGCBP pBp = pDbgc->pFirstBp; 715 while (pBp) 716 { 717 uint32_t iBp = pBp->iBp; 718 pBp = pBp->pNext; 719 720 int rc2 = DBGFR3BpClear(pUVM, iBp); 721 if (RT_FAILURE(rc2)) 722 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpClear(,%#x)", iBp); 723 if (RT_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND) 724 dbgcBpDelete(pDbgc, iBp); 725 } 726 } 727 else 728 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 729 } 730 return rc; 731 } 732 733 734 /** 735 * @callback_method_impl{FNDBGCCMD, The 'bd' command.} 736 */ 737 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 738 { 739 /* 740 * Enumerate the arguments. 741 */ 742 int rc = VINF_SUCCESS; 743 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 744 { 745 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 746 { 747 /* one */ 748 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 749 if (iBp == paArgs[iArg].u.u64Number) 750 { 751 rc = DBGFR3BpDisable(pUVM, iBp); 752 if (RT_FAILURE(rc)) 753 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpDisable failed for breakpoint %#x", iBp); 754 } 755 else 756 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 757 } 758 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 759 { 760 /* all */ 761 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 762 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 763 { 764 int rc2 = DBGFR3BpDisable(pUVM, pBp->iBp); 765 if (RT_FAILURE(rc2)) 766 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpDisable failed for breakpoint %#x", pBp->iBp); 767 } 768 } 769 else 770 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 771 } 772 return rc; 773 } 774 775 776 /** 777 * @callback_method_impl{FNDBGCCMD, The 'be' command.} 778 */ 779 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 780 { 781 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 782 783 /* 784 * Enumerate the arguments. 785 */ 786 int rc = VINF_SUCCESS; 787 for (unsigned iArg = 0; iArg < cArgs && RT_SUCCESS(rc); iArg++) 788 { 789 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 790 { 791 /* one */ 792 uint32_t iBp = (uint32_t)paArgs[iArg].u.u64Number; 793 if (iBp == paArgs[iArg].u.u64Number) 794 { 795 rc = DBGFR3BpEnable(pUVM, iBp); 796 if (RT_FAILURE(rc)) 797 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpEnable failed for breakpoint %#x", iBp); 798 } 799 else 800 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Breakpoint id %RX64 is too large", paArgs[iArg].u.u64Number); 801 } 802 else if (!strcmp(paArgs[iArg].u.pszString, "all")) 803 { 804 /* all */ 805 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 806 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext) 807 { 808 int rc2 = DBGFR3BpEnable(pUVM, pBp->iBp); 809 if (RT_FAILURE(rc2)) 810 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc2, "DBGFR3BpEnable failed for breakpoint %#x", pBp->iBp); 811 } 812 } 813 else 814 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Invalid argument '%s'", paArgs[iArg].u.pszString); 815 } 816 return rc; 817 } 818 819 820 /** 821 * Breakpoint enumeration callback function. 822 * 823 * @returns VBox status code. Any failure will stop the enumeration. 824 * @param pUVM The user mode VM handle. 825 * @param pvUser The user argument. 826 * @param pBp Pointer to the breakpoint information. (readonly) 827 */ 828 static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PUVM pUVM, void *pvUser, PCDBGFBP pBp) 829 { 830 PDBGC pDbgc = (PDBGC)pvUser; 831 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp); 832 833 /* 834 * BP type and size. 835 */ 836 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%#4x %c ", pBp->iBp, pBp->fEnabled ? 'e' : 'd'); 837 bool fHasAddress = false; 838 switch (pBp->enmType) 839 { 840 case DBGFBPTYPE_INT3: 841 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " p %RGv", pBp->u.Int3.GCPtr); 842 fHasAddress = true; 843 break; 844 case DBGFBPTYPE_REG: 845 { 846 char chType; 847 switch (pBp->u.Reg.fType) 848 { 849 case X86_DR7_RW_EO: chType = 'x'; break; 850 case X86_DR7_RW_WO: chType = 'w'; break; 851 case X86_DR7_RW_IO: chType = 'i'; break; 852 case X86_DR7_RW_RW: chType = 'r'; break; 853 default: chType = '?'; break; 854 855 } 856 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%d %c %RGv", pBp->u.Reg.cb, chType, pBp->u.Reg.GCPtr); 857 fHasAddress = true; 858 break; 859 } 860 861 case DBGFBPTYPE_REM: 862 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " r %RGv", pBp->u.Rem.GCPtr); 863 fHasAddress = true; 864 break; 865 866 /** @todo realign the list when I/O and MMIO breakpoint command have been added and it's possible to test this code. */ 867 case DBGFBPTYPE_PORT_IO: 868 case DBGFBPTYPE_MMIO: 869 { 870 uint32_t fAccess = pBp->enmType == DBGFBPTYPE_PORT_IO ? pBp->u.PortIo.fAccess : pBp->u.Mmio.fAccess; 871 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, pBp->enmType == DBGFBPTYPE_PORT_IO ? " i" : " m"); 872 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %c%c%c%c%c%c", 873 fAccess & DBGFBPIOACCESS_READ_MASK ? 'r' : '-', 874 fAccess & DBGFBPIOACCESS_READ_BYTE ? '1' : '-', 875 fAccess & DBGFBPIOACCESS_READ_WORD ? '2' : '-', 876 fAccess & DBGFBPIOACCESS_READ_DWORD ? '4' : '-', 877 fAccess & DBGFBPIOACCESS_READ_QWORD ? '8' : '-', 878 fAccess & DBGFBPIOACCESS_READ_OTHER ? '+' : '-'); 879 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %c%c%c%c%c%c", 880 fAccess & DBGFBPIOACCESS_WRITE_MASK ? 'w' : '-', 881 fAccess & DBGFBPIOACCESS_WRITE_BYTE ? '1' : '-', 882 fAccess & DBGFBPIOACCESS_WRITE_WORD ? '2' : '-', 883 fAccess & DBGFBPIOACCESS_WRITE_DWORD ? '4' : '-', 884 fAccess & DBGFBPIOACCESS_WRITE_QWORD ? '8' : '-', 885 fAccess & DBGFBPIOACCESS_WRITE_OTHER ? '+' : '-'); 886 if (pBp->enmType == DBGFBPTYPE_PORT_IO) 887 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04x-%04x", 888 pBp->u.PortIo.uPort, pBp->u.PortIo.uPort + pBp->u.PortIo.cPorts - 1); 889 else 890 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%RGp LB %03x", pBp->u.Mmio.PhysAddr, pBp->u.Mmio.cb); 891 break; 892 } 893 894 default: 895 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " unknown type %d!!", pBp->enmType); 896 AssertFailed(); 897 break; 898 899 } 900 if (pBp->iHitDisable == ~(uint64_t)0) 901 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04RX64 (%04RX64 to ~0) ", pBp->cHits, pBp->iHitTrigger); 902 else 903 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " %04RX64 (%04RX64 to %04RX64)", pBp->cHits, pBp->iHitTrigger, pBp->iHitDisable); 904 905 /* 906 * Try resolve the address if it has one. 907 */ 908 if (fHasAddress) 909 { 910 RTDBGSYMBOL Sym; 911 RTINTPTR off; 912 DBGFADDRESS Addr; 913 int rc = DBGFR3AsSymbolByAddr(pUVM, pDbgc->hDbgAs, DBGFR3AddrFromFlat(pDbgc->pUVM, &Addr, pBp->u.GCPtr), 914 RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &off, &Sym, NULL); 915 if (RT_SUCCESS(rc)) 916 { 917 if (!off) 918 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s", Sym.szName); 919 else if (off > 0) 920 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s+%RGv", Sym.szName, off); 921 else 922 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "%s-%RGv", Sym.szName, -off); 923 } 924 } 925 926 /* 927 * The commands. 928 */ 929 if (pDbgcBp) 930 { 931 if (pDbgcBp->cchCmd) 932 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "\n cmds: '%s'\n", pDbgcBp->szCmd); 933 else 934 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, "\n"); 935 } 936 else 937 DBGCCmdHlpPrintf(&pDbgc->CmdHlp, " [unknown bp]\n"); 938 939 return VINF_SUCCESS; 940 } 941 942 943 /** 944 * @callback_method_impl{FNDBGCCMD, The 'bl' command.} 945 */ 946 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 947 { 948 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 949 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, -1, cArgs == 0); 950 NOREF(paArgs); 951 952 /* 953 * Enumerate the breakpoints. 954 */ 955 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 956 int rc = DBGFR3BpEnum(pUVM, dbgcEnumBreakpointsCallback, pDbgc); 957 if (RT_FAILURE(rc)) 958 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3BpEnum"); 959 return rc; 960 } 961 962 963 /** 964 * @callback_method_impl{FNDBGCCMD, The 'bp' command.} 965 */ 966 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 967 { 968 /* 969 * Convert the pointer to a DBGF address. 970 */ 971 DBGFADDRESS Address; 972 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 973 if (RT_FAILURE(rc)) 974 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,'%DV',)", &paArgs[0]); 975 976 /* 977 * Pick out the optional arguments. 978 */ 979 uint64_t iHitTrigger = 0; 980 uint64_t iHitDisable = ~0; 981 const char *pszCmds = NULL; 982 unsigned iArg = 1; 983 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 984 { 985 iHitTrigger = paArgs[iArg].u.u64Number; 986 iArg++; 987 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 988 { 989 iHitDisable = paArgs[iArg].u.u64Number; 990 iArg++; 991 } 992 } 993 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 994 { 995 pszCmds = paArgs[iArg].u.pszString; 996 iArg++; 997 } 998 999 /* 1000 * Try set the breakpoint. 1001 */ 1002 uint32_t iBp; 1003 rc = DBGFR3BpSet(pUVM, &Address, iHitTrigger, iHitDisable, &iBp); 1004 if (RT_SUCCESS(rc)) 1005 { 1006 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1007 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 1008 if (RT_SUCCESS(rc)) 1009 return DBGCCmdHlpPrintf(pCmdHlp, "Set breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 1010 if (rc == VERR_DBGC_BP_EXISTS) 1011 { 1012 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 1013 if (RT_SUCCESS(rc)) 1014 return DBGCCmdHlpPrintf(pCmdHlp, "Updated breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 1015 } 1016 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 1017 AssertRC(rc2); 1018 } 1019 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set breakpoint at %RGv", Address.FlatPtr); 1020 } 1021 1022 1023 /** 1024 * @callback_method_impl{FNDBGCCMD, The 'br' command.} 1025 */ 1026 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1027 { 1028 /* 1029 * Convert the pointer to a DBGF address. 1030 */ 1031 DBGFADDRESS Address; 1032 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address); 1033 if (RT_FAILURE(rc)) 1034 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,'%DV',)", &paArgs[0]); 1035 1036 /* 1037 * Pick out the optional arguments. 1038 */ 1039 uint64_t iHitTrigger = 0; 1040 uint64_t iHitDisable = ~0; 1041 const char *pszCmds = NULL; 1042 unsigned iArg = 1; 1043 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1044 { 1045 iHitTrigger = paArgs[iArg].u.u64Number; 1046 iArg++; 1047 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1048 { 1049 iHitDisable = paArgs[iArg].u.u64Number; 1050 iArg++; 1051 } 1052 } 1053 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING) 1054 { 1055 pszCmds = paArgs[iArg].u.pszString; 1056 iArg++; 1057 } 1058 1059 /* 1060 * Try set the breakpoint. 1061 */ 1062 uint32_t iBp; 1063 rc = DBGFR3BpSetREM(pUVM, &Address, iHitTrigger, iHitDisable, &iBp); 1064 if (RT_SUCCESS(rc)) 1065 { 1066 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1067 rc = dbgcBpAdd(pDbgc, iBp, pszCmds); 1068 if (RT_SUCCESS(rc)) 1069 return DBGCCmdHlpPrintf(pCmdHlp, "Set REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 1070 if (rc == VERR_DBGC_BP_EXISTS) 1071 { 1072 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds); 1073 if (RT_SUCCESS(rc)) 1074 return DBGCCmdHlpPrintf(pCmdHlp, "Updated REM breakpoint %u at %RGv\n", iBp, Address.FlatPtr); 1075 } 1076 int rc2 = DBGFR3BpClear(pDbgc->pUVM, iBp); 1077 AssertRC(rc2); 1078 } 1079 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Failed to set REM breakpoint at %RGv", Address.FlatPtr); 1080 } 1081 1082 1083 /** 1084 * Helps the unassmble ('u') command display symbols it starts at and passes. 1085 * 1086 * @param pUVM The user mode VM handle. 1087 * @param pCmdHlp The command helpers for printing via. 1088 * @param hDbgAs The address space to look up addresses in. 1089 * @param pAddress The current address. 1090 * @param pcbCallAgain Where to return the distance to the next check (in 1091 * instruction bytes). 1092 */ 1093 static void dbgcCmdUnassambleHelpListNear(PUVM pUVM, PDBGCCMDHLP pCmdHlp, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, 1094 PRTUINTPTR pcbCallAgain) 1095 { 1096 RTDBGSYMBOL Symbol; 1097 RTGCINTPTR offDispSym; 1098 int rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, RTDBGSYMADDR_FLAGS_LESS_OR_EQUAL, &offDispSym, &Symbol, NULL); 1099 if (RT_FAILURE(rc) || offDispSym > _1G) 1100 rc = DBGFR3AsSymbolByAddr(pUVM, hDbgAs, pAddress, RTDBGSYMADDR_FLAGS_GREATER_OR_EQUAL, &offDispSym, &Symbol, NULL); 1101 if (RT_SUCCESS(rc) && offDispSym < _1G) 1102 { 1103 if (!offDispSym) 1104 { 1105 DBGCCmdHlpPrintf(pCmdHlp, "%s:\n", Symbol.szName); 1106 *pcbCallAgain = !Symbol.cb ? 64 : Symbol.cb; 1107 } 1108 else if (offDispSym > 0) 1109 { 1110 DBGCCmdHlpPrintf(pCmdHlp, "%s+%#llx:\n", Symbol.szName, (uint64_t)offDispSym); 1111 *pcbCallAgain = !Symbol.cb ? 64 : Symbol.cb > (RTGCUINTPTR)offDispSym ? Symbol.cb - (RTGCUINTPTR)offDispSym : 1; 1112 } 1113 else 1114 { 1115 DBGCCmdHlpPrintf(pCmdHlp, "%s-%#llx:\n", Symbol.szName, (uint64_t)-offDispSym); 1116 *pcbCallAgain = !Symbol.cb ? 64 : (RTGCUINTPTR)-offDispSym + Symbol.cb; 1117 } 1118 } 1119 else 1120 *pcbCallAgain = UINT32_MAX; 1121 } 1122 1123 1124 /** 1125 * @callback_method_impl{FNDBGCCMD, The 'u' command.} 1126 */ 1127 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1128 { 1129 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1130 1131 /* 1132 * Validate input. 1133 */ 1134 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 1135 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, -1, cArgs <= 1); 1136 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 0 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 1137 1138 if (!cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 1139 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Don't know where to start disassembling"); 1140 1141 /* 1142 * Check the desired mode. 1143 */ 1144 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS | DBGF_DISAS_FLAGS_UNPATCHED_BYTES | DBGF_DISAS_FLAGS_ANNOTATE_PATCHED; 1145 switch (pCmd->pszCmd[1]) 1146 { 1147 default: AssertFailed(); 1148 case '\0': fFlags |= DBGF_DISAS_FLAGS_DEFAULT_MODE; break; 1149 case '6': fFlags |= DBGF_DISAS_FLAGS_64BIT_MODE; break; 1150 case '3': fFlags |= DBGF_DISAS_FLAGS_32BIT_MODE; break; 1151 case '1': fFlags |= DBGF_DISAS_FLAGS_16BIT_MODE; break; 1152 case 'v': fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE; break; 1153 } 1154 1155 /** @todo should use DBGFADDRESS for everything */ 1156 1157 /* 1158 * Find address. 1159 */ 1160 if (!cArgs) 1161 { 1162 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType)) 1163 { 1164 /** @todo Batch query CS, RIP, CPU mode and flags. */ 1165 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 1166 if ( pDbgc->fRegCtxGuest 1167 && CPUMIsGuestIn64BitCode(pVCpu)) 1168 { 1169 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FLAT; 1170 pDbgc->SourcePos.u.GCFlat = CPUMGetGuestRIP(pVCpu); 1171 } 1172 else 1173 { 1174 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR; 1175 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu); 1176 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu); 1177 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE 1178 && pDbgc->fRegCtxGuest 1179 && (CPUMGetGuestEFlags(pVCpu) & X86_EFL_VM)) 1180 { 1181 fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK; 1182 fFlags |= DBGF_DISAS_FLAGS_16BIT_REAL_MODE; 1183 } 1184 } 1185 1186 if (pDbgc->fRegCtxGuest) 1187 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST; 1188 else 1189 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER | DBGF_DISAS_FLAGS_HYPER; 1190 } 1191 else if ((fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_DEFAULT_MODE && pDbgc->fDisasm) 1192 { 1193 fFlags &= ~DBGF_DISAS_FLAGS_MODE_MASK; 1194 fFlags |= pDbgc->fDisasm & (DBGF_DISAS_FLAGS_MODE_MASK | DBGF_DISAS_FLAGS_HYPER); 1195 } 1196 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE; 1197 } 1198 else 1199 pDbgc->DisasmPos = paArgs[0]; 1200 pDbgc->pLastPos = &pDbgc->DisasmPos; 1201 1202 /* 1203 * Range. 1204 */ 1205 switch (pDbgc->DisasmPos.enmRangeType) 1206 { 1207 case DBGCVAR_RANGE_NONE: 1208 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 1209 pDbgc->DisasmPos.u64Range = 10; 1210 break; 1211 1212 case DBGCVAR_RANGE_ELEMENTS: 1213 if (pDbgc->DisasmPos.u64Range > 2048) 1214 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Too many lines requested. Max is 2048 lines"); 1215 break; 1216 1217 case DBGCVAR_RANGE_BYTES: 1218 if (pDbgc->DisasmPos.u64Range > 65536) 1219 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The requested range is too big. Max is 64KB"); 1220 break; 1221 1222 default: 1223 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Unknown range type %d", pDbgc->DisasmPos.enmRangeType); 1224 } 1225 1226 /* 1227 * Convert physical and host addresses to guest addresses. 1228 */ 1229 RTDBGAS hDbgAs = pDbgc->hDbgAs; 1230 int rc; 1231 switch (pDbgc->DisasmPos.enmType) 1232 { 1233 case DBGCVAR_TYPE_GC_FLAT: 1234 case DBGCVAR_TYPE_GC_FAR: 1235 break; 1236 case DBGCVAR_TYPE_GC_PHYS: 1237 hDbgAs = DBGF_AS_PHYS; 1238 case DBGCVAR_TYPE_HC_FLAT: 1239 case DBGCVAR_TYPE_HC_PHYS: 1240 { 1241 DBGCVAR VarTmp; 1242 rc = DBGCCmdHlpEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos); 1243 if (RT_FAILURE(rc)) 1244 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "failed to evaluate '%%(%Dv)'", &pDbgc->DisasmPos); 1245 pDbgc->DisasmPos = VarTmp; 1246 break; 1247 } 1248 default: AssertFailed(); break; 1249 } 1250 1251 DBGFADDRESS CurAddr; 1252 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE 1253 && pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FAR) 1254 DBGFR3AddrFromFlat(pUVM, &CurAddr, ((uint32_t)pDbgc->DisasmPos.u.GCFar.sel << 4) + pDbgc->DisasmPos.u.GCFar.off); 1255 else 1256 { 1257 rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->DisasmPos, &CurAddr); 1258 if (RT_FAILURE(rc)) 1259 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr failed on '%Dv'", &pDbgc->DisasmPos); 1260 } 1261 1262 if (CurAddr.fFlags & DBGFADDRESS_FLAGS_HMA) 1263 fFlags |= DBGF_DISAS_FLAGS_HYPER; /* This crap is due to not using DBGFADDRESS as DBGFR3Disas* input. */ 1264 pDbgc->fDisasm = fFlags; 1265 1266 /* 1267 * Figure out where we are and display it. Also calculate when we need to 1268 * check for a new symbol if possible. 1269 */ 1270 RTGCUINTPTR cbCheckSymbol; 1271 dbgcCmdUnassambleHelpListNear(pUVM, pCmdHlp, hDbgAs, &CurAddr, &cbCheckSymbol); 1272 1273 /* 1274 * Do the disassembling. 1275 */ 1276 unsigned cTries = 32; 1277 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range; 1278 if (iRangeLeft == 0) /* kludge for 'r'. */ 1279 iRangeLeft = -1; 1280 for (;;) 1281 { 1282 /* 1283 * Disassemble the instruction. 1284 */ 1285 char szDis[256]; 1286 uint32_t cbInstr = 1; 1287 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT) 1288 rc = DBGFR3DisasInstrEx(pUVM, pDbgc->idCpu, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, 1289 &szDis[0], sizeof(szDis), &cbInstr); 1290 else 1291 rc = DBGFR3DisasInstrEx(pUVM, pDbgc->idCpu, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, 1292 &szDis[0], sizeof(szDis), &cbInstr); 1293 if (RT_SUCCESS(rc)) 1294 { 1295 /* print it */ 1296 rc = DBGCCmdHlpPrintf(pCmdHlp, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]); 1297 if (RT_FAILURE(rc)) 1298 return rc; 1299 } 1300 else 1301 { 1302 /* bitch. */ 1303 int rc2 = DBGCCmdHlpPrintf(pCmdHlp, "Failed to disassemble instruction, skipping one byte.\n"); 1304 if (RT_FAILURE(rc2)) 1305 return rc2; 1306 if (cTries-- > 0) 1307 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "Too many disassembly failures. Giving up"); 1308 cbInstr = 1; 1309 } 1310 1311 /* advance */ 1312 if (iRangeLeft < 0) /* 'r' */ 1313 break; 1314 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS) 1315 iRangeLeft--; 1316 else 1317 iRangeLeft -= cbInstr; 1318 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr); 1319 if (RT_FAILURE(rc)) 1320 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpEval(,,'(%Dv) + %x')", &pDbgc->DisasmPos, cbInstr); 1321 if (iRangeLeft <= 0) 1322 break; 1323 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER); 1324 1325 /* Print next symbol? */ 1326 if (cbCheckSymbol <= cbInstr) 1327 { 1328 if ( (fFlags & DBGF_DISAS_FLAGS_MODE_MASK) == DBGF_DISAS_FLAGS_16BIT_REAL_MODE 1329 && pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FAR) 1330 DBGFR3AddrFromFlat(pUVM, &CurAddr, ((uint32_t)pDbgc->DisasmPos.u.GCFar.sel << 4) + pDbgc->DisasmPos.u.GCFar.off); 1331 else 1332 rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->DisasmPos, &CurAddr); 1333 if (RT_SUCCESS(rc)) 1334 dbgcCmdUnassambleHelpListNear(pUVM, pCmdHlp, hDbgAs, &CurAddr, &cbCheckSymbol); 1335 else 1336 cbCheckSymbol = UINT32_MAX; 1337 } 1338 else 1339 cbCheckSymbol -= cbInstr; 1340 } 1341 1342 NOREF(pCmd); 1343 return VINF_SUCCESS; 1344 } 1345 1346 1347 /** 1348 * @callback_method_impl{FNDBGCCMD, The 'ls' command.} 1349 */ 1350 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1351 { 1352 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1353 1354 /* 1355 * Validate input. 1356 */ 1357 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 1358 if (cArgs == 1) 1359 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 1360 if (!pUVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType)) 1361 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Don't know where to start listing..."); 1362 if (!pUVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType)) 1363 return DBGCCmdHlpFail(pCmdHlp, pCmd, "GC address but no VM"); 1364 1365 /* 1366 * Find address. 1367 */ 1368 if (!cArgs) 1369 { 1370 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType)) 1371 { 1372 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 1373 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR; 1374 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVCpu) : CPUMGetHyperEIP(pVCpu); 1375 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVCpu) : CPUMGetHyperCS(pVCpu); 1376 } 1377 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE; 1378 } 1379 else 1380 pDbgc->SourcePos = paArgs[0]; 1381 pDbgc->pLastPos = &pDbgc->SourcePos; 1382 1383 /* 1384 * Ensure the source address is flat GC. 1385 */ 1386 switch (pDbgc->SourcePos.enmType) 1387 { 1388 case DBGCVAR_TYPE_GC_FLAT: 1389 break; 1390 case DBGCVAR_TYPE_GC_PHYS: 1391 case DBGCVAR_TYPE_GC_FAR: 1392 case DBGCVAR_TYPE_HC_FLAT: 1393 case DBGCVAR_TYPE_HC_PHYS: 1394 { 1395 int rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos); 1396 if (RT_FAILURE(rc)) 1397 return DBGCCmdHlpPrintf(pCmdHlp, "error: Invalid address or address type. (rc=%d)\n", rc); 1398 break; 1399 } 1400 default: AssertFailed(); break; 1401 } 1402 1403 /* 1404 * Range. 1405 */ 1406 switch (pDbgc->SourcePos.enmRangeType) 1407 { 1408 case DBGCVAR_RANGE_NONE: 1409 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 1410 pDbgc->SourcePos.u64Range = 10; 1411 break; 1412 1413 case DBGCVAR_RANGE_ELEMENTS: 1414 if (pDbgc->SourcePos.u64Range > 2048) 1415 return DBGCCmdHlpPrintf(pCmdHlp, "error: Too many lines requested. Max is 2048 lines.\n"); 1416 break; 1417 1418 case DBGCVAR_RANGE_BYTES: 1419 if (pDbgc->SourcePos.u64Range > 65536) 1420 return DBGCCmdHlpPrintf(pCmdHlp, "error: The requested range is too big. Max is 64KB.\n"); 1421 break; 1422 1423 default: 1424 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType); 1425 } 1426 1427 /* 1428 * Do the disassembling. 1429 */ 1430 bool fFirst = 1; 1431 RTDBGLINE LinePrev = { 0, 0, 0, 0, 0, "" }; 1432 int iRangeLeft = (int)pDbgc->SourcePos.u64Range; 1433 if (iRangeLeft == 0) /* kludge for 'r'. */ 1434 iRangeLeft = -1; 1435 for (;;) 1436 { 1437 /* 1438 * Get line info. 1439 */ 1440 RTDBGLINE Line; 1441 RTGCINTPTR off; 1442 DBGFADDRESS SourcePosAddr; 1443 int rc = DBGCCmdHlpVarToDbgfAddr(pCmdHlp, &pDbgc->SourcePos, &SourcePosAddr); 1444 if (RT_FAILURE(rc)) 1445 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGCCmdHlpVarToDbgfAddr(,%Dv)", &pDbgc->SourcePos); 1446 rc = DBGFR3AsLineByAddr(pUVM, pDbgc->hDbgAs, &SourcePosAddr, &off, &Line, NULL); 1447 if (RT_FAILURE(rc)) 1448 return VINF_SUCCESS; 1449 1450 unsigned cLines = 0; 1451 if (memcmp(&Line, &LinePrev, sizeof(Line))) 1452 { 1453 /* 1454 * Print filenamename 1455 */ 1456 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename)) 1457 fFirst = true; 1458 if (fFirst) 1459 { 1460 rc = DBGCCmdHlpPrintf(pCmdHlp, "[%s @ %d]\n", Line.szFilename, Line.uLineNo); 1461 if (RT_FAILURE(rc)) 1462 return rc; 1463 } 1464 1465 /* 1466 * Try open the file and read the line. 1467 */ 1468 FILE *phFile = fopen(Line.szFilename, "r"); 1469 if (phFile) 1470 { 1471 /* Skip ahead to the desired line. */ 1472 char szLine[4096]; 1473 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1; 1474 if (cBefore > 7) 1475 cBefore = 0; 1476 unsigned cLeft = Line.uLineNo - cBefore; 1477 while (cLeft > 0) 1478 { 1479 szLine[0] = '\0'; 1480 if (!fgets(szLine, sizeof(szLine), phFile)) 1481 break; 1482 cLeft--; 1483 } 1484 if (!cLeft) 1485 { 1486 /* print the before lines */ 1487 for (;;) 1488 { 1489 size_t cch = strlen(szLine); 1490 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || RT_C_IS_SPACE(szLine[cch - 1])) ) 1491 szLine[--cch] = '\0'; 1492 if (cBefore-- <= 0) 1493 break; 1494 1495 rc = DBGCCmdHlpPrintf(pCmdHlp, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine); 1496 szLine[0] = '\0'; 1497 (void)fgets(szLine, sizeof(szLine), phFile); 1498 cLines++; 1499 } 1500 /* print the actual line */ 1501 rc = DBGCCmdHlpPrintf(pCmdHlp, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine); 1502 } 1503 fclose(phFile); 1504 if (RT_FAILURE(rc)) 1505 return rc; 1506 fFirst = false; 1507 } 1508 else 1509 return DBGCCmdHlpPrintf(pCmdHlp, "Warning: couldn't open source file '%s'\n", Line.szFilename); 1510 1511 LinePrev = Line; 1512 } 1513 1514 1515 /* 1516 * Advance 1517 */ 1518 if (iRangeLeft < 0) /* 'r' */ 1519 break; 1520 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS) 1521 iRangeLeft -= cLines; 1522 else 1523 iRangeLeft -= 1; 1524 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1); 1525 if (RT_FAILURE(rc)) 1526 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1); 1527 if (iRangeLeft <= 0) 1528 break; 1529 } 1530 1531 NOREF(pCmd); 1532 return 0; 1533 } 1534 1535 1536 /** 1537 * @callback_method_impl{FNDBGCCMD, The 'r' command.} 1538 */ 1539 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1540 { 1541 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1542 if (!pDbgc->fRegCtxGuest) 1543 return dbgcCmdRegHyper(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 1544 return dbgcCmdRegGuest(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 1545 } 1546 1547 1548 /** 1549 * @callback_method_impl{FNDBGCCMD, Common worker for the dbgcCmdReg*() 1550 * commands.} 1551 */ 1552 static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs, 1553 const char *pszPrefix) 1554 { 1555 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1556 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1 || cArgs == 2 || cArgs == 3); 1557 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_STRING 1558 || paArgs[0].enmType == DBGCVAR_TYPE_SYMBOL); 1559 1560 /* 1561 * Parse the register name and kind. 1562 */ 1563 const char *pszReg = paArgs[0].u.pszString; 1564 if (*pszReg == '@') 1565 pszReg++; 1566 VMCPUID idCpu = pDbgc->idCpu; 1567 if (*pszPrefix) 1568 idCpu |= DBGFREG_HYPER_VMCPUID; 1569 if (*pszReg == '.') 1570 { 1571 pszReg++; 1572 idCpu |= DBGFREG_HYPER_VMCPUID; 1573 } 1574 const char * const pszActualPrefix = idCpu & DBGFREG_HYPER_VMCPUID ? "." : ""; 1575 1576 /* 1577 * Query the register type & value (the setter needs the type). 1578 */ 1579 DBGFREGVALTYPE enmType; 1580 DBGFREGVAL Value; 1581 int rc = DBGFR3RegNmQuery(pUVM, idCpu, pszReg, &Value, &enmType); 1582 if (RT_FAILURE(rc)) 1583 { 1584 if (rc == VERR_DBGF_REGISTER_NOT_FOUND) 1585 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown register: '%s%s'.\n", 1586 pszActualPrefix, pszReg); 1587 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegNmQuery failed querying '%s%s': %Rrc.\n", 1588 pszActualPrefix, pszReg, rc); 1589 } 1590 if (cArgs == 1) 1591 { 1592 /* 1593 * Show the register. 1594 */ 1595 char szValue[160]; 1596 rc = DBGFR3RegFormatValue(szValue, sizeof(szValue), &Value, enmType, true /*fSpecial*/); 1597 if (RT_SUCCESS(rc)) 1598 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s%s=%s\n", pszActualPrefix, pszReg, szValue); 1599 else 1600 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegFormatValue failed: %Rrc.\n", rc); 1601 } 1602 else 1603 { 1604 DBGCVAR NewValueTmp; 1605 PCDBGCVAR pNewValue; 1606 if (cArgs == 3) 1607 { 1608 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 1, paArgs[1].enmType == DBGCVAR_TYPE_STRING); 1609 if (strcmp(paArgs[1].u.pszString, "=")) 1610 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Second argument must be '='."); 1611 pNewValue = &paArgs[2]; 1612 } 1613 else 1614 { 1615 /* Not possible to convince the parser to support both codeview and 1616 windbg syntax and make the equal sign optional. Try help it. */ 1617 /** @todo make DBGCCmdHlpConvert do more with strings. */ 1618 rc = DBGCCmdHlpConvert(pCmdHlp, &paArgs[1], DBGCVAR_TYPE_NUMBER, true /*fConvSyms*/, &NewValueTmp); 1619 if (RT_FAILURE(rc)) 1620 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "The last argument must be a value or valid symbol."); 1621 pNewValue = &NewValueTmp; 1622 } 1623 1624 /* 1625 * Modify the register. 1626 */ 1627 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 1, pNewValue->enmType == DBGCVAR_TYPE_NUMBER); 1628 if (enmType != DBGFREGVALTYPE_DTR) 1629 { 1630 enmType = DBGFREGVALTYPE_U64; 1631 rc = DBGCCmdHlpVarToNumber(pCmdHlp, pNewValue, &Value.u64); 1632 } 1633 else 1634 { 1635 enmType = DBGFREGVALTYPE_DTR; 1636 rc = DBGCCmdHlpVarToNumber(pCmdHlp, pNewValue, &Value.dtr.u64Base); 1637 if (RT_SUCCESS(rc) && pNewValue->enmRangeType != DBGCVAR_RANGE_NONE) 1638 Value.dtr.u32Limit = (uint32_t)pNewValue->u64Range; 1639 } 1640 if (RT_SUCCESS(rc)) 1641 { 1642 rc = DBGFR3RegNmSet(pUVM, idCpu, pszReg, &Value, enmType); 1643 if (RT_FAILURE(rc)) 1644 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegNmSet failed settings '%s%s': %Rrc\n", 1645 pszActualPrefix, pszReg, rc); 1646 if (rc != VINF_SUCCESS) 1647 DBGCCmdHlpPrintf(pCmdHlp, "%s: warning: %Rrc\n", pCmd->pszCmd, rc); 1648 } 1649 else 1650 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegFormatValue failed: %Rrc.\n", rc); 1651 } 1652 return rc; 1653 } 1654 1655 1656 /** 1657 * @callback_method_impl{FNDBGCCMD, 1658 * The 'rg'\, 'rg64' and 'rg32' commands\, worker for 'r'.} 1659 */ 1660 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1661 { 1662 /* 1663 * Show all registers our selves. 1664 */ 1665 if (cArgs == 0) 1666 { 1667 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1668 bool const f64BitMode = !strcmp(pCmd->pszCmd, "rg64") 1669 || ( strcmp(pCmd->pszCmd, "rg32") != 0 1670 && DBGFR3CpuIsIn64BitCode(pUVM, pDbgc->idCpu)); 1671 char szDisAndRegs[8192]; 1672 int rc; 1673 1674 if (pDbgc->fRegTerse) 1675 { 1676 if (f64BitMode) 1677 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs), 1678 "u %016VR{rip} L 0\n" 1679 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n" 1680 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n" 1681 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n" 1682 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n" 1683 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n" 1684 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss} rflags=%08VR{rflags}\n"); 1685 else 1686 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs), 1687 "u %04VR{cs}:%08VR{eip} L 0\n" 1688 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n" 1689 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n" 1690 "cs=%04VR{cs} ds=%04VR{ds} es=%04VR{es} fs=%04VR{fs} gs=%04VR{gs} ss=%04VR{ss} eflags=%08VR{eflags}\n"); 1691 } 1692 else 1693 { 1694 if (f64BitMode) 1695 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, &szDisAndRegs[0], sizeof(szDisAndRegs), 1696 "u %016VR{rip} L 0\n" 1697 "rax=%016VR{rax} rbx=%016VR{rbx} rcx=%016VR{rcx} rdx=%016VR{rdx}\n" 1698 "rsi=%016VR{rsi} rdi=%016VR{rdi} r8 =%016VR{r8} r9 =%016VR{r9}\n" 1699 "r10=%016VR{r10} r11=%016VR{r11} r12=%016VR{r12} r13=%016VR{r13}\n" 1700 "r14=%016VR{r14} r15=%016VR{r15} %VRF{rflags}\n" 1701 "rip=%016VR{rip} rsp=%016VR{rsp} rbp=%016VR{rbp}\n" 1702 "cs={%04VR{cs} base=%016VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} cr0=%016VR{cr0}\n" 1703 "ds={%04VR{ds} base=%016VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} cr2=%016VR{cr2}\n" 1704 "es={%04VR{es} base=%016VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} cr3=%016VR{cr3}\n" 1705 "fs={%04VR{fs} base=%016VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr4=%016VR{cr4}\n" 1706 "gs={%04VR{gs} base=%016VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr8=%016VR{cr8}\n" 1707 "ss={%04VR{ss} base=%016VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n" 1708 "dr0=%016VR{dr0} dr1=%016VR{dr1} dr2=%016VR{dr2} dr3=%016VR{dr3}\n" 1709 "dr6=%016VR{dr6} dr7=%016VR{dr7}\n" 1710 "gdtr=%016VR{gdtr_base}:%04VR{gdtr_lim} idtr=%016VR{idtr_base}:%04VR{idtr_lim} rflags=%08VR{rflags}\n" 1711 "ldtr={%04VR{ldtr} base=%016VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%08VR{ldtr_attr}}\n" 1712 "tr ={%04VR{tr} base=%016VR{tr_base} limit=%08VR{tr_lim} flags=%08VR{tr_attr}}\n" 1713 " sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n" 1714 " efer=%016VR{efer}\n" 1715 " pat=%016VR{pat}\n" 1716 " sf_mask=%016VR{sf_mask}\n" 1717 "krnl_gs_base=%016VR{krnl_gs_base}\n" 1718 " lstar=%016VR{lstar}\n" 1719 " star=%016VR{star} cstar=%016VR{cstar}\n" 1720 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n" 1721 ); 1722 else 1723 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu, szDisAndRegs, sizeof(szDisAndRegs), 1724 "u %04VR{cs}:%08VR{eip} L 0\n" 1725 "eax=%08VR{eax} ebx=%08VR{ebx} ecx=%08VR{ecx} edx=%08VR{edx} esi=%08VR{esi} edi=%08VR{edi}\n" 1726 "eip=%08VR{eip} esp=%08VR{esp} ebp=%08VR{ebp} %VRF{eflags}\n" 1727 "cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} dr0=%08VR{dr0} dr1=%08VR{dr1}\n" 1728 "ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} dr2=%08VR{dr2} dr3=%08VR{dr3}\n" 1729 "es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} dr6=%08VR{dr6} dr7=%08VR{dr7}\n" 1730 "fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} cr0=%08VR{cr0} cr2=%08VR{cr2}\n" 1731 "gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}} cr3=%08VR{cr3} cr4=%08VR{cr4}\n" 1732 "ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}} cr8=%08VR{cr8}\n" 1733 "gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim} idtr=%08VR{idtr_base}:%04VR{idtr_lim} eflags=%08VR{eflags}\n" 1734 "ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n" 1735 "tr ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n" 1736 "sysenter={cs=%04VR{sysenter_cs} eip=%08VR{sysenter_eip} esp=%08VR{sysenter_esp}}\n" 1737 "fcw=%04VR{fcw} fsw=%04VR{fsw} ftw=%04VR{ftw} mxcsr=%04VR{mxcsr} mxcsr_mask=%04VR{mxcsr_mask}\n" 1738 ); 1739 } 1740 if (RT_FAILURE(rc)) 1741 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed"); 1742 char *pszRegs = strchr(szDisAndRegs, '\n'); 1743 *pszRegs++ = '\0'; 1744 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs); 1745 1746 /* 1747 * Disassemble one instruction at cs:[r|e]ip. 1748 */ 1749 if (!f64BitMode && strstr(pszRegs, " vm ")) /* a big ugly... */ 1750 return pCmdHlp->pfnExec(pCmdHlp, "uv86 %s", szDisAndRegs + 2); 1751 return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs); 1752 } 1753 return dbgcCmdRegCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, ""); 1754 } 1755 1756 1757 /** 1758 * @callback_method_impl{FNDBGCCMD, The 'rh' command.} 1759 */ 1760 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1761 { 1762 /* 1763 * Show all registers our selves. 1764 */ 1765 if (cArgs == 0) 1766 { 1767 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1768 char szDisAndRegs[8192]; 1769 int rc; 1770 1771 if (pDbgc->fRegTerse) 1772 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu | DBGFREG_HYPER_VMCPUID, szDisAndRegs, sizeof(szDisAndRegs), 1773 "u %VR{cs}:%VR{eip} L 0\n" 1774 ".eax=%08VR{eax} .ebx=%08VR{ebx} .ecx=%08VR{ecx} .edx=%08VR{edx} .esi=%08VR{esi} .edi=%08VR{edi}\n" 1775 ".eip=%08VR{eip} .esp=%08VR{esp} .ebp=%08VR{ebp} .%VRF{eflags}\n" 1776 ".cs=%04VR{cs} .ds=%04VR{ds} .es=%04VR{es} .fs=%04VR{fs} .gs=%04VR{gs} .ss=%04VR{ss} .eflags=%08VR{eflags}\n"); 1777 else 1778 rc = DBGFR3RegPrintf(pUVM, pDbgc->idCpu | DBGFREG_HYPER_VMCPUID, szDisAndRegs, sizeof(szDisAndRegs), 1779 "u %04VR{cs}:%08VR{eip} L 0\n" 1780 ".eax=%08VR{eax} .ebx=%08VR{ebx} .ecx=%08VR{ecx} .edx=%08VR{edx} .esi=%08VR{esi} .edi=%08VR{edi}\n" 1781 ".eip=%08VR{eip} .esp=%08VR{esp} .ebp=%08VR{ebp} .%VRF{eflags}\n" 1782 ".cs={%04VR{cs} base=%08VR{cs_base} limit=%08VR{cs_lim} flags=%04VR{cs_attr}} .dr0=%08VR{dr0} .dr1=%08VR{dr1}\n" 1783 ".ds={%04VR{ds} base=%08VR{ds_base} limit=%08VR{ds_lim} flags=%04VR{ds_attr}} .dr2=%08VR{dr2} .dr3=%08VR{dr3}\n" 1784 ".es={%04VR{es} base=%08VR{es_base} limit=%08VR{es_lim} flags=%04VR{es_attr}} .dr6=%08VR{dr6} .dr6=%08VR{dr6}\n" 1785 ".fs={%04VR{fs} base=%08VR{fs_base} limit=%08VR{fs_lim} flags=%04VR{fs_attr}} .cr3=%016VR{cr3}\n" 1786 ".gs={%04VR{gs} base=%08VR{gs_base} limit=%08VR{gs_lim} flags=%04VR{gs_attr}}\n" 1787 ".ss={%04VR{ss} base=%08VR{ss_base} limit=%08VR{ss_lim} flags=%04VR{ss_attr}}\n" 1788 ".gdtr=%08VR{gdtr_base}:%04VR{gdtr_lim} .idtr=%08VR{idtr_base}:%04VR{idtr_lim} .eflags=%08VR{eflags}\n" 1789 ".ldtr={%04VR{ldtr} base=%08VR{ldtr_base} limit=%08VR{ldtr_lim} flags=%04VR{ldtr_attr}}\n" 1790 ".tr ={%04VR{tr} base=%08VR{tr_base} limit=%08VR{tr_lim} flags=%04VR{tr_attr}}\n" 1791 ); 1792 if (RT_FAILURE(rc)) 1793 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3RegPrintf failed"); 1794 char *pszRegs = strchr(szDisAndRegs, '\n'); 1795 *pszRegs++ = '\0'; 1796 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s", pszRegs); 1797 1798 /* 1799 * Disassemble one instruction at cs:[r|e]ip. 1800 */ 1801 return pCmdHlp->pfnExec(pCmdHlp, "%s", szDisAndRegs); 1802 } 1803 return dbgcCmdRegCommon(pCmd, pCmdHlp, pUVM, paArgs, cArgs, "."); 1804 } 1805 1806 1807 /** 1808 * @callback_method_impl{FNDBGCCMD, The 'rt' command.} 1809 */ 1810 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1811 { 1812 NOREF(pCmd); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs); 1813 1814 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1815 pDbgc->fRegTerse = !pDbgc->fRegTerse; 1816 return DBGCCmdHlpPrintf(pCmdHlp, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n"); 1817 } 1818 1819 1820 /** 1821 * @callback_method_impl{FNDBGCCMD, The 't' command.} 1822 */ 1823 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1824 { 1825 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1826 1827 int rc = DBGFR3Step(pUVM, pDbgc->idCpu); 1828 if (RT_SUCCESS(rc)) 1829 pDbgc->fReady = false; 1830 else 1831 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM); 1832 1833 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); 1834 return rc; 1835 } 1836 1837 1838 /** 1839 * @callback_method_impl{FNDBGCCMD, The 'k'\, 'kg' and 'kh' commands.} 1840 */ 1841 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 1842 { 1843 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1844 1845 /* 1846 * Figure which context we're called for and start walking that stack. 1847 */ 1848 int rc; 1849 PCDBGFSTACKFRAME pFirstFrame; 1850 bool const fGuest = pCmd->pszCmd[1] == 'g' 1851 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest); 1852 rc = DBGFR3StackWalkBegin(pUVM, pDbgc->idCpu, fGuest ? DBGFCODETYPE_GUEST : DBGFCODETYPE_HYPER, &pFirstFrame); 1853 if (RT_FAILURE(rc)) 1854 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to begin stack walk, rc=%Rrc\n", rc); 1855 1856 /* 1857 * Print header. 1858 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol 1859 */ 1860 uint32_t fBitFlags = 0; 1861 for (PCDBGFSTACKFRAME pFrame = pFirstFrame; 1862 pFrame; 1863 pFrame = DBGFR3StackWalkNext(pFrame)) 1864 { 1865 uint32_t const fCurBitFlags = pFrame->fFlags & (DBGFSTACKFRAME_FLAGS_16BIT | DBGFSTACKFRAME_FLAGS_32BIT | DBGFSTACKFRAME_FLAGS_64BIT); 1866 if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_16BIT) 1867 { 1868 if (fCurBitFlags != fBitFlags) 1869 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "SS:BP Ret SS:BP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n"); 1870 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04RX16:%04RX16 %04RX16:%04RX16 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32", 1871 pFrame->AddrFrame.Sel, 1872 (uint16_t)pFrame->AddrFrame.off, 1873 pFrame->AddrReturnFrame.Sel, 1874 (uint16_t)pFrame->AddrReturnFrame.off, 1875 (uint32_t)pFrame->AddrReturnPC.Sel, 1876 (uint32_t)pFrame->AddrReturnPC.off, 1877 pFrame->Args.au32[0], 1878 pFrame->Args.au32[1], 1879 pFrame->Args.au32[2], 1880 pFrame->Args.au32[3]); 1881 } 1882 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT) 1883 { 1884 if (fCurBitFlags != fBitFlags) 1885 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n"); 1886 rc = DBGCCmdHlpPrintf(pCmdHlp, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32", 1887 (uint32_t)pFrame->AddrFrame.off, 1888 (uint32_t)pFrame->AddrReturnFrame.off, 1889 (uint32_t)pFrame->AddrReturnPC.Sel, 1890 (uint32_t)pFrame->AddrReturnPC.off, 1891 pFrame->Args.au32[0], 1892 pFrame->Args.au32[1], 1893 pFrame->Args.au32[2], 1894 pFrame->Args.au32[3]); 1895 } 1896 else if (fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT) 1897 { 1898 if (fCurBitFlags != fBitFlags) 1899 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "RBP Ret SS:RBP Ret RIP CS:RIP / Symbol [line]\n"); 1900 rc = DBGCCmdHlpPrintf(pCmdHlp, "%016RX64 %04RX16:%016RX64 %016RX64", 1901 (uint64_t)pFrame->AddrFrame.off, 1902 pFrame->AddrReturnFrame.Sel, 1903 (uint64_t)pFrame->AddrReturnFrame.off, 1904 (uint64_t)pFrame->AddrReturnPC.off); 1905 } 1906 if (RT_FAILURE(rc)) 1907 break; 1908 if (!pFrame->pSymPC) 1909 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1910 fCurBitFlags & DBGFSTACKFRAME_FLAGS_64BIT 1911 ? " %RTsel:%016RGv" 1912 : fCurBitFlags & DBGFSTACKFRAME_FLAGS_32BIT 1913 ? " %RTsel:%08RGv" 1914 : " %RTsel:%04RGv" 1915 , pFrame->AddrPC.Sel, pFrame->AddrPC.off); 1916 else 1917 { 1918 RTGCINTPTR offDisp = pFrame->AddrPC.FlatPtr - pFrame->pSymPC->Value; /** @todo this isn't 100% correct for segmented stuff. */ 1919 if (offDisp > 0) 1920 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s+%llx", pFrame->pSymPC->szName, (int64_t)offDisp); 1921 else if (offDisp < 0) 1922 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s-%llx", pFrame->pSymPC->szName, -(int64_t)offDisp); 1923 else 1924 rc = DBGCCmdHlpPrintf(pCmdHlp, " %s", pFrame->pSymPC->szName); 1925 } 1926 if (RT_SUCCESS(rc) && pFrame->pLinePC) 1927 rc = DBGCCmdHlpPrintf(pCmdHlp, " [%s @ 0i%d]", pFrame->pLinePC->szFilename, pFrame->pLinePC->uLineNo); 1928 if (RT_SUCCESS(rc)) 1929 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 1930 if (RT_FAILURE(rc)) 1931 break; 1932 1933 fBitFlags = fCurBitFlags; 1934 } 1935 1936 DBGFR3StackWalkEnd(pFirstFrame); 1937 1938 NOREF(paArgs); NOREF(cArgs); 1939 return rc; 1940 } 1941 1942 1943 static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP pCmdHlp, PCX86DESC64 pDesc, unsigned iEntry, bool fHyper, bool *pfDblEntry) 1944 { 1945 /* GUEST64 */ 1946 int rc; 1947 1948 const char *pszHyper = fHyper ? " HYPER" : ""; 1949 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP"; 1950 if (pDesc->Gen.u1DescType) 1951 { 1952 static const char * const s_apszTypes[] = 1953 { 1954 "DataRO", /* 0 Read-Only */ 1955 "DataRO", /* 1 Read-Only - Accessed */ 1956 "DataRW", /* 2 Read/Write */ 1957 "DataRW", /* 3 Read/Write - Accessed */ 1958 "DownRO", /* 4 Expand-down, Read-Only */ 1959 "DownRO", /* 5 Expand-down, Read-Only - Accessed */ 1960 "DownRW", /* 6 Expand-down, Read/Write */ 1961 "DownRW", /* 7 Expand-down, Read/Write - Accessed */ 1962 "CodeEO", /* 8 Execute-Only */ 1963 "CodeEO", /* 9 Execute-Only - Accessed */ 1964 "CodeER", /* A Execute/Readable */ 1965 "CodeER", /* B Execute/Readable - Accessed */ 1966 "ConfE0", /* C Conforming, Execute-Only */ 1967 "ConfE0", /* D Conforming, Execute-Only - Accessed */ 1968 "ConfER", /* E Conforming, Execute/Readable */ 1969 "ConfER" /* F Conforming, Execute/Readable - Accessed */ 1970 }; 1971 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA"; 1972 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 1973 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 1974 uint32_t u32Base = X86DESC_BASE(pDesc); 1975 uint32_t cbLimit = X86DESC_LIMIT_G(pDesc); 1976 1977 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n", 1978 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 1979 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig, 1980 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper); 1981 } 1982 else 1983 { 1984 static const char * const s_apszTypes[] = 1985 { 1986 "Ill-0 ", /* 0 0000 Reserved (Illegal) */ 1987 "Ill-1 ", /* 1 0001 Available 16-bit TSS */ 1988 "LDT ", /* 2 0010 LDT */ 1989 "Ill-3 ", /* 3 0011 Busy 16-bit TSS */ 1990 "Ill-4 ", /* 4 0100 16-bit Call Gate */ 1991 "Ill-5 ", /* 5 0101 Task Gate */ 1992 "Ill-6 ", /* 6 0110 16-bit Interrupt Gate */ 1993 "Ill-7 ", /* 7 0111 16-bit Trap Gate */ 1994 "Ill-8 ", /* 8 1000 Reserved (Illegal) */ 1995 "Tss64A", /* 9 1001 Available 32-bit TSS */ 1996 "Ill-A ", /* A 1010 Reserved (Illegal) */ 1997 "Tss64B", /* B 1011 Busy 32-bit TSS */ 1998 "Call64", /* C 1100 32-bit Call Gate */ 1999 "Ill-D ", /* D 1101 Reserved (Illegal) */ 2000 "Int64 ", /* E 1110 32-bit Interrupt Gate */ 2001 "Trap64" /* F 1111 32-bit Trap Gate */ 2002 }; 2003 switch (pDesc->Gen.u4Type) 2004 { 2005 /* raw */ 2006 case X86_SEL_TYPE_SYS_UNDEFINED: 2007 case X86_SEL_TYPE_SYS_UNDEFINED2: 2008 case X86_SEL_TYPE_SYS_UNDEFINED4: 2009 case X86_SEL_TYPE_SYS_UNDEFINED3: 2010 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 2011 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 2012 case X86_SEL_TYPE_SYS_286_CALL_GATE: 2013 case X86_SEL_TYPE_SYS_286_INT_GATE: 2014 case X86_SEL_TYPE_SYS_286_TRAP_GATE: 2015 case X86_SEL_TYPE_SYS_TASK_GATE: 2016 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s %.8Rhxs DPL=%d %s%s\n", 2017 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc, 2018 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2019 break; 2020 2021 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 2022 case X86_SEL_TYPE_SYS_386_TSS_BUSY: 2023 case X86_SEL_TYPE_SYS_LDT: 2024 { 2025 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB"; 2026 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 2027 const char *pszLong = pDesc->Gen.u1Long ? "LONG" : " "; 2028 2029 uint64_t u64Base = X86DESC64_BASE(pDesc); 2030 uint32_t cbLimit = X86DESC_LIMIT_G(pDesc); 2031 2032 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%016RX64 Lim=%08x DPL=%d %s %s %s %sAVL=%d R=%d%s\n", 2033 iEntry, s_apszTypes[pDesc->Gen.u4Type], u64Base, cbLimit, 2034 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszLong, pszBig, 2035 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1), 2036 pszHyper); 2037 if (pfDblEntry) 2038 *pfDblEntry = true; 2039 break; 2040 } 2041 2042 case X86_SEL_TYPE_SYS_386_CALL_GATE: 2043 { 2044 unsigned cParams = pDesc->au8[4] & 0x1f; 2045 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC"; 2046 RTSEL sel = pDesc->au16[1]; 2047 uint64_t off = pDesc->au16[0] 2048 | ((uint64_t)pDesc->au16[3] << 16) 2049 | ((uint64_t)pDesc->Gen.u32BaseHigh3 << 32); 2050 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%016RX64 DPL=%d %s %s=%d%s\n", 2051 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 2052 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper); 2053 if (pfDblEntry) 2054 *pfDblEntry = true; 2055 break; 2056 } 2057 2058 case X86_SEL_TYPE_SYS_386_INT_GATE: 2059 case X86_SEL_TYPE_SYS_386_TRAP_GATE: 2060 { 2061 RTSEL sel = pDesc->Gate.u16Sel; 2062 uint64_t off = pDesc->Gate.u16OffsetLow 2063 | ((uint64_t)pDesc->Gate.u16OffsetHigh << 16) 2064 | ((uint64_t)pDesc->Gate.u32OffsetTop << 32); 2065 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%016RX64 DPL=%u %s IST=%u%s\n", 2066 iEntry, s_apszTypes[pDesc->Gate.u4Type], sel, off, 2067 pDesc->Gate.u2Dpl, pszPresent, pDesc->Gate.u3IST, pszHyper); 2068 if (pfDblEntry) 2069 *pfDblEntry = true; 2070 break; 2071 } 2072 2073 /* impossible, just it's necessary to keep gcc happy. */ 2074 default: 2075 return VINF_SUCCESS; 2076 } 2077 } 2078 return VINF_SUCCESS; 2079 } 2080 2081 2082 /** 2083 * Worker function that displays one descriptor entry (GDT, LDT, IDT). 2084 * 2085 * @returns pfnPrintf status code. 2086 * @param pCmdHlp The DBGC command helpers. 2087 * @param pDesc The descriptor to display. 2088 * @param iEntry The descriptor entry number. 2089 * @param fHyper Whether the selector belongs to the hypervisor or not. 2090 */ 2091 static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper) 2092 { 2093 int rc; 2094 2095 const char *pszHyper = fHyper ? " HYPER" : ""; 2096 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP"; 2097 if (pDesc->Gen.u1DescType) 2098 { 2099 static const char * const s_apszTypes[] = 2100 { 2101 "DataRO", /* 0 Read-Only */ 2102 "DataRO", /* 1 Read-Only - Accessed */ 2103 "DataRW", /* 2 Read/Write */ 2104 "DataRW", /* 3 Read/Write - Accessed */ 2105 "DownRO", /* 4 Expand-down, Read-Only */ 2106 "DownRO", /* 5 Expand-down, Read-Only - Accessed */ 2107 "DownRW", /* 6 Expand-down, Read/Write */ 2108 "DownRW", /* 7 Expand-down, Read/Write - Accessed */ 2109 "CodeEO", /* 8 Execute-Only */ 2110 "CodeEO", /* 9 Execute-Only - Accessed */ 2111 "CodeER", /* A Execute/Readable */ 2112 "CodeER", /* B Execute/Readable - Accessed */ 2113 "ConfE0", /* C Conforming, Execute-Only */ 2114 "ConfE0", /* D Conforming, Execute-Only - Accessed */ 2115 "ConfER", /* E Conforming, Execute/Readable */ 2116 "ConfER" /* F Conforming, Execute/Readable - Accessed */ 2117 }; 2118 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA"; 2119 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 2120 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 2121 uint32_t u32Base = pDesc->Gen.u16BaseLow 2122 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16) 2123 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24); 2124 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16); 2125 if (pDesc->Gen.u1Granularity) 2126 cbLimit <<= PAGE_SHIFT; 2127 2128 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d L=%d%s\n", 2129 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 2130 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig, 2131 pDesc->Gen.u1Available, pDesc->Gen.u1Long, pszHyper); 2132 } 2133 else 2134 { 2135 static const char * const s_apszTypes[] = 2136 { 2137 "Ill-0 ", /* 0 0000 Reserved (Illegal) */ 2138 "Tss16A", /* 1 0001 Available 16-bit TSS */ 2139 "LDT ", /* 2 0010 LDT */ 2140 "Tss16B", /* 3 0011 Busy 16-bit TSS */ 2141 "Call16", /* 4 0100 16-bit Call Gate */ 2142 "TaskG ", /* 5 0101 Task Gate */ 2143 "Int16 ", /* 6 0110 16-bit Interrupt Gate */ 2144 "Trap16", /* 7 0111 16-bit Trap Gate */ 2145 "Ill-8 ", /* 8 1000 Reserved (Illegal) */ 2146 "Tss32A", /* 9 1001 Available 32-bit TSS */ 2147 "Ill-A ", /* A 1010 Reserved (Illegal) */ 2148 "Tss32B", /* B 1011 Busy 32-bit TSS */ 2149 "Call32", /* C 1100 32-bit Call Gate */ 2150 "Ill-D ", /* D 1101 Reserved (Illegal) */ 2151 "Int32 ", /* E 1110 32-bit Interrupt Gate */ 2152 "Trap32" /* F 1111 32-bit Trap Gate */ 2153 }; 2154 switch (pDesc->Gen.u4Type) 2155 { 2156 /* raw */ 2157 case X86_SEL_TYPE_SYS_UNDEFINED: 2158 case X86_SEL_TYPE_SYS_UNDEFINED2: 2159 case X86_SEL_TYPE_SYS_UNDEFINED4: 2160 case X86_SEL_TYPE_SYS_UNDEFINED3: 2161 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s %.8Rhxs DPL=%d %s%s\n", 2162 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc, 2163 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2164 break; 2165 2166 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 2167 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 2168 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 2169 case X86_SEL_TYPE_SYS_386_TSS_BUSY: 2170 case X86_SEL_TYPE_SYS_LDT: 2171 { 2172 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " "; 2173 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB"; 2174 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " "; 2175 uint32_t u32Base = pDesc->Gen.u16BaseLow 2176 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16) 2177 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24); 2178 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16); 2179 if (pDesc->Gen.u1Granularity) 2180 cbLimit <<= PAGE_SHIFT; 2181 2182 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n", 2183 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit, 2184 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig, 2185 pDesc->Gen.u1Available, pDesc->Gen.u1Long | (pDesc->Gen.u1DefBig << 1), 2186 pszHyper); 2187 break; 2188 } 2189 2190 case X86_SEL_TYPE_SYS_TASK_GATE: 2191 { 2192 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s TSS=%04x DPL=%d %s%s\n", 2193 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1], 2194 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2195 break; 2196 } 2197 2198 case X86_SEL_TYPE_SYS_286_CALL_GATE: 2199 case X86_SEL_TYPE_SYS_386_CALL_GATE: 2200 { 2201 unsigned cParams = pDesc->au8[4] & 0x1f; 2202 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC"; 2203 RTSEL sel = pDesc->au16[1]; 2204 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16); 2205 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n", 2206 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 2207 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper); 2208 break; 2209 } 2210 2211 case X86_SEL_TYPE_SYS_286_INT_GATE: 2212 case X86_SEL_TYPE_SYS_386_INT_GATE: 2213 case X86_SEL_TYPE_SYS_286_TRAP_GATE: 2214 case X86_SEL_TYPE_SYS_386_TRAP_GATE: 2215 { 2216 RTSEL sel = pDesc->au16[1]; 2217 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16); 2218 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n", 2219 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off, 2220 pDesc->Gen.u2Dpl, pszPresent, pszHyper); 2221 break; 2222 } 2223 2224 /* impossible, just it's necessary to keep gcc happy. */ 2225 default: 2226 return VINF_SUCCESS; 2227 } 2228 } 2229 return rc; 2230 } 2231 2232 2233 /** 2234 * @callback_method_impl{FNDBGCCMD, The 'dg'\, 'dga'\, 'dl' and 'dla' commands.} 2235 */ 2236 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2237 { 2238 /* 2239 * Validate input. 2240 */ 2241 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2242 2243 /* 2244 * Get the CPU mode, check which command variation this is 2245 * and fix a default parameter if needed. 2246 */ 2247 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2248 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 2249 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu); 2250 bool fGdt = pCmd->pszCmd[1] == 'g'; 2251 bool fAll = pCmd->pszCmd[2] == 'a'; 2252 RTSEL SelTable = fGdt ? 0 : X86_SEL_LDT; 2253 2254 DBGCVAR Var; 2255 if (!cArgs) 2256 { 2257 cArgs = 1; 2258 paArgs = &Var; 2259 Var.enmType = DBGCVAR_TYPE_NUMBER; 2260 Var.u.u64Number = 0; 2261 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 2262 Var.u64Range = 1024; 2263 } 2264 2265 /* 2266 * Process the arguments. 2267 */ 2268 for (unsigned i = 0; i < cArgs; i++) 2269 { 2270 /* 2271 * Retrieve the selector value from the argument. 2272 * The parser may confuse pointers and numbers if more than one 2273 * argument is given, that that into account. 2274 */ 2275 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, i, paArgs[i].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[i].enmType)); 2276 uint64_t u64; 2277 unsigned cSels = 1; 2278 switch (paArgs[i].enmType) 2279 { 2280 case DBGCVAR_TYPE_NUMBER: 2281 u64 = paArgs[i].u.u64Number; 2282 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE) 2283 cSels = RT_MIN(paArgs[i].u64Range, 1024); 2284 break; 2285 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break; 2286 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break; 2287 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break; 2288 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break; 2289 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break; 2290 default: u64 = _64K; break; 2291 } 2292 if (u64 < _64K) 2293 { 2294 unsigned Sel = (RTSEL)u64; 2295 2296 /* 2297 * Dump the specified range. 2298 */ 2299 bool fSingle = cSels == 1; 2300 while ( cSels-- > 0 2301 && Sel < _64K) 2302 { 2303 DBGFSELINFO SelInfo; 2304 int rc = DBGFR3SelQueryInfo(pUVM, pDbgc->idCpu, Sel | SelTable, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo); 2305 if (RT_SUCCESS(rc)) 2306 { 2307 if (SelInfo.fFlags & DBGFSELINFO_FLAGS_REAL_MODE) 2308 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x RealM Bas=%04x Lim=%04x\n", 2309 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit); 2310 else if ( fAll 2311 || fSingle 2312 || SelInfo.u.Raw.Gen.u1Present) 2313 { 2314 if (enmMode == CPUMMODE_PROTECTED) 2315 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &SelInfo.u.Raw, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER)); 2316 else 2317 { 2318 bool fDblSkip = false; 2319 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &SelInfo.u.Raw64, Sel, !!(SelInfo.fFlags & DBGFSELINFO_FLAGS_HYPER), &fDblSkip); 2320 if (fDblSkip) 2321 Sel += 4; 2322 } 2323 } 2324 } 2325 else 2326 { 2327 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %Rrc\n", Sel, rc); 2328 if (!fAll) 2329 return rc; 2330 } 2331 if (RT_FAILURE(rc)) 2332 return rc; 2333 2334 /* next */ 2335 Sel += 8; 2336 } 2337 } 2338 else 2339 DBGCCmdHlpPrintf(pCmdHlp, "error: %llx is out of bounds\n", u64); 2340 } 2341 2342 return VINF_SUCCESS; 2343 } 2344 2345 2346 /** 2347 * @callback_method_impl{FNDBGCCMD, The 'di' and 'dia' commands.} 2348 */ 2349 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2350 { 2351 /* 2352 * Validate input. 2353 */ 2354 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2355 2356 /* 2357 * Establish some stuff like the current IDTR and CPU mode, 2358 * and fix a default parameter. 2359 */ 2360 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2361 PVMCPU pVCpu = VMMR3GetCpuByIdU(pUVM, pDbgc->idCpu); 2362 uint16_t cbLimit; 2363 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVCpu, &cbLimit); 2364 CPUMMODE enmMode = CPUMGetGuestMode(pVCpu); 2365 unsigned cbEntry; 2366 switch (enmMode) 2367 { 2368 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break; 2369 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break; 2370 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break; 2371 default: 2372 return DBGCCmdHlpPrintf(pCmdHlp, "error: Invalid CPU mode %d.\n", enmMode); 2373 } 2374 2375 bool fAll = pCmd->pszCmd[2] == 'a'; 2376 DBGCVAR Var; 2377 if (!cArgs) 2378 { 2379 cArgs = 1; 2380 paArgs = &Var; 2381 Var.enmType = DBGCVAR_TYPE_NUMBER; 2382 Var.u.u64Number = 0; 2383 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS; 2384 Var.u64Range = 256; 2385 } 2386 2387 /* 2388 * Process the arguments. 2389 */ 2390 for (unsigned i = 0; i < cArgs; i++) 2391 { 2392 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, i, paArgs[i].enmType == DBGCVAR_TYPE_NUMBER); 2393 if (paArgs[i].u.u64Number < 256) 2394 { 2395 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number; 2396 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE 2397 ? paArgs[i].u64Range 2398 : 1; 2399 bool fSingle = cInts == 1; 2400 while ( cInts-- > 0 2401 && iInt < 256) 2402 { 2403 /* 2404 * Try read it. 2405 */ 2406 union 2407 { 2408 RTFAR16 Real; 2409 X86DESC Prot; 2410 X86DESC64 Long; 2411 } u; 2412 if (iInt * cbEntry + (cbEntry - 1) > cbLimit) 2413 { 2414 DBGCCmdHlpPrintf(pCmdHlp, "%04x not within the IDT\n", (unsigned)iInt); 2415 if (!fAll && !fSingle) 2416 return VINF_SUCCESS; 2417 } 2418 DBGCVAR AddrVar; 2419 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT; 2420 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry; 2421 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE; 2422 int rc = pCmdHlp->pfnMemRead(pCmdHlp, &u, cbEntry, &AddrVar, NULL); 2423 if (RT_FAILURE(rc)) 2424 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt); 2425 2426 /* 2427 * Display it. 2428 */ 2429 switch (enmMode) 2430 { 2431 case CPUMMODE_REAL: 2432 rc = DBGCCmdHlpPrintf(pCmdHlp, "%04x %RTfp16\n", (unsigned)iInt, u.Real); 2433 /** @todo resolve 16:16 IDTE to a symbol */ 2434 break; 2435 case CPUMMODE_PROTECTED: 2436 if (fAll || fSingle || u.Prot.Gen.u1Present) 2437 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false); 2438 break; 2439 case CPUMMODE_LONG: 2440 if (fAll || fSingle || u.Long.Gen.u1Present) 2441 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL); 2442 break; 2443 default: break; /* to shut up gcc */ 2444 } 2445 if (RT_FAILURE(rc)) 2446 return rc; 2447 2448 /* next */ 2449 iInt++; 2450 } 2451 } 2452 else 2453 DBGCCmdHlpPrintf(pCmdHlp, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number); 2454 } 2455 2456 return VINF_SUCCESS; 2457 } 2458 2459 2460 /** 2461 * @callback_method_impl{FNDBGCCMD, 2462 * The 'da'\, 'dq'\, 'dd'\, 'dw' and 'db' commands.} 2463 */ 2464 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2465 { 2466 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2467 2468 /* 2469 * Validate input. 2470 */ 2471 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 2472 if (cArgs == 1) 2473 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2474 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2475 2476 /* 2477 * Figure out the element size. 2478 */ 2479 unsigned cbElement; 2480 bool fAscii = false; 2481 switch (pCmd->pszCmd[1]) 2482 { 2483 default: 2484 case 'b': cbElement = 1; break; 2485 case 'w': cbElement = 2; break; 2486 case 'd': cbElement = 4; break; 2487 case 'q': cbElement = 8; break; 2488 case 'a': 2489 cbElement = 1; 2490 fAscii = true; 2491 break; 2492 case '\0': 2493 fAscii = !!(pDbgc->cbDumpElement & 0x80000000); 2494 cbElement = pDbgc->cbDumpElement & 0x7fffffff; 2495 if (!cbElement) 2496 cbElement = 1; 2497 break; 2498 } 2499 2500 /* 2501 * Find address. 2502 */ 2503 if (!cArgs) 2504 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE; 2505 else 2506 pDbgc->DumpPos = paArgs[0]; 2507 2508 /* 2509 * Range. 2510 */ 2511 switch (pDbgc->DumpPos.enmRangeType) 2512 { 2513 case DBGCVAR_RANGE_NONE: 2514 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES; 2515 pDbgc->DumpPos.u64Range = 0x60; 2516 break; 2517 2518 case DBGCVAR_RANGE_ELEMENTS: 2519 if (pDbgc->DumpPos.u64Range > 2048) 2520 return DBGCCmdHlpPrintf(pCmdHlp, "error: Too many elements requested. Max is 2048 elements.\n"); 2521 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES; 2522 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range; 2523 break; 2524 2525 case DBGCVAR_RANGE_BYTES: 2526 if (pDbgc->DumpPos.u64Range > 65536) 2527 return DBGCCmdHlpPrintf(pCmdHlp, "error: The requested range is too big. Max is 64KB.\n"); 2528 break; 2529 2530 default: 2531 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType); 2532 } 2533 2534 pDbgc->pLastPos = &pDbgc->DumpPos; 2535 2536 /* 2537 * Do the dumping. 2538 */ 2539 pDbgc->cbDumpElement = cbElement | (fAscii << 31); 2540 int cbLeft = (int)pDbgc->DumpPos.u64Range; 2541 uint8_t u8Prev = '\0'; 2542 for (;;) 2543 { 2544 /* 2545 * Read memory. 2546 */ 2547 char achBuffer[16]; 2548 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft); 2549 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft); 2550 int rc = pCmdHlp->pfnMemRead(pCmdHlp, &achBuffer, cbReq, &pDbgc->DumpPos, &cb); 2551 if (RT_FAILURE(rc)) 2552 { 2553 if (u8Prev && u8Prev != '\n') 2554 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2555 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos); 2556 } 2557 2558 /* 2559 * Display it. 2560 */ 2561 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb); 2562 if (!fAscii) 2563 { 2564 DBGCCmdHlpPrintf(pCmdHlp, "%DV:", &pDbgc->DumpPos); 2565 unsigned i; 2566 for (i = 0; i < cb; i += cbElement) 2567 { 2568 const char *pszSpace = " "; 2569 if (cbElement <= 2 && i == 8 && !fAscii) 2570 pszSpace = "-"; 2571 switch (cbElement) 2572 { 2573 case 1: DBGCCmdHlpPrintf(pCmdHlp, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break; 2574 case 2: DBGCCmdHlpPrintf(pCmdHlp, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break; 2575 case 4: DBGCCmdHlpPrintf(pCmdHlp, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break; 2576 case 8: DBGCCmdHlpPrintf(pCmdHlp, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break; 2577 } 2578 } 2579 2580 /* chars column */ 2581 if (pDbgc->cbDumpElement == 1) 2582 { 2583 while (i++ < sizeof(achBuffer)) 2584 DBGCCmdHlpPrintf(pCmdHlp, " "); 2585 DBGCCmdHlpPrintf(pCmdHlp, " "); 2586 for (i = 0; i < cb; i += cbElement) 2587 { 2588 uint8_t u8 = *(uint8_t *)&achBuffer[i]; 2589 if (RT_C_IS_PRINT(u8) && u8 < 127 && u8 >= 32) 2590 DBGCCmdHlpPrintf(pCmdHlp, "%c", u8); 2591 else 2592 DBGCCmdHlpPrintf(pCmdHlp, "."); 2593 } 2594 } 2595 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2596 } 2597 else 2598 { 2599 /* 2600 * We print up to the first zero and stop there. 2601 * Only printables + '\t' and '\n' are printed. 2602 */ 2603 if (!u8Prev) 2604 DBGCCmdHlpPrintf(pCmdHlp, "%DV:\n", &pDbgc->DumpPos); 2605 uint8_t u8 = '\0'; 2606 unsigned i; 2607 for (i = 0; i < cb; i++) 2608 { 2609 u8Prev = u8; 2610 u8 = *(uint8_t *)&achBuffer[i]; 2611 if ( u8 < 127 2612 && ( (RT_C_IS_PRINT(u8) && u8 >= 32) 2613 || u8 == '\t' 2614 || u8 == '\n')) 2615 DBGCCmdHlpPrintf(pCmdHlp, "%c", u8); 2616 else if (!u8) 2617 break; 2618 else 2619 DBGCCmdHlpPrintf(pCmdHlp, "\\x%x", u8); 2620 } 2621 if (u8 == '\0') 2622 cb = cbLeft = i + 1; 2623 if (cbLeft - cb <= 0 && u8Prev != '\n') 2624 DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2625 } 2626 2627 /* 2628 * Advance 2629 */ 2630 cbLeft -= (int)cb; 2631 rc = DBGCCmdHlpEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb); 2632 if (RT_FAILURE(rc)) 2633 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb); 2634 if (cbLeft <= 0) 2635 break; 2636 } 2637 2638 NOREF(pCmd); 2639 return VINF_SUCCESS; 2640 } 2641 2642 2643 /** 2644 * Best guess at which paging mode currently applies to the guest 2645 * paging structures. 2646 * 2647 * This have to come up with a decent answer even when the guest 2648 * is in non-paged protected mode or real mode. 2649 * 2650 * @returns cr3. 2651 * @param pDbgc The DBGC instance. 2652 * @param pfPAE Where to store the page address extension indicator. 2653 * @param pfLME Where to store the long mode enabled indicator. 2654 * @param pfPSE Where to store the page size extension indicator. 2655 * @param pfPGE Where to store the page global enabled indicator. 2656 * @param pfNXE Where to store the no-execution enabled indicator. 2657 */ 2658 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 2659 { 2660 PVMCPU pVCpu = VMMR3GetCpuByIdU(pDbgc->pUVM, pDbgc->idCpu); 2661 RTGCUINTREG cr4 = CPUMGetGuestCR4(pVCpu); 2662 *pfPSE = !!(cr4 & X86_CR4_PSE); 2663 *pfPGE = !!(cr4 & X86_CR4_PGE); 2664 if (cr4 & X86_CR4_PAE) 2665 { 2666 *pfPSE = true; 2667 *pfPAE = true; 2668 } 2669 else 2670 *pfPAE = false; 2671 2672 *pfLME = CPUMGetGuestMode(pVCpu) == CPUMMODE_LONG; 2673 *pfNXE = false; /* GUEST64 GUESTNX */ 2674 return CPUMGetGuestCR3(pVCpu); 2675 } 2676 2677 2678 /** 2679 * Determine the shadow paging mode. 2680 * 2681 * @returns cr3. 2682 * @param pDbgc The DBGC instance. 2683 * @param pfPAE Where to store the page address extension indicator. 2684 * @param pfLME Where to store the long mode enabled indicator. 2685 * @param pfPSE Where to store the page size extension indicator. 2686 * @param pfPGE Where to store the page global enabled indicator. 2687 * @param pfNXE Where to store the no-execution enabled indicator. 2688 */ 2689 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE) 2690 { 2691 PVMCPU pVCpu = VMMR3GetCpuByIdU(pDbgc->pUVM, pDbgc->idCpu); 2692 2693 *pfPSE = true; 2694 *pfPGE = false; 2695 switch (PGMGetShadowMode(pVCpu)) 2696 { 2697 default: 2698 case PGMMODE_32_BIT: 2699 *pfPAE = *pfLME = *pfNXE = false; 2700 break; 2701 case PGMMODE_PAE: 2702 *pfLME = *pfNXE = false; 2703 *pfPAE = true; 2704 break; 2705 case PGMMODE_PAE_NX: 2706 *pfLME = false; 2707 *pfPAE = *pfNXE = true; 2708 break; 2709 case PGMMODE_AMD64: 2710 *pfNXE = false; 2711 *pfPAE = *pfLME = true; 2712 break; 2713 case PGMMODE_AMD64_NX: 2714 *pfPAE = *pfLME = *pfNXE = true; 2715 break; 2716 } 2717 return PGMGetHyperCR3(pVCpu); 2718 } 2719 2720 2721 /** 2722 * @callback_method_impl{FNDBGCCMD, 2723 * The 'dpd'\, 'dpda'\, 'dpdb'\, 'dpdg' and 'dpdh' commands.} 2724 */ 2725 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2726 { 2727 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2728 2729 /* 2730 * Validate input. 2731 */ 2732 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 2733 if (cArgs == 1 && pCmd->pszCmd[3] == 'a') 2734 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2735 if (cArgs == 1 && pCmd->pszCmd[3] != 'a') 2736 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2737 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 2738 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2739 2740 /* 2741 * Guest or shadow page directories? Get the paging parameters. 2742 */ 2743 bool fGuest = pCmd->pszCmd[3] != 'h'; 2744 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a') 2745 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 2746 ? pDbgc->fRegCtxGuest 2747 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 2748 2749 bool fPAE, fLME, fPSE, fPGE, fNXE; 2750 uint64_t cr3 = fGuest 2751 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 2752 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 2753 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 2754 2755 /* 2756 * Setup default argument if none was specified. 2757 * Fix address / index confusion. 2758 */ 2759 DBGCVAR VarDefault; 2760 if (!cArgs) 2761 { 2762 if (pCmd->pszCmd[3] == 'a') 2763 { 2764 if (fLME || fPAE) 2765 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n"); 2766 if (fGuest) 2767 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3); 2768 else 2769 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3); 2770 } 2771 else 2772 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0); 2773 paArgs = &VarDefault; 2774 cArgs = 1; 2775 } 2776 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER) 2777 { 2778 /* If it's a number (not an address), it's an index, so convert it to an address. */ 2779 Assert(pCmd->pszCmd[3] != 'a'); 2780 VarDefault = paArgs[0]; 2781 if (fPAE) 2782 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n"); 2783 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry) 2784 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1); 2785 VarDefault.u.u64Number <<= X86_PD_SHIFT; 2786 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT; 2787 paArgs = &VarDefault; 2788 } 2789 2790 /* 2791 * Locate the PDE to start displaying at. 2792 * 2793 * The 'dpda' command takes the address of a PDE, while the others are guest 2794 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple 2795 * while the others require us to do all the tedious walking thru the paging 2796 * hierarchy to find the intended PDE. 2797 */ 2798 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */ 2799 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */ 2800 DBGCVAR VarPDEAddr; /* The address of the current PDE. */ 2801 unsigned cEntries; /* The number of entries to display. */ 2802 unsigned cEntriesMax; /* The max number of entries to display. */ 2803 int rc; 2804 if (pCmd->pszCmd[3] == 'a') 2805 { 2806 VarPDEAddr = paArgs[0]; 2807 switch (VarPDEAddr.enmRangeType) 2808 { 2809 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break; 2810 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break; 2811 default: cEntries = 10; break; 2812 } 2813 cEntriesMax = PAGE_SIZE / cbEntry; 2814 } 2815 else 2816 { 2817 /* 2818 * Determine the range. 2819 */ 2820 switch (paArgs[0].enmRangeType) 2821 { 2822 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 2823 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 2824 default: cEntries = 10; break; 2825 } 2826 2827 /* 2828 * Normalize the input address, it must be a flat GC address. 2829 */ 2830 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 2831 if (RT_FAILURE(rc)) 2832 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 2833 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 2834 { 2835 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 2836 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 2837 } 2838 if (fPAE) 2839 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1); 2840 else 2841 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1); 2842 2843 /* 2844 * Do the paging walk until we get to the page directory. 2845 */ 2846 DBGCVAR VarCur; 2847 if (fGuest) 2848 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 2849 else 2850 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 2851 if (fLME) 2852 { 2853 /* Page Map Level 4 Lookup. */ 2854 /* Check if it's a valid address first? */ 2855 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 2856 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 2857 X86PML4E Pml4e; 2858 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 2859 if (RT_FAILURE(rc)) 2860 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 2861 if (!Pml4e.n.u1Present) 2862 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 2863 2864 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 2865 Assert(fPAE); 2866 } 2867 if (fPAE) 2868 { 2869 /* Page directory pointer table. */ 2870 X86PDPE Pdpe; 2871 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe); 2872 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 2873 if (RT_FAILURE(rc)) 2874 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 2875 if (!Pdpe.n.u1Present) 2876 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 2877 2878 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK; 2879 VarPDEAddr = VarCur; 2880 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 2881 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE); 2882 } 2883 else 2884 { 2885 /* 32-bit legacy - CR3 == page directory. */ 2886 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK; 2887 VarPDEAddr = VarCur; 2888 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE); 2889 } 2890 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 2891 } 2892 2893 /* adjust cEntries */ 2894 cEntries = RT_MAX(1, cEntries); 2895 cEntries = RT_MIN(cEntries, cEntriesMax); 2896 2897 /* 2898 * The display loop. 2899 */ 2900 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n", 2901 &VarPDEAddr, iEntry); 2902 do 2903 { 2904 /* 2905 * Read. 2906 */ 2907 X86PDEPAE Pde; 2908 Pde.u = 0; 2909 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, cbEntry, &VarPDEAddr, NULL); 2910 if (RT_FAILURE(rc)) 2911 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr); 2912 2913 /* 2914 * Display. 2915 */ 2916 if (iEntry != ~0U) 2917 { 2918 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 2919 iEntry++; 2920 } 2921 if (fPSE && Pde.b.u1Size) 2922 DBGCCmdHlpPrintf(pCmdHlp, 2923 fPAE 2924 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 2925 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 2926 Pde.u, 2927 Pde.u & X86_PDE_PAE_PG_MASK, 2928 Pde.b.u1Present ? "p " : "np", 2929 Pde.b.u1Write ? "w" : "r", 2930 Pde.b.u1User ? "u" : "s", 2931 Pde.b.u1Accessed ? "a " : "na", 2932 Pde.b.u1Dirty ? "d " : "nd", 2933 Pde.b.u3Available, 2934 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ", 2935 Pde.b.u1WriteThru ? "pwt" : " ", 2936 Pde.b.u1CacheDisable ? "pcd" : " ", 2937 Pde.b.u1PAT ? "pat" : "", 2938 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 2939 else 2940 DBGCCmdHlpPrintf(pCmdHlp, 2941 fPAE 2942 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s" 2943 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s", 2944 Pde.u, 2945 Pde.u & X86_PDE_PAE_PG_MASK, 2946 Pde.n.u1Present ? "p " : "np", 2947 Pde.n.u1Write ? "w" : "r", 2948 Pde.n.u1User ? "u" : "s", 2949 Pde.n.u1Accessed ? "a " : "na", 2950 Pde.u & RT_BIT(6) ? "6 " : " ", 2951 Pde.n.u3Available, 2952 Pde.u & RT_BIT(8) ? "8" : " ", 2953 Pde.n.u1WriteThru ? "pwt" : " ", 2954 Pde.n.u1CacheDisable ? "pcd" : " ", 2955 Pde.u & RT_BIT(7) ? "7" : "", 2956 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "); 2957 if (Pde.u & UINT64_C(0x7fff000000000000)) 2958 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000))); 2959 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 2960 if (RT_FAILURE(rc)) 2961 return rc; 2962 2963 /* 2964 * Advance. 2965 */ 2966 VarPDEAddr.u.u64Number += cbEntry; 2967 if (iEntry != ~0U) 2968 VarGCPtr.u.GCFlat += fPAE ? RT_BIT_32(X86_PD_PAE_SHIFT) : RT_BIT_32(X86_PD_SHIFT); 2969 } while (cEntries-- > 0); 2970 2971 return VINF_SUCCESS; 2972 } 2973 2974 2975 /** 2976 * @callback_method_impl{FNDBGCCMD, The 'dpdb' command.} 2977 */ 2978 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2979 { 2980 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2981 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]); 2982 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]); 2983 if (RT_FAILURE(rc1)) 2984 return rc1; 2985 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); 2986 return rc2; 2987 } 2988 2989 2990 /** 2991 * @callback_method_impl{FNDBGCCMD, The 'dph*' commands and main part of 'm'.} 2992 */ 2993 static DECLCALLBACK(int) dbgcCmdDumpPageHierarchy(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 2994 { 2995 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 2996 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 2997 2998 /* 2999 * Figure the context and base flags. 3000 */ 3001 uint32_t fFlags = DBGFPGDMP_FLAGS_PAGE_INFO | DBGFPGDMP_FLAGS_PRINT_CR3; 3002 if (pCmd->pszCmd[0] == 'm') 3003 fFlags |= DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW; 3004 else if (pCmd->pszCmd[3] == '\0') 3005 fFlags |= pDbgc->fRegCtxGuest ? DBGFPGDMP_FLAGS_GUEST : DBGFPGDMP_FLAGS_SHADOW; 3006 else if (pCmd->pszCmd[3] == 'g') 3007 fFlags |= DBGFPGDMP_FLAGS_GUEST; 3008 else if (pCmd->pszCmd[3] == 'h') 3009 fFlags |= DBGFPGDMP_FLAGS_SHADOW; 3010 else 3011 AssertFailed(); 3012 3013 if (pDbgc->cPagingHierarchyDumps == 0) 3014 fFlags |= DBGFPGDMP_FLAGS_HEADER; 3015 pDbgc->cPagingHierarchyDumps = (pDbgc->cPagingHierarchyDumps + 1) % 42; 3016 3017 /* 3018 * Get the range. 3019 */ 3020 PCDBGCVAR pRange = cArgs > 0 ? &paArgs[0] : pDbgc->pLastPos; 3021 RTGCPTR GCPtrFirst = NIL_RTGCPTR; 3022 int rc = DBGCCmdHlpVarToFlatAddr(pCmdHlp, pRange, &GCPtrFirst); 3023 if (RT_FAILURE(rc)) 3024 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to convert %DV to a flat address: %Rrc", pRange, rc); 3025 3026 uint64_t cbRange; 3027 rc = DBGCCmdHlpVarGetRange(pCmdHlp, pRange, PAGE_SIZE, PAGE_SIZE * 8, &cbRange); 3028 if (RT_FAILURE(rc)) 3029 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to obtain the range of %DV: %Rrc", pRange, rc); 3030 3031 RTGCPTR GCPtrLast = RTGCPTR_MAX - GCPtrFirst; 3032 if (cbRange >= GCPtrLast) 3033 GCPtrLast = RTGCPTR_MAX; 3034 else if (!cbRange) 3035 GCPtrLast = GCPtrFirst; 3036 else 3037 GCPtrLast = GCPtrFirst + cbRange - 1; 3038 3039 /* 3040 * Do we have a CR3? 3041 */ 3042 uint64_t cr3 = 0; 3043 if (cArgs > 1) 3044 { 3045 if ((fFlags & (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) == (DBGFPGDMP_FLAGS_GUEST | DBGFPGDMP_FLAGS_SHADOW)) 3046 return DBGCCmdHlpFail(pCmdHlp, pCmd, "No CR3 or mode arguments when dumping both context, please."); 3047 if (paArgs[1].enmType != DBGCVAR_TYPE_NUMBER) 3048 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The CR3 argument is not a number: %DV", &paArgs[1]); 3049 cr3 = paArgs[1].u.u64Number; 3050 } 3051 else 3052 fFlags |= DBGFPGDMP_FLAGS_CURRENT_CR3; 3053 3054 /* 3055 * Do we have a mode? 3056 */ 3057 if (cArgs > 2) 3058 { 3059 if (paArgs[2].enmType != DBGCVAR_TYPE_STRING) 3060 return DBGCCmdHlpFail(pCmdHlp, pCmd, "The mode argument is not a string: %DV", &paArgs[2]); 3061 static const struct MODETOFLAGS 3062 { 3063 const char *pszName; 3064 uint32_t fFlags; 3065 } s_aModeToFlags[] = 3066 { 3067 { "ept", DBGFPGDMP_FLAGS_EPT }, 3068 { "legacy", 0 }, 3069 { "legacy-np", DBGFPGDMP_FLAGS_NP }, 3070 { "pse", DBGFPGDMP_FLAGS_PSE }, 3071 { "pse-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_NP }, 3072 { "pae", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE }, 3073 { "pae-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NP }, 3074 { "pae-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE }, 3075 { "pae-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP }, 3076 { "long", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME }, 3077 { "long-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NP }, 3078 { "long-nx", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE }, 3079 { "long-nx-np", DBGFPGDMP_FLAGS_PSE | DBGFPGDMP_FLAGS_PAE | DBGFPGDMP_FLAGS_LME | DBGFPGDMP_FLAGS_NXE | DBGFPGDMP_FLAGS_NP } 3080 }; 3081 int i = RT_ELEMENTS(s_aModeToFlags); 3082 while (i-- > 0) 3083 if (!strcmp(s_aModeToFlags[i].pszName, paArgs[2].u.pszString)) 3084 { 3085 fFlags |= s_aModeToFlags[i].fFlags; 3086 break; 3087 } 3088 if (i < 0) 3089 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Unknown mode: \"%s\"", paArgs[2].u.pszString); 3090 } 3091 else 3092 fFlags |= DBGFPGDMP_FLAGS_CURRENT_MODE; 3093 3094 /* 3095 * Call the worker. 3096 */ 3097 rc = DBGFR3PagingDumpEx(pUVM, pDbgc->idCpu, fFlags, cr3, GCPtrFirst, GCPtrLast, 99 /*cMaxDepth*/, 3098 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp)); 3099 if (RT_FAILURE(rc)) 3100 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3PagingDumpEx: %Rrc\n", rc); 3101 return VINF_SUCCESS; 3102 } 3103 3104 3105 3106 /** 3107 * @callback_method_impl{FNDBGCCMD, The 'dpg*' commands.} 3108 */ 3109 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3110 { 3111 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3112 3113 /* 3114 * Validate input. 3115 */ 3116 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs == 1); 3117 if (pCmd->pszCmd[3] == 'a') 3118 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 3119 else 3120 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 3121 || DBGCVAR_ISPOINTER(paArgs[0].enmType)); 3122 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3123 3124 /* 3125 * Guest or shadow page tables? Get the paging parameters. 3126 */ 3127 bool fGuest = pCmd->pszCmd[3] != 'h'; 3128 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a') 3129 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER 3130 ? pDbgc->fRegCtxGuest 3131 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType); 3132 3133 bool fPAE, fLME, fPSE, fPGE, fNXE; 3134 uint64_t cr3 = fGuest 3135 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE) 3136 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE); 3137 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE); 3138 3139 /* 3140 * Locate the PTE to start displaying at. 3141 * 3142 * The 'dpta' command takes the address of a PTE, while the others are guest 3143 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple 3144 * while the others require us to do all the tedious walking thru the paging 3145 * hierarchy to find the intended PTE. 3146 */ 3147 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */ 3148 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */ 3149 DBGCVAR VarPTEAddr; /* The address of the current PTE. */ 3150 unsigned cEntries; /* The number of entries to display. */ 3151 unsigned cEntriesMax; /* The max number of entries to display. */ 3152 int rc; 3153 if (pCmd->pszCmd[3] == 'a') 3154 { 3155 VarPTEAddr = paArgs[0]; 3156 switch (VarPTEAddr.enmRangeType) 3157 { 3158 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break; 3159 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break; 3160 default: cEntries = 10; break; 3161 } 3162 cEntriesMax = PAGE_SIZE / cbEntry; 3163 } 3164 else 3165 { 3166 /* 3167 * Determine the range. 3168 */ 3169 switch (paArgs[0].enmRangeType) 3170 { 3171 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break; 3172 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break; 3173 default: cEntries = 10; break; 3174 } 3175 3176 /* 3177 * Normalize the input address, it must be a flat GC address. 3178 */ 3179 rc = DBGCCmdHlpEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]); 3180 if (RT_FAILURE(rc)) 3181 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3182 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT) 3183 { 3184 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat; 3185 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT; 3186 } 3187 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK; 3188 3189 /* 3190 * Do the paging walk until we get to the page table. 3191 */ 3192 DBGCVAR VarCur; 3193 if (fGuest) 3194 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3); 3195 else 3196 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3); 3197 if (fLME) 3198 { 3199 /* Page Map Level 4 Lookup. */ 3200 /* Check if it's a valid address first? */ 3201 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK; 3202 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E); 3203 X86PML4E Pml4e; 3204 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pml4e, sizeof(Pml4e), &VarCur, NULL); 3205 if (RT_FAILURE(rc)) 3206 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur); 3207 if (!Pml4e.n.u1Present) 3208 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr); 3209 3210 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK; 3211 Assert(fPAE); 3212 } 3213 if (fPAE) 3214 { 3215 /* Page directory pointer table. */ 3216 X86PDPE Pdpe; 3217 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPT_SHIFT) & X86_PDPT_MASK_PAE) * sizeof(Pdpe); 3218 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pdpe, sizeof(Pdpe), &VarCur, NULL); 3219 if (RT_FAILURE(rc)) 3220 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur); 3221 if (!Pdpe.n.u1Present) 3222 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr); 3223 3224 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK; 3225 3226 /* Page directory (PAE). */ 3227 X86PDEPAE Pde; 3228 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde); 3229 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL); 3230 if (RT_FAILURE(rc)) 3231 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3232 if (!Pde.n.u1Present) 3233 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3234 if (fPSE && Pde.n.u1Size) 3235 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3236 3237 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK; 3238 VarPTEAddr = VarCur; 3239 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK; 3240 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE); 3241 } 3242 else 3243 { 3244 /* Page directory (legacy). */ 3245 X86PDE Pde; 3246 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde); 3247 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pde, sizeof(Pde), &VarCur, NULL); 3248 if (RT_FAILURE(rc)) 3249 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur); 3250 if (!Pde.n.u1Present) 3251 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr); 3252 if (fPSE && Pde.n.u1Size) 3253 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr); 3254 3255 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK; 3256 VarPTEAddr = VarCur; 3257 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK; 3258 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE); 3259 } 3260 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry; 3261 } 3262 3263 /* adjust cEntries */ 3264 cEntries = RT_MAX(1, cEntries); 3265 cEntries = RT_MIN(cEntries, cEntriesMax); 3266 3267 /* 3268 * The display loop. 3269 */ 3270 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", 3271 &VarPTEAddr, &VarGCPtr, iEntry); 3272 do 3273 { 3274 /* 3275 * Read. 3276 */ 3277 X86PTEPAE Pte; 3278 Pte.u = 0; 3279 rc = pCmdHlp->pfnMemRead(pCmdHlp, &Pte, cbEntry, &VarPTEAddr, NULL); 3280 if (RT_FAILURE(rc)) 3281 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr); 3282 3283 /* 3284 * Display. 3285 */ 3286 if (iEntry != ~0U) 3287 { 3288 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr); 3289 iEntry++; 3290 } 3291 DBGCCmdHlpPrintf(pCmdHlp, 3292 fPAE 3293 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s" 3294 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s", 3295 Pte.u, 3296 Pte.u & X86_PTE_PAE_PG_MASK, 3297 Pte.n.u1Present ? "p " : "np", 3298 Pte.n.u1Write ? "w" : "r", 3299 Pte.n.u1User ? "u" : "s", 3300 Pte.n.u1Accessed ? "a " : "na", 3301 Pte.n.u1Dirty ? "d " : "nd", 3302 Pte.n.u3Available, 3303 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ", 3304 Pte.n.u1WriteThru ? "pwt" : " ", 3305 Pte.n.u1CacheDisable ? "pcd" : " ", 3306 Pte.n.u1PAT ? "pat" : " ", 3307 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " " 3308 ); 3309 if (Pte.u & UINT64_C(0x7fff000000000000)) 3310 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000))); 3311 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n"); 3312 if (RT_FAILURE(rc)) 3313 return rc; 3314 3315 /* 3316 * Advance. 3317 */ 3318 VarPTEAddr.u.u64Number += cbEntry; 3319 if (iEntry != ~0U) 3320 VarGCPtr.u.GCFlat += PAGE_SIZE; 3321 } while (cEntries-- > 0); 3322 3323 return VINF_SUCCESS; 3324 } 3325 3326 3327 /** 3328 * @callback_method_impl{FNDBGCCMD, The 'dptb' command.} 3329 */ 3330 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3331 { 3332 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3333 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]); 3334 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]); 3335 if (RT_FAILURE(rc1)) 3336 return rc1; 3337 NOREF(pCmd); NOREF(cArgs); 3338 return rc2; 3339 } 3340 3341 3342 /** 3343 * @callback_method_impl{FNDBGCCMD, The 'dt' command.} 3344 */ 3345 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3346 { 3347 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3348 int rc; 3349 3350 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3351 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs <= 1); 3352 if (cArgs == 1) 3353 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[0].enmType != DBGCVAR_TYPE_STRING 3354 && paArgs[0].enmType != DBGCVAR_TYPE_SYMBOL); 3355 3356 /* 3357 * Check if the command indicates the type. 3358 */ 3359 enum { kTss16, kTss32, kTss64, kTssToBeDetermined } enmTssType = kTssToBeDetermined; 3360 if (!strcmp(pCmd->pszCmd, "dt16")) 3361 enmTssType = kTss16; 3362 else if (!strcmp(pCmd->pszCmd, "dt32")) 3363 enmTssType = kTss32; 3364 else if (!strcmp(pCmd->pszCmd, "dt64")) 3365 enmTssType = kTss64; 3366 3367 /* 3368 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer. 3369 */ 3370 uint32_t SelTss = UINT32_MAX; 3371 DBGCVAR VarTssAddr; 3372 if (cArgs == 0) 3373 { 3374 /** @todo consider querying the hidden bits instead (missing API). */ 3375 uint16_t SelTR; 3376 rc = DBGFR3RegCpuQueryU16(pUVM, pDbgc->idCpu, DBGFREG_TR, &SelTR); 3377 if (RT_FAILURE(rc)) 3378 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to query TR, rc=%Rrc\n", rc); 3379 DBGCVAR_INIT_GC_FAR(&VarTssAddr, SelTR, 0); 3380 SelTss = SelTR; 3381 } 3382 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER) 3383 { 3384 if (paArgs[0].u.u64Number < 0xffff) 3385 DBGCVAR_INIT_GC_FAR(&VarTssAddr, (RTSEL)paArgs[0].u.u64Number, 0); 3386 else 3387 { 3388 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_ELEMENTS) 3389 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Element count doesn't combine with a TSS address.\n"); 3390 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, paArgs[0].u.u64Number); 3391 if (paArgs[0].enmRangeType == DBGCVAR_RANGE_BYTES) 3392 { 3393 VarTssAddr.enmRangeType = paArgs[0].enmRangeType; 3394 VarTssAddr.u64Range = paArgs[0].u64Range; 3395 } 3396 } 3397 } 3398 else 3399 VarTssAddr = paArgs[0]; 3400 3401 /* 3402 * Deal with TSS:ign by means of the GDT. 3403 */ 3404 if (VarTssAddr.enmType == DBGCVAR_TYPE_GC_FAR) 3405 { 3406 SelTss = VarTssAddr.u.GCFar.sel; 3407 DBGFSELINFO SelInfo; 3408 rc = DBGFR3SelQueryInfo(pUVM, pDbgc->idCpu, VarTssAddr.u.GCFar.sel, DBGFSELQI_FLAGS_DT_GUEST, &SelInfo); 3409 if (RT_FAILURE(rc)) 3410 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3SelQueryInfo(,%u,%d,,) -> %Rrc.\n", 3411 pDbgc->idCpu, VarTssAddr.u.GCFar.sel, rc); 3412 3413 if (SelInfo.u.Raw.Gen.u1DescType) 3414 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (!sys)\n", VarTssAddr.u.GCFar.sel); 3415 3416 switch (SelInfo.u.Raw.Gen.u4Type) 3417 { 3418 case X86_SEL_TYPE_SYS_286_TSS_BUSY: 3419 case X86_SEL_TYPE_SYS_286_TSS_AVAIL: 3420 if (enmTssType == kTssToBeDetermined) 3421 enmTssType = kTss16; 3422 break; 3423 3424 case X86_SEL_TYPE_SYS_386_TSS_BUSY: /* AMD64 too */ 3425 case X86_SEL_TYPE_SYS_386_TSS_AVAIL: 3426 if (enmTssType == kTssToBeDetermined) 3427 enmTssType = SelInfo.fFlags & DBGFSELINFO_FLAGS_LONG_MODE ? kTss64 : kTss32; 3428 break; 3429 3430 default: 3431 return DBGCCmdHlpFail(pCmdHlp, pCmd, "%04x is not a TSS selector. (type=%x)\n", 3432 VarTssAddr.u.GCFar.sel, SelInfo.u.Raw.Gen.u4Type); 3433 } 3434 3435 DBGCVAR_INIT_GC_FLAT(&VarTssAddr, SelInfo.GCPtrBase); 3436 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, RT_MAX(SelInfo.cbLimit + 1, SelInfo.cbLimit)); 3437 } 3438 3439 /* 3440 * Determine the TSS type if none is currently given. 3441 */ 3442 if (enmTssType == kTssToBeDetermined) 3443 { 3444 if ( VarTssAddr.u64Range > 0 3445 && VarTssAddr.u64Range < sizeof(X86TSS32) - 4) 3446 enmTssType = kTss16; 3447 else 3448 { 3449 uint64_t uEfer; 3450 rc = DBGFR3RegCpuQueryU64(pUVM, pDbgc->idCpu, DBGFREG_MSR_K6_EFER, &uEfer); 3451 if ( RT_FAILURE(rc) 3452 || !(uEfer & MSR_K6_EFER_LMA) ) 3453 enmTssType = kTss32; 3454 else 3455 enmTssType = kTss64; 3456 } 3457 } 3458 3459 /* 3460 * Figure the min/max sizes. 3461 * ASSUMES max TSS size is 64 KB. 3462 */ 3463 uint32_t cbTssMin; 3464 uint32_t cbTssMax; 3465 switch (enmTssType) 3466 { 3467 case kTss16: 3468 cbTssMin = cbTssMax = sizeof(X86TSS16); 3469 break; 3470 case kTss32: 3471 cbTssMin = RT_OFFSETOF(X86TSS32, IntRedirBitmap); 3472 cbTssMax = _64K; 3473 break; 3474 case kTss64: 3475 cbTssMin = RT_OFFSETOF(X86TSS64, IntRedirBitmap); 3476 cbTssMax = _64K; 3477 break; 3478 default: 3479 AssertFailedReturn(VERR_INTERNAL_ERROR); 3480 } 3481 uint32_t cbTss = VarTssAddr.enmRangeType == DBGCVAR_RANGE_BYTES ? (uint32_t)VarTssAddr.u64Range : 0; 3482 if (cbTss == 0) 3483 cbTss = cbTssMin; 3484 else if (cbTss < cbTssMin) 3485 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Minimum TSS size is %u bytes, you specified %llu (%llx) bytes.\n", 3486 cbTssMin, VarTssAddr.u64Range, VarTssAddr.u64Range); 3487 else if (cbTss > cbTssMax) 3488 cbTss = cbTssMax; 3489 DBGCVAR_SET_RANGE(&VarTssAddr, DBGCVAR_RANGE_BYTES, cbTss); 3490 3491 /* 3492 * Read the TSS into a temporary buffer. 3493 */ 3494 uint8_t abBuf[_64K]; 3495 size_t cbTssRead; 3496 rc = DBGCCmdHlpMemRead(pCmdHlp, abBuf, cbTss, &VarTssAddr, &cbTssRead); 3497 if (RT_FAILURE(rc)) 3498 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read TSS at %Dv: %Rrc\n", &VarTssAddr, rc); 3499 if (cbTssRead < cbTssMin) 3500 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Failed to read essential parts of the TSS (read %zu, min %zu).\n", 3501 cbTssRead, cbTssMin); 3502 if (cbTssRead < cbTss) 3503 memset(&abBuf[cbTssRead], 0xff, cbTss - cbTssRead); 3504 3505 3506 /* 3507 * Format the TSS. 3508 */ 3509 uint16_t offIoBitmap; 3510 switch (enmTssType) 3511 { 3512 case kTss16: 3513 { 3514 PCX86TSS16 pTss = (PCX86TSS16)&abBuf[0]; 3515 if (SelTss != UINT32_MAX) 3516 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS16 at %Dv\n", SelTss, &VarTssAddr); 3517 else 3518 DBGCCmdHlpPrintf(pCmdHlp, "TSS16 at %Dv\n", &VarTssAddr); 3519 DBGCCmdHlpPrintf(pCmdHlp, 3520 "ax=%04x bx=%04x cx=%04x dx=%04x si=%04x di=%04x\n" 3521 "ip=%04x sp=%04x bp=%04x\n" 3522 "cs=%04x ss=%04x ds=%04x es=%04x flags=%04x\n" 3523 "ss:sp0=%04x:%04x ss:sp1=%04x:%04x ss:sp2=%04x:%04x\n" 3524 "prev=%04x ldtr=%04x\n" 3525 , 3526 pTss->ax, pTss->bx, pTss->cx, pTss->dx, pTss->si, pTss->di, 3527 pTss->ip, pTss->sp, pTss->bp, 3528 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->flags, 3529 pTss->ss0, pTss->sp0, pTss->ss1, pTss->sp1, pTss->ss2, pTss->sp2, 3530 pTss->selPrev, pTss->selLdt); 3531 if (pTss->cs != 0) 3532 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%04x L 0", pTss->cs, pTss->ip); 3533 offIoBitmap = 0; 3534 break; 3535 } 3536 3537 case kTss32: 3538 { 3539 PCX86TSS32 pTss = (PCX86TSS32)&abBuf[0]; 3540 if (SelTss != UINT32_MAX) 3541 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS32 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin); 3542 else 3543 DBGCCmdHlpPrintf(pCmdHlp, "TSS32 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin); 3544 DBGCCmdHlpPrintf(pCmdHlp, 3545 "eax=%08x bx=%08x ecx=%08x edx=%08x esi=%08x edi=%08x\n" 3546 "eip=%08x esp=%08x ebp=%08x\n" 3547 "cs=%04x ss=%04x ds=%04x es=%04x fs=%04x gs=%04x eflags=%08x\n" 3548 "ss:esp0=%04x:%08x ss:esp1=%04x:%08x ss:esp2=%04x:%08x\n" 3549 "prev=%04x ldtr=%04x cr3=%08x debug=%u iomap=%04x\n" 3550 , 3551 pTss->eax, pTss->ebx, pTss->ecx, pTss->edx, pTss->esi, pTss->edi, 3552 pTss->eip, pTss->esp, pTss->ebp, 3553 pTss->cs, pTss->ss, pTss->ds, pTss->es, pTss->fs, pTss->gs, pTss->eflags, 3554 pTss->ss0, pTss->esp0, pTss->ss1, pTss->esp1, pTss->ss2, pTss->esp2, 3555 pTss->selPrev, pTss->selLdt, pTss->cr3, pTss->fDebugTrap, pTss->offIoBitmap); 3556 if (pTss->cs != 0) 3557 pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pTss->cs, pTss->eip); 3558 offIoBitmap = pTss->offIoBitmap; 3559 break; 3560 } 3561 3562 case kTss64: 3563 { 3564 PCX86TSS64 pTss = (PCX86TSS64)&abBuf[0]; 3565 if (SelTss != UINT32_MAX) 3566 DBGCCmdHlpPrintf(pCmdHlp, "%04x TSS64 at %Dv (min=%04x)\n", SelTss, &VarTssAddr, cbTssMin); 3567 else 3568 DBGCCmdHlpPrintf(pCmdHlp, "TSS64 at %Dv (min=%04x)\n", &VarTssAddr, cbTssMin); 3569 DBGCCmdHlpPrintf(pCmdHlp, 3570 "rsp0=%016RX16 rsp1=%016RX16 rsp2=%016RX16\n" 3571 "ist1=%016RX16 ist2=%016RX16\n" 3572 "ist3=%016RX16 ist4=%016RX16\n" 3573 "ist5=%016RX16 ist6=%016RX16\n" 3574 "ist7=%016RX16 iomap=%04x\n" 3575 , 3576 pTss->rsp0, pTss->rsp1, pTss->rsp2, 3577 pTss->ist1, pTss->ist2, 3578 pTss->ist3, pTss->ist4, 3579 pTss->ist5, pTss->ist6, 3580 pTss->ist7, pTss->offIoBitmap); 3581 offIoBitmap = pTss->offIoBitmap; 3582 break; 3583 } 3584 3585 default: 3586 AssertFailedReturn(VERR_INTERNAL_ERROR); 3587 } 3588 3589 /* 3590 * Dump the interrupt redirection bitmap. 3591 */ 3592 if (enmTssType != kTss16) 3593 { 3594 if ( offIoBitmap > cbTssMin 3595 && offIoBitmap < cbTss) /** @todo check exactly what the edge cases are here. */ 3596 { 3597 if (offIoBitmap - cbTssMin >= 32) 3598 { 3599 DBGCCmdHlpPrintf(pCmdHlp, "Interrupt redirection:\n"); 3600 uint8_t const *pbIntRedirBitmap = &abBuf[offIoBitmap - 32]; 3601 uint32_t iStart = 0; 3602 bool fPrev = ASMBitTest(pbIntRedirBitmap, 0); /* LE/BE issue */ 3603 for (uint32_t i = 0; i < 256; i++) 3604 { 3605 bool fThis = ASMBitTest(pbIntRedirBitmap, i); 3606 if (fThis != fPrev) 3607 { 3608 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, i - 1, fPrev ? "Protected mode" : "Redirected"); 3609 fPrev = fThis; 3610 iStart = i; 3611 } 3612 } 3613 if (iStart != 255) 3614 DBGCCmdHlpPrintf(pCmdHlp, "%02x-%02x %s\n", iStart, 255, fPrev ? "Protected mode" : "Redirected"); 3615 } 3616 else 3617 DBGCCmdHlpPrintf(pCmdHlp, "Invalid interrupt redirection bitmap size: %u (%#x), expected 32 bytes.\n", 3618 offIoBitmap - cbTssMin, offIoBitmap - cbTssMin); 3619 } 3620 else if (offIoBitmap > 0) 3621 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap (-%#x)\n", cbTssMin - offIoBitmap); 3622 else 3623 DBGCCmdHlpPrintf(pCmdHlp, "No interrupt redirection bitmap\n"); 3624 } 3625 3626 /* 3627 * Dump the I/O permission bitmap if present. The IOPM cannot start below offset 0x64 3628 * (that applies to both 32-bit and 64-bit TSSs since their size is the same). 3629 */ 3630 if (enmTssType != kTss16) 3631 { 3632 if (offIoBitmap < cbTss && offIoBitmap >= 0x64) 3633 { 3634 uint32_t cPorts = RT_MIN((cbTss - offIoBitmap) * 8, _64K); 3635 DBGCVAR VarAddr; 3636 DBGCCmdHlpEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarTssAddr, offIoBitmap); 3637 DBGCCmdHlpPrintf(pCmdHlp, "I/O bitmap at %DV - %#x ports:\n", &VarAddr, cPorts); 3638 3639 uint8_t const *pbIoBitmap = &abBuf[offIoBitmap]; 3640 uint32_t iStart = 0; 3641 bool fPrev = ASMBitTest(pbIoBitmap, 0); 3642 uint32_t cLine = 0; 3643 for (uint32_t i = 1; i < cPorts; i++) 3644 { 3645 bool fThis = ASMBitTest(pbIoBitmap, i); 3646 if (fThis != fPrev) 3647 { 3648 cLine++; 3649 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s%s", iStart, i-1, 3650 fPrev ? "GP" : "OK", (cLine % 6) == 0 ? "\n" : " "); 3651 fPrev = fThis; 3652 iStart = i; 3653 } 3654 } 3655 if (iStart != _64K-1) 3656 DBGCCmdHlpPrintf(pCmdHlp, "%04x-%04x %s\n", iStart, _64K-1, fPrev ? "GP" : "OK"); 3657 } 3658 else if (offIoBitmap > 0) 3659 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap (-%#x)\n", cbTssMin - offIoBitmap); 3660 else 3661 DBGCCmdHlpPrintf(pCmdHlp, "No I/O bitmap\n"); 3662 } 3663 3664 return VINF_SUCCESS; 3665 } 3666 3667 3668 /** 3669 * @callback_method_impl{FNDBGCCMD, The 'm' command.} 3670 */ 3671 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3672 { 3673 DBGCCmdHlpPrintf(pCmdHlp, "Address: %DV\n", &paArgs[0]); 3674 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3675 return dbgcCmdDumpPageHierarchy(pCmd, pCmdHlp, pUVM, paArgs, cArgs); 3676 } 3677 3678 3679 /** 3680 * Converts one or more variables into a byte buffer for a 3681 * given unit size. 3682 * 3683 * @returns VBox status codes: 3684 * @retval VERR_TOO_MUCH_DATA if the buffer is too small, bitched. 3685 * @retval VERR_INTERNAL_ERROR on bad variable type, bitched. 3686 * @retval VINF_SUCCESS on success. 3687 * 3688 * @param pvBuf The buffer to convert into. 3689 * @param pcbBuf The buffer size on input. The size of the result on output. 3690 * @param cbUnit The unit size to apply when converting. 3691 * The high bit is used to indicate unicode string. 3692 * @param paVars The array of variables to convert. 3693 * @param cVars The number of variables. 3694 */ 3695 int dbgcVarsToBytes(PDBGCCMDHLP pCmdHlp, void *pvBuf, uint32_t *pcbBuf, size_t cbUnit, PCDBGCVAR paVars, unsigned cVars) 3696 { 3697 union 3698 { 3699 uint8_t *pu8; 3700 uint16_t *pu16; 3701 uint32_t *pu32; 3702 uint64_t *pu64; 3703 } u, uEnd; 3704 u.pu8 = (uint8_t *)pvBuf; 3705 uEnd.pu8 = u.pu8 + *pcbBuf; 3706 3707 unsigned i; 3708 for (i = 0; i < cVars && u.pu8 < uEnd.pu8; i++) 3709 { 3710 switch (paVars[i].enmType) 3711 { 3712 case DBGCVAR_TYPE_GC_FAR: 3713 case DBGCVAR_TYPE_GC_FLAT: 3714 case DBGCVAR_TYPE_GC_PHYS: 3715 case DBGCVAR_TYPE_HC_FLAT: 3716 case DBGCVAR_TYPE_HC_PHYS: 3717 case DBGCVAR_TYPE_NUMBER: 3718 { 3719 uint64_t u64 = paVars[i].u.u64Number; 3720 switch (cbUnit & 0x1f) 3721 { 3722 case 1: 3723 do 3724 { 3725 *u.pu8++ = u64; 3726 u64 >>= 8; 3727 } while (u64); 3728 break; 3729 case 2: 3730 do 3731 { 3732 *u.pu16++ = u64; 3733 u64 >>= 16; 3734 } while (u64); 3735 break; 3736 case 4: 3737 *u.pu32++ = u64; 3738 u64 >>= 32; 3739 if (u64) 3740 *u.pu32++ = u64; 3741 break; 3742 case 8: 3743 *u.pu64++ = u64; 3744 break; 3745 } 3746 break; 3747 } 3748 3749 case DBGCVAR_TYPE_STRING: 3750 case DBGCVAR_TYPE_SYMBOL: 3751 { 3752 const char *psz = paVars[i].u.pszString; 3753 size_t cbString = strlen(psz); 3754 if (cbUnit & RT_BIT_32(31)) 3755 { 3756 /* Explode char to unit. */ 3757 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8) * (cbUnit & 0x1f)) 3758 { 3759 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3760 return VERR_TOO_MUCH_DATA; 3761 } 3762 while (*psz) 3763 { 3764 switch (cbUnit & 0x1f) 3765 { 3766 case 1: *u.pu8++ = *psz; break; 3767 case 2: *u.pu16++ = *psz; break; 3768 case 4: *u.pu32++ = *psz; break; 3769 case 8: *u.pu64++ = *psz; break; 3770 } 3771 psz++; 3772 } 3773 } 3774 else 3775 { 3776 /* Raw copy with zero padding if the size isn't aligned. */ 3777 if (cbString > (uintptr_t)(uEnd.pu8 - u.pu8)) 3778 { 3779 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3780 return VERR_TOO_MUCH_DATA; 3781 } 3782 3783 size_t cbCopy = cbString & ~(cbUnit - 1); 3784 memcpy(u.pu8, psz, cbCopy); 3785 u.pu8 += cbCopy; 3786 psz += cbCopy; 3787 3788 size_t cbReminder = cbString & (cbUnit - 1); 3789 if (cbReminder) 3790 { 3791 memcpy(u.pu8, psz, cbString & (cbUnit - 1)); 3792 memset(u.pu8 + cbReminder, 0, cbUnit - cbReminder); 3793 u.pu8 += cbUnit; 3794 } 3795 } 3796 break; 3797 } 3798 3799 default: 3800 *pcbBuf = u.pu8 - (uint8_t *)pvBuf; 3801 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INTERNAL_ERROR, 3802 "i=%d enmType=%d\n", i, paVars[i].enmType); 3803 return VERR_INTERNAL_ERROR; 3804 } 3805 } 3806 *pcbBuf = u.pu8 - (uint8_t *)pvBuf; 3807 if (i != cVars) 3808 { 3809 pCmdHlp->pfnVBoxError(pCmdHlp, VERR_TOO_MUCH_DATA, "Max %d bytes.\n", uEnd.pu8 - (uint8_t *)pvBuf); 3810 return VERR_TOO_MUCH_DATA; 3811 } 3812 return VINF_SUCCESS; 3813 } 3814 3815 3816 /** 3817 * @callback_method_impl{FNDBGCCMD, The 'eb'\, 'ew'\, 'ed' and 'eq' commands.} 3818 */ 3819 static DECLCALLBACK(int) dbgcCmdEditMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 3820 { 3821 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3822 unsigned iArg; 3823 3824 /* 3825 * Validate input. 3826 */ 3827 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2); 3828 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, DBGCVAR_ISPOINTER(paArgs[0].enmType)); 3829 for (iArg = 1; iArg < cArgs; iArg++) 3830 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER); 3831 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM); 3832 3833 /* 3834 * Figure out the element size. 3835 */ 3836 unsigned cbElement; 3837 switch (pCmd->pszCmd[1]) 3838 { 3839 default: 3840 case 'b': cbElement = 1; break; 3841 case 'w': cbElement = 2; break; 3842 case 'd': cbElement = 4; break; 3843 case 'q': cbElement = 8; break; 3844 } 3845 3846 /* 3847 * Do setting. 3848 */ 3849 DBGCVAR Addr = paArgs[0]; 3850 for (iArg = 1;;) 3851 { 3852 size_t cbWritten; 3853 int rc = pCmdHlp->pfnMemWrite(pCmdHlp, &paArgs[iArg].u, cbElement, &Addr, &cbWritten); 3854 if (RT_FAILURE(rc)) 3855 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Writing memory at %DV.\n", &Addr); 3856 if (cbWritten != cbElement) 3857 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Only wrote %u out of %u bytes!\n", cbWritten, cbElement); 3858 3859 /* advance. */ 3860 iArg++; 3861 if (iArg >= cArgs) 3862 break; 3863 rc = DBGCCmdHlpEval(pCmdHlp, &Addr, "%Dv + %#x", &Addr, cbElement); 3864 if (RT_FAILURE(rc)) 3865 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]); 3866 } 3867 3868 return VINF_SUCCESS; 3869 } 3870 3871 3872 /** 3873 * Executes the search. 3874 * 3875 * @returns VBox status code. 3876 * @param pCmdHlp The command helpers. 3877 * @param pUVM The user mode VM handle. 3878 * @param pAddress The address to start searching from. (undefined on output) 3879 * @param cbRange The address range to search. Must not wrap. 3880 * @param pabBytes The byte pattern to search for. 3881 * @param cbBytes The size of the pattern. 3882 * @param cbUnit The search unit. 3883 * @param cMaxHits The max number of hits. 3884 * @param pResult Where to store the result if it's a function invocation. 3885 */ 3886 static int dbgcCmdWorkerSearchMemDoIt(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR cbRange, 3887 const uint8_t *pabBytes, uint32_t cbBytes, 3888 uint32_t cbUnit, uint64_t cMaxHits, PDBGCVAR pResult) 3889 { 3890 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3891 3892 /* 3893 * Do the search. 3894 */ 3895 uint64_t cHits = 0; 3896 for (;;) 3897 { 3898 /* search */ 3899 DBGFADDRESS HitAddress; 3900 int rc = DBGFR3MemScan(pUVM, pDbgc->idCpu, pAddress, cbRange, 1, pabBytes, cbBytes, &HitAddress); 3901 if (RT_FAILURE(rc)) 3902 { 3903 if (rc != VERR_DBGF_MEM_NOT_FOUND) 3904 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3MemScan\n"); 3905 3906 /* update the current address so we can save it (later). */ 3907 pAddress->off += cbRange; 3908 pAddress->FlatPtr += cbRange; 3909 cbRange = 0; 3910 break; 3911 } 3912 3913 /* report result */ 3914 DBGCVAR VarCur; 3915 rc = DBGCCmdHlpVarFromDbgfAddr(pCmdHlp, &HitAddress, &VarCur); 3916 if (RT_FAILURE(rc)) 3917 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGCCmdHlpVarFromDbgfAddr\n"); 3918 if (!pResult) 3919 pCmdHlp->pfnExec(pCmdHlp, "db %DV LB 10", &VarCur); 3920 else 3921 DBGCVAR_ASSIGN(pResult, &VarCur); 3922 3923 /* advance */ 3924 cbRange -= HitAddress.FlatPtr - pAddress->FlatPtr; 3925 *pAddress = HitAddress; 3926 pAddress->FlatPtr += cbBytes; 3927 pAddress->off += cbBytes; 3928 if (cbRange <= cbBytes) 3929 { 3930 cbRange = 0; 3931 break; 3932 } 3933 cbRange -= cbBytes; 3934 3935 if (++cHits >= cMaxHits) 3936 { 3937 /// @todo save the search. 3938 break; 3939 } 3940 } 3941 3942 /* 3943 * Save the search so we can resume it... 3944 */ 3945 if (pDbgc->abSearch != pabBytes) 3946 { 3947 memcpy(pDbgc->abSearch, pabBytes, cbBytes); 3948 pDbgc->cbSearch = cbBytes; 3949 pDbgc->cbSearchUnit = cbUnit; 3950 } 3951 pDbgc->cMaxSearchHits = cMaxHits; 3952 pDbgc->SearchAddr = *pAddress; 3953 pDbgc->cbSearchRange = cbRange; 3954 3955 return cHits ? VINF_SUCCESS : VERR_DBGC_COMMAND_FAILED; 3956 } 3957 3958 3959 /** 3960 * Resumes the previous search. 3961 * 3962 * @returns VBox status code. 3963 * @param pCmdHlp Pointer to the command helper functions. 3964 * @param pUVM The user mode VM handle. 3965 * @param pResult Where to store the result of a function invocation. 3966 */ 3967 static int dbgcCmdWorkerSearchMemResume(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGCVAR pResult) 3968 { 3969 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 3970 3971 /* 3972 * Make sure there is a previous command. 3973 */ 3974 if (!pDbgc->cbSearch) 3975 { 3976 DBGCCmdHlpPrintf(pCmdHlp, "Error: No previous search\n"); 3977 return VERR_DBGC_COMMAND_FAILED; 3978 } 3979 3980 /* 3981 * Make range and address adjustments. 3982 */ 3983 DBGFADDRESS Address = pDbgc->SearchAddr; 3984 if (Address.FlatPtr == ~(RTGCUINTPTR)0) 3985 { 3986 Address.FlatPtr -= Address.off; 3987 Address.off = 0; 3988 } 3989 3990 RTGCUINTPTR cbRange = pDbgc->cbSearchRange; 3991 if (!cbRange) 3992 cbRange = ~(RTGCUINTPTR)0; 3993 if (Address.FlatPtr + cbRange < pDbgc->SearchAddr.FlatPtr) 3994 cbRange = ~(RTGCUINTPTR)0 - pDbgc->SearchAddr.FlatPtr + !!pDbgc->SearchAddr.FlatPtr; 3995 3996 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, pDbgc->abSearch, pDbgc->cbSearch, 3997 pDbgc->cbSearchUnit, pDbgc->cMaxSearchHits, pResult); 3998 } 3999 4000 4001 /** 4002 * Search memory, worker for the 's' and 's?' functions. 4003 * 4004 * @returns VBox status code. 4005 * @param pCmdHlp Pointer to the command helper functions. 4006 * @param pUVM The user mode VM handle. 4007 * @param pAddress Where to start searching. If no range, search till end of address space. 4008 * @param cMaxHits The maximum number of hits. 4009 * @param chType The search type. 4010 * @param paPatArgs The pattern variable array. 4011 * @param cPatArgs Number of pattern variables. 4012 * @param pResult Where to store the result of a function invocation. 4013 */ 4014 static int dbgcCmdWorkerSearchMem(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR pAddress, uint64_t cMaxHits, char chType, 4015 PCDBGCVAR paPatArgs, unsigned cPatArgs, PDBGCVAR pResult) 4016 { 4017 if (pResult) 4018 DBGCVAR_INIT_GC_FLAT(pResult, 0); 4019 4020 /* 4021 * Convert the search pattern into bytes and DBGFR3MemScan can deal with. 4022 */ 4023 uint32_t cbUnit; 4024 switch (chType) 4025 { 4026 case 'a': 4027 case 'b': cbUnit = 1; break; 4028 case 'u': cbUnit = 2 | RT_BIT_32(31); break; 4029 case 'w': cbUnit = 2; break; 4030 case 'd': cbUnit = 4; break; 4031 case 'q': cbUnit = 8; break; 4032 default: 4033 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "chType=%c\n", chType); 4034 } 4035 uint8_t abBytes[RT_SIZEOFMEMB(DBGC, abSearch)]; 4036 uint32_t cbBytes = sizeof(abBytes); 4037 int rc = dbgcVarsToBytes(pCmdHlp, abBytes, &cbBytes, cbUnit, paPatArgs, cPatArgs); 4038 if (RT_FAILURE(rc)) 4039 return VERR_DBGC_COMMAND_FAILED; 4040 4041 /* 4042 * Make DBGF address and fix the range. 4043 */ 4044 DBGFADDRESS Address; 4045 rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pAddress, &Address); 4046 if (RT_FAILURE(rc)) 4047 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "VarToDbgfAddr(,%Dv,)\n", pAddress); 4048 4049 RTGCUINTPTR cbRange; 4050 switch (pAddress->enmRangeType) 4051 { 4052 case DBGCVAR_RANGE_BYTES: 4053 cbRange = pAddress->u64Range; 4054 if (cbRange != pAddress->u64Range) 4055 cbRange = ~(RTGCUINTPTR)0; 4056 break; 4057 4058 case DBGCVAR_RANGE_ELEMENTS: 4059 cbRange = (RTGCUINTPTR)(pAddress->u64Range * cbUnit); 4060 if ( cbRange != pAddress->u64Range * cbUnit 4061 || cbRange < pAddress->u64Range) 4062 cbRange = ~(RTGCUINTPTR)0; 4063 break; 4064 4065 default: 4066 cbRange = ~(RTGCUINTPTR)0; 4067 break; 4068 } 4069 if (Address.FlatPtr + cbRange < Address.FlatPtr) 4070 cbRange = ~(RTGCUINTPTR)0 - Address.FlatPtr + !!Address.FlatPtr; 4071 4072 /* 4073 * Ok, do it. 4074 */ 4075 return dbgcCmdWorkerSearchMemDoIt(pCmdHlp, pUVM, &Address, cbRange, abBytes, cbBytes, cbUnit, cMaxHits, pResult); 4076 } 4077 4078 4079 /** 4080 * @callback_method_impl{FNDBGCCMD, The 's' command.} 4081 */ 4082 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 4083 { 4084 /* check that the parser did what it's supposed to do. */ 4085 //if ( cArgs <= 2 4086 // && paArgs[0].enmType != DBGCVAR_TYPE_STRING) 4087 // return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n"); 4088 4089 /* 4090 * Repeat previous search? 4091 */ 4092 if (cArgs == 0) 4093 return dbgcCmdWorkerSearchMemResume(pCmdHlp, pUVM, NULL); 4094 4095 /* 4096 * Parse arguments. 4097 */ 4098 4099 return -1; 4100 } 4101 4102 4103 /** 4104 * @callback_method_impl{FNDBGCCMD, The 's?' command.} 4105 */ 4106 static DECLCALLBACK(int) dbgcCmdSearchMemType(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 4107 { 4108 /* check that the parser did what it's supposed to do. */ 4109 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, 0, cArgs >= 2 && DBGCVAR_ISGCPOINTER(paArgs[0].enmType)); 4110 return dbgcCmdWorkerSearchMem(pCmdHlp, pUVM, &paArgs[0], 25, pCmd->pszCmd[1], paArgs + 1, cArgs - 1, NULL); 4111 } 4112 4113 4114 /** 4115 * Matching function for interrupts event names. 4116 * 4117 * This parses the interrupt number and length. 4118 * 4119 * @returns True if match, false if not. 4120 * @param pPattern The user specified pattern to match. 4121 * @param pszEvtName The event name. 4122 * @param pCmdHlp Command helpers for warning about malformed stuff. 4123 * @param piFirst Where to return start interrupt number on success. 4124 * @param pcInts Where to return the number of interrupts on success. 4125 */ 4126 static bool dbgcEventIsMatchingInt(PCDBGCVAR pPattern, const char *pszEvtName, PDBGCCMDHLP pCmdHlp, 4127 uint8_t *piFirst, uint16_t *pcInts) 4128 { 4129 /* 4130 * Ignore trailing hex digits when comparing with the event base name. 4131 */ 4132 const char *pszPattern = pPattern->u.pszString; 4133 const char *pszEnd = RTStrEnd(pszPattern, RTSTR_MAX); 4134 while ( (uintptr_t)pszEnd > (uintptr_t)pszPattern 4135 && RT_C_IS_XDIGIT(pszEnd[-1])) 4136 pszEnd -= 1; 4137 if (RTStrSimplePatternNMatch(pszPattern, pszEnd - pszPattern, pszEvtName, RTSTR_MAX)) 4138 { 4139 /* 4140 * Parse the index and length. 4141 */ 4142 if (!*pszEnd) 4143 *piFirst = 0; 4144 else 4145 { 4146 int rc = RTStrToUInt8Full(pszEnd, 16, piFirst); 4147 if (rc != VINF_SUCCESS) 4148 { 4149 if (RT_FAILURE(rc)) 4150 *piFirst = 0; 4151 DBGCCmdHlpPrintf(pCmdHlp, "Warning: %Rrc parsing '%s' - interpreting it as %#x\n", rc, pszEnd, *piFirst); 4152 } 4153 } 4154 4155 if (pPattern->enmRangeType == DBGCVAR_RANGE_NONE) 4156 *pcInts = 1; 4157 else 4158 *pcInts = RT_MIN(RT_MAX(pPattern->u64Range, 256 - *piFirst), 1); 4159 return true; 4160 } 4161 return false; 4162 } 4163 4164 4165 /** 4166 * Updates a DBGC event config. 4167 * 4168 * @returns VINF_SUCCESS or VERR_NO_MEMORY. 4169 * @param ppEvtCfg The event configuration entry to update. 4170 * @param pszCmd The new command. Leave command alone if NULL. 4171 * @param enmEvtState The new event state. 4172 * @param fChangeCmdOnly Whether to only update the command. 4173 */ 4174 static int dbgcEventUpdate(PDBGCEVTCFG *ppEvtCfg, const char *pszCmd, DBGCEVTSTATE enmEvtState, bool fChangeCmdOnly) 4175 { 4176 PDBGCEVTCFG pEvtCfg = *ppEvtCfg; 4177 4178 /* 4179 * If we've got a command string, update the command too. 4180 */ 4181 if (pszCmd) 4182 { 4183 size_t cchCmd = strlen(pszCmd); 4184 if ( !cchCmd 4185 && ( !fChangeCmdOnly 4186 ? enmEvtState == kDbgcEvtState_Disabled 4187 : !pEvtCfg || pEvtCfg->enmState == kDbgcEvtState_Disabled)) 4188 { 4189 /* NULL entry is fine if no command and disabled. */ 4190 RTMemFree(pEvtCfg); 4191 *ppEvtCfg = NULL; 4192 } 4193 else 4194 { 4195 if (!pEvtCfg || pEvtCfg->cchCmd < cchCmd) 4196 { 4197 RTMemFree(pEvtCfg); 4198 *ppEvtCfg = pEvtCfg = (PDBGCEVTCFG)RTMemAlloc(RT_OFFSETOF(DBGCEVTCFG, szCmd[cchCmd + 1])); 4199 if (!pEvtCfg) 4200 return VERR_NO_MEMORY; 4201 } 4202 pEvtCfg->enmState = enmEvtState; 4203 pEvtCfg->cchCmd = cchCmd; 4204 memcpy(pEvtCfg->szCmd, pszCmd, cchCmd + 1); 4205 } 4206 } 4207 /* 4208 * Update existing or enable new. If NULL and not enabled, we can keep it that way. 4209 */ 4210 else if (pEvtCfg || enmEvtState != kDbgcEvtState_Disabled) 4211 { 4212 if (!pEvtCfg) 4213 { 4214 *ppEvtCfg = pEvtCfg = (PDBGCEVTCFG)RTMemAlloc(sizeof(DBGCEVTCFG)); 4215 if (!pEvtCfg) 4216 return VERR_NO_MEMORY; 4217 pEvtCfg->cchCmd = 0; 4218 pEvtCfg->szCmd[0] = '\0'; 4219 } 4220 pEvtCfg->enmState = enmEvtState; 4221 } 4222 4223 return VINF_SUCCESS; 4224 } 4225 4226 4227 /** 4228 * Record one settings change for a plain event. 4229 * 4230 * @returns The new @a cIntCfgs value. 4231 * @param paEventCfgs The event setttings array. Must have DBGFEVENT_END 4232 * entries. 4233 * @param cEventCfgs The current number of entries in @a paEventCfgs. 4234 * @param enmType The event to change the settings for. 4235 * @param enmEvtState The new event state. 4236 * @param iSxEvt Index into the g_aDbgcSxEvents array. 4237 * 4238 * @remarks We use abUnused[0] for the enmEvtState, while abUnused[1] and 4239 * abUnused[2] are used for iSxEvt. 4240 */ 4241 static uint32_t dbgcEventAddPlainConfig(PDBGFEVENTCONFIG paEventCfgs, uint32_t cEventCfgs, DBGFEVENTTYPE enmType, 4242 DBGCEVTSTATE enmEvtState, uint16_t iSxEvt) 4243 { 4244 uint32_t iCfg; 4245 for (iCfg = 0; iCfg < cEventCfgs; iCfg++) 4246 if (paEventCfgs[iCfg].enmType == enmType) 4247 break; 4248 if (iCfg == cEventCfgs) 4249 { 4250 Assert(cEventCfgs < DBGFEVENT_END); 4251 paEventCfgs[iCfg].enmType = enmType; 4252 cEventCfgs++; 4253 } 4254 paEventCfgs[iCfg].fEnabled = enmEvtState > kDbgcEvtState_Disabled; 4255 paEventCfgs[iCfg].abUnused[0] = enmEvtState; 4256 paEventCfgs[iCfg].abUnused[1] = (uint8_t)iSxEvt; 4257 paEventCfgs[iCfg].abUnused[2] = (uint8_t)(iSxEvt >> 8); 4258 return cEventCfgs; 4259 } 4260 4261 4262 /** 4263 * Record one or more interrupt event config changes. 4264 * 4265 * @returns The new @a cIntCfgs value. 4266 * @param paIntCfgs Interrupt confiruation array. Must have 256 entries. 4267 * @param cIntCfgs The current number of entries in @a paIntCfgs. 4268 * @param iInt The interrupt number to start with. 4269 * @param cInts The number of interrupts to change. 4270 * @param pszName The settings name (hwint/swint). 4271 * @param enmEvtState The new event state. 4272 * @param bIntOp The new DBGF interrupt state. 4273 */ 4274 static uint32_t dbgcEventAddIntConfig(PDBGFINTERRUPTCONFIG paIntCfgs, uint32_t cIntCfgs, uint8_t iInt, uint16_t cInts, 4275 const char *pszName, DBGCEVTSTATE enmEvtState, uint8_t bIntOp) 4276 { 4277 bool const fHwInt = *pszName == 'h'; 4278 4279 bIntOp |= (uint8_t)enmEvtState << 4; 4280 uint8_t const bSoftState = !fHwInt ? bIntOp : DBGFINTERRUPTSTATE_DONT_TOUCH; 4281 uint8_t const bHardState = fHwInt ? bIntOp : DBGFINTERRUPTSTATE_DONT_TOUCH; 4282 4283 while (cInts > 0) 4284 { 4285 uint32_t iCfg; 4286 for (iCfg = 0; iCfg < cIntCfgs; iCfg++) 4287 if (paIntCfgs[iCfg].iInterrupt == iInt) 4288 break; 4289 if (iCfg == cIntCfgs) 4290 break; 4291 if (fHwInt) 4292 paIntCfgs[iCfg].enmHardState = bHardState; 4293 else 4294 paIntCfgs[iCfg].enmSoftState = bSoftState; 4295 iInt++; 4296 cInts--; 4297 } 4298 4299 while (cInts > 0) 4300 { 4301 Assert(cIntCfgs < 256); 4302 paIntCfgs[cIntCfgs].iInterrupt = iInt; 4303 paIntCfgs[cIntCfgs].enmHardState = bHardState; 4304 paIntCfgs[cIntCfgs].enmSoftState = bSoftState; 4305 cIntCfgs++; 4306 iInt++; 4307 cInts--; 4308 } 4309 4310 return cIntCfgs; 4311 } 4312 4313 4314 /** 4315 * Applies event settings changes to DBGC and DBGF. 4316 * 4317 * @returns VBox status code (fully bitched) 4318 * @param pCmdHlp The command helpers. 4319 * @param pUVM The user mode VM handle. 4320 * @param paIntCfgs Interrupt configuration array. We use the upper 4 4321 * bits of the settings for the DBGCEVTSTATE. This 4322 * will be cleared. 4323 * @param cIntCfgs Number of interrupt configuration changes. 4324 * @param paEventCfgs The generic event configuration array. We use the 4325 * abUnused[0] member for the DBGCEVTSTATE, and 4326 * abUnused[2:1] for the g_aDbgcSxEvents index. 4327 * @param cEventCfgs The number of generic event settings changes. 4328 * @param pszCmd The commands to associate with the changed events. 4329 * If this is NULL, don't touch the command. 4330 * @param fChangeCmdOnly Whether to only change the commands (sx-). 4331 */ 4332 static int dbgcEventApplyChanges(PDBGCCMDHLP pCmdHlp, PUVM pUVM, PDBGFINTERRUPTCONFIG paIntCfgs, uint32_t cIntCfgs, 4333 PCDBGFEVENTCONFIG paEventCfgs, uint32_t cEventCfgs, const char *pszCmd, bool fChangeCmdOnly) 4334 { 4335 int rc; 4336 4337 /* 4338 * Apply changes to DBGC. This can only fail with out of memory error. 4339 */ 4340 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 4341 if (cIntCfgs) 4342 for (uint32_t iCfg = 0; iCfg < cIntCfgs; iCfg++) 4343 { 4344 DBGCEVTSTATE enmEvtState = (DBGCEVTSTATE)(paIntCfgs[iCfg].enmHardState >> 4); 4345 paIntCfgs[iCfg].enmHardState &= 0xf; 4346 if (paIntCfgs[iCfg].enmHardState != DBGFINTERRUPTSTATE_DONT_TOUCH) 4347 { 4348 rc = dbgcEventUpdate(&pDbgc->apHardInts[paIntCfgs[iCfg].iInterrupt], pszCmd, enmEvtState, fChangeCmdOnly); 4349 if (RT_FAILURE(rc)) 4350 return rc; 4351 } 4352 4353 enmEvtState = (DBGCEVTSTATE)(paIntCfgs[iCfg].enmSoftState >> 4); 4354 paIntCfgs[iCfg].enmSoftState &= 0xf; 4355 if (paIntCfgs[iCfg].enmSoftState != DBGFINTERRUPTSTATE_DONT_TOUCH) 4356 { 4357 rc = dbgcEventUpdate(&pDbgc->apSoftInts[paIntCfgs[iCfg].iInterrupt], pszCmd, enmEvtState, fChangeCmdOnly); 4358 if (RT_FAILURE(rc)) 4359 return rc; 4360 } 4361 } 4362 4363 if (cEventCfgs) 4364 { 4365 for (uint32_t iCfg = 0; iCfg < cEventCfgs; iCfg++) 4366 { 4367 Assert((unsigned)paEventCfgs[iCfg].enmType < RT_ELEMENTS(pDbgc->apEventCfgs)); 4368 uint16_t iSxEvt = RT_MAKE_U16(paEventCfgs[iCfg].abUnused[1], paEventCfgs[iCfg].abUnused[2]); 4369 Assert(iSxEvt < RT_ELEMENTS(g_aDbgcSxEvents)); 4370 rc = dbgcEventUpdate(&pDbgc->apEventCfgs[iSxEvt], pszCmd, (DBGCEVTSTATE)paEventCfgs[iCfg].abUnused[0], fChangeCmdOnly); 4371 if (RT_FAILURE(rc)) 4372 return rc; 4373 } 4374 } 4375 4376 /* 4377 * Apply changes to DBGF. 4378 */ 4379 if (false) /// @todo fix API if (!fChangeCmdOnly) 4380 { 4381 if (cIntCfgs) 4382 { 4383 rc = DBGFR3InterruptConfigEx(pUVM, paIntCfgs, cIntCfgs); 4384 if (RT_FAILURE(rc)) 4385 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3InterruptConfigEx: %Rrc\n", rc); 4386 } 4387 if (cEventCfgs) 4388 { 4389 rc = DBGFR3EventConfigEx(pUVM, paEventCfgs, cEventCfgs); 4390 if (RT_FAILURE(rc)) 4391 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3EventConfigEx: %Rrc\n", rc); 4392 } 4393 } 4394 4395 return VINF_SUCCESS; 4396 } 4117 4397 4118 4398 … … 4125 4405 * Figure out which command this is. 4126 4406 */ 4127 enum 4128 { 4129 kEventEnable, 4130 kEventNotify, 4131 kEventIgnore, 4132 kEventChangeCmd 4133 } enmSubOp; 4407 uint8_t bIntOp; 4408 DBGCEVTSTATE enmEvtState; 4409 bool fChangeCmdOnly; 4134 4410 switch (pCmd->pszCmd[2]) 4135 4411 { 4136 case 'e': enmSubOp = kEventEnable; break;4137 case 'n': enmSubOp = kEventNotify; break;4138 case '-': enmSubOp = kEventChangeCmd;break;4139 case 'i': enmSubOp = kEventIgnore; break;4412 case 'e': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Enabled; fChangeCmdOnly = false; break; 4413 case 'n': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Notify; fChangeCmdOnly = false; break; 4414 case '-': bIntOp = DBGFINTERRUPTSTATE_ENABLED; enmEvtState = kDbgcEvtState_Invalid; fChangeCmdOnly = true; break; 4415 case 'i': bIntOp = DBGFINTERRUPTSTATE_DISABLED; enmEvtState = kDbgcEvtState_Disabled; fChangeCmdOnly = false; break; 4140 4416 default: 4141 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "pszCmd=%s\n", pCmd->pszCmd);4417 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "pszCmd=%s\n", pCmd->pszCmd); 4142 4418 } 4143 4419 … … 4146 4422 */ 4147 4423 unsigned iArg = 0; 4148 const char *pszC ommand = NULL;4424 const char *pszCmd = NULL; 4149 4425 if ( cArgs >= iArg + 2 4150 4426 && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING … … 4152 4428 && strcmp(paArgs[iArg].u.pszString, "-c") == 0) 4153 4429 { 4154 pszC ommand = paArgs[iArg + 1].u.pszString;4430 pszCmd = paArgs[iArg + 1].u.pszString; 4155 4431 iArg += 2; 4156 if ( enmSubOp != kEventEnable 4157 && enmSubOp != kEventChangeCmd) 4158 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Only the 'sxe' and 'sxc' command takes '-c cmds'.\n"); 4159 } 4432 } 4433 if (fChangeCmdOnly && !pszCmd) 4434 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "The 'sx-' requires the '-c cmd' arguments.\n"); 4160 4435 4161 4436 /* 4162 4437 * The remaining arguments are event specifiers to which the operation should be applied. 4163 4438 */ 4439 uint32_t cIntCfgs = 0; 4440 DBGFINTERRUPTCONFIG aIntCfgs[256]; 4441 uint32_t cEventCfgs = 0; 4442 DBGFEVENTCONFIG aEventCfgs[DBGFEVENT_END]; 4443 4164 4444 for (; iArg < cArgs; iArg++) 4165 4445 { 4166 4446 DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, paArgs[iArg].enmType == DBGCVAR_TYPE_STRING 4167 4447 || paArgs[iArg].enmType == DBGCVAR_TYPE_SYMBOL); 4168 4448 uint32_t cHits = 0; 4449 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++) 4450 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain) 4451 { 4452 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName) 4453 || ( g_aDbgcSxEvents[iEvt].pszAltNm 4454 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) ) 4455 { 4456 cEventCfgs = dbgcEventAddPlainConfig(aEventCfgs, cEventCfgs, g_aDbgcSxEvents[iEvt].enmType, 4457 enmEvtState, iEvt); 4458 cHits++; 4459 } 4460 } 4461 else 4462 { 4463 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt); 4464 uint8_t iInt; 4465 uint16_t cInts; 4466 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts)) 4467 { 4468 cIntCfgs = dbgcEventAddIntConfig(aIntCfgs, cIntCfgs, iInt, cInts, g_aDbgcSxEvents[iEvt].pszName, 4469 enmEvtState, bIntOp); 4470 cHits++; 4471 } 4472 } 4473 if (!cHits) 4474 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString); 4475 } 4476 4477 /* 4478 * Apply the changes. 4479 */ 4480 return dbgcEventApplyChanges(pCmdHlp, pUVM, aIntCfgs, cIntCfgs, aEventCfgs, cEventCfgs, pszCmd, fChangeCmdOnly); 4481 } 4482 4483 4484 /** 4485 * @callback_method_impl{FNDBGCCMD, The 'sxr' commands.} 4486 */ 4487 static DECLCALLBACK(int) dbgcCmdEventCtrlReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 4488 { 4489 uint32_t cEventCfgs = 0; 4490 DBGFEVENTCONFIG aEventCfgs[DBGFEVENT_END]; 4491 uint32_t cIntCfgs = 0; 4492 DBGFINTERRUPTCONFIG aIntCfgs[256]; 4493 4494 if (cArgs == 0) 4495 { 4496 /* 4497 * All events. 4498 */ 4499 for (uint32_t iInt = 0; iInt < 256; iInt++) 4500 { 4501 aIntCfgs[iInt].iInterrupt = iInt; 4502 aIntCfgs[iInt].enmHardState = DBGFINTERRUPTSTATE_DONT_TOUCH; 4503 aIntCfgs[iInt].enmSoftState = DBGFINTERRUPTSTATE_DONT_TOUCH; 4504 } 4505 cIntCfgs = 256; 4506 4507 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++) 4508 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain) 4509 { 4510 aEventCfgs[cEventCfgs].enmType = g_aDbgcSxEvents[iEvt].enmType; 4511 aEventCfgs[cEventCfgs].fEnabled = g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled; 4512 aEventCfgs[cEventCfgs].abUnused[0] = g_aDbgcSxEvents[iEvt].enmDefault; 4513 aEventCfgs[cEventCfgs].abUnused[1] = (uint8_t)iEvt; 4514 aEventCfgs[cEventCfgs].abUnused[2] = (uint8_t)(iEvt >> 8); 4515 cEventCfgs++; 4516 } 4517 else 4518 { 4519 uint8_t const bState = ( g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled 4520 ? DBGFINTERRUPTSTATE_ENABLED : DBGFINTERRUPTSTATE_DISABLED) 4521 | ((uint8_t)g_aDbgcSxEvents[iEvt].enmDefault << 4); 4522 if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0) 4523 for (uint32_t iInt = 0; iInt < 256; iInt++) 4524 aIntCfgs[iInt].enmHardState = bState; 4525 else 4526 for (uint32_t iInt = 0; iInt < 256; iInt++) 4527 aIntCfgs[iInt].enmSoftState = bState; 4528 } 4529 } 4530 else 4531 { 4532 /* 4533 * Selected events. 4534 */ 4535 for (uint32_t iArg = 0; iArg < cArgs; iArg++) 4536 { 4537 unsigned cHits = 0; 4538 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++) 4539 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain) 4540 { 4541 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName) 4542 || ( g_aDbgcSxEvents[iEvt].pszAltNm 4543 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) ) 4544 { 4545 cEventCfgs = dbgcEventAddPlainConfig(aEventCfgs, cEventCfgs, g_aDbgcSxEvents[iEvt].enmType, 4546 g_aDbgcSxEvents[iEvt].enmDefault, iEvt); 4547 cHits++; 4548 } 4549 } 4550 else 4551 { 4552 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt); 4553 uint8_t iInt; 4554 uint16_t cInts; 4555 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts)) 4556 { 4557 cIntCfgs = dbgcEventAddIntConfig(aIntCfgs, cIntCfgs, iInt, cInts, g_aDbgcSxEvents[iEvt].pszName, 4558 g_aDbgcSxEvents[iEvt].enmDefault, 4559 g_aDbgcSxEvents[iEvt].enmDefault > kDbgcEvtState_Disabled 4560 ? DBGFINTERRUPTSTATE_ENABLED : DBGFINTERRUPTSTATE_DISABLED); 4561 cHits++; 4562 } 4563 } 4564 if (!cHits) 4565 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString); 4566 } 4567 } 4568 4569 /* 4570 * Apply the reset changes. 4571 */ 4572 return dbgcEventApplyChanges(pCmdHlp, pUVM, aIntCfgs, cIntCfgs, aEventCfgs, cEventCfgs, "", false); 4573 } 4574 4575 4576 /** 4577 * Used during DBGC initialization to configure events with defaults. 4578 * 4579 * @returns VBox status code. 4580 * @param pDbgc The DBGC instance. 4581 */ 4582 void dbgcEventInit(PDBGC pDbgc) 4583 { 4584 if (pDbgc->pUVM) 4585 dbgcCmdEventCtrlReset(NULL, &pDbgc->CmdHlp, pDbgc->pUVM, NULL, 0); 4586 } 4587 4588 4589 /** 4590 * Used during DBGC termination to disable all events. 4591 * 4592 * @param pDbgc The DBGC instance. 4593 */ 4594 void dbgcEventTerm(PDBGC pDbgc) 4595 { 4596 /** @todo need to do more than just reset later. */ 4597 if (pDbgc->pUVM) 4598 dbgcCmdEventCtrlReset(NULL, &pDbgc->CmdHlp, pDbgc->pUVM, NULL, 0); 4599 } 4600 4601 4602 static void dbgcEventDisplay(PDBGCCMDHLP pCmdHlp, const char *pszName, DBGCEVTSTATE enmDefault, PDBGCEVTCFG const *ppEvtCfg) 4603 { 4604 PDBGCEVTCFG pEvtCfg = *ppEvtCfg; 4605 4606 const char *pszState; 4607 switch (pEvtCfg ? pEvtCfg->enmState : kDbgcEvtState_Disabled) 4608 { 4609 case kDbgcEvtState_Disabled: pszState = "ignore"; break; 4610 case kDbgcEvtState_Enabled: pszState = "enabled"; break; 4611 case kDbgcEvtState_Notify: pszState = "notify"; break; 4612 default: 4613 AssertFailed(); 4614 pszState = "invalid"; 4615 break; 4616 } 4617 4618 if (pEvtCfg && pEvtCfg->cchCmd > 0) 4619 DBGCCmdHlpPrintf(pCmdHlp, "%-18s %-7s \"%s\"\n", pszName, pszState, pEvtCfg->szCmd); 4620 else 4621 DBGCCmdHlpPrintf(pCmdHlp, "%-18s %s\n", pszName, pszState); 4622 } 4623 4624 4625 static void dbgcEventDisplayRange(PDBGCCMDHLP pCmdHlp, const char *pszBaseNm, DBGCEVTSTATE enmDefault, 4626 PDBGCEVTCFG const *papEvtCfgs, unsigned iCfg, unsigned cCfgs) 4627 { 4628 do 4629 { 4630 PCDBGCEVTCFG pFirstCfg = papEvtCfgs[iCfg]; 4631 if (pFirstCfg && pFirstCfg->enmState == kDbgcEvtState_Disabled && pFirstCfg->cchCmd == 0) 4632 pFirstCfg = NULL; 4633 4634 unsigned const iFirstCfg = iCfg; 4635 iCfg++; 4636 while (iCfg < cCfgs) 4637 { 4638 PCDBGCEVTCFG pCurCfg = papEvtCfgs[iCfg]; 4639 if (pCurCfg && pCurCfg->enmState == kDbgcEvtState_Disabled && pCurCfg->cchCmd == 0) 4640 pCurCfg = NULL; 4641 if (pCurCfg != pFirstCfg) 4642 { 4643 if (!pCurCfg || !pFirstCfg) 4644 break; 4645 if (pCurCfg->enmState != pFirstCfg->enmState) 4646 break; 4647 if (pCurCfg->cchCmd != pFirstCfg->cchCmd) 4648 break; 4649 if (memcmp(pCurCfg->szCmd, pFirstCfg->szCmd, pFirstCfg->cchCmd) != 0) 4650 break; 4651 } 4652 iCfg++; 4653 } 4654 4655 char szName[16]; 4656 unsigned cEntries = iCfg - iFirstCfg; 4657 if (cEntries == 1) 4658 RTStrPrintf(szName, sizeof(szName), "%s%02x", pszBaseNm, iFirstCfg); 4659 else 4660 RTStrPrintf(szName, sizeof(szName), "%s%02x L %#x", pszBaseNm, iFirstCfg, cEntries); 4661 dbgcEventDisplay(pCmdHlp, szName, enmDefault, &papEvtCfgs[iFirstCfg]); 4662 4663 cCfgs -= cEntries; 4664 } while (cCfgs > 0); 4665 } 4666 4667 4668 /** 4669 * @callback_method_impl{FNDBGCCMD, The 'sx' commands.} 4670 */ 4671 static DECLCALLBACK(int) dbgcCmdEventCtrlList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs) 4672 { 4673 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 4674 4675 if (cArgs == 0) 4676 { 4677 /* 4678 * All events. 4679 */ 4680 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++) 4681 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain) 4682 dbgcEventDisplay(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4683 &pDbgc->apEventCfgs[iEvt]); 4684 else if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0) 4685 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4686 pDbgc->apHardInts, 0, 256); 4687 else 4688 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4689 pDbgc->apSoftInts, 0, 256); 4690 } 4691 else 4692 { 4693 /* 4694 * Selected events. 4695 */ 4696 for (uint32_t iArg = 0; iArg < cArgs; iArg++) 4697 { 4698 unsigned cHits = 0; 4699 for (uint32_t iEvt = 0; iEvt < RT_ELEMENTS(g_aDbgcSxEvents); iEvt++) 4700 if (g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Plain) 4701 { 4702 if ( RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszName) 4703 || ( g_aDbgcSxEvents[iEvt].pszAltNm 4704 && RTStrSimplePatternMatch(paArgs[iArg].u.pszString, g_aDbgcSxEvents[iEvt].pszAltNm)) ) 4705 { 4706 dbgcEventDisplay(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4707 &pDbgc->apEventCfgs[iEvt]); 4708 cHits++; 4709 } 4710 } 4711 else 4712 { 4713 Assert(g_aDbgcSxEvents[iEvt].enmKind == kDbgcSxEventKind_Interrupt); 4714 uint8_t iInt; 4715 uint16_t cInts; 4716 if (dbgcEventIsMatchingInt(&paArgs[iArg], g_aDbgcSxEvents[iEvt].pszName, pCmdHlp, &iInt, &cInts)) 4717 { 4718 if (strcmp(g_aDbgcSxEvents[iEvt].pszName, "hwint") == 0) 4719 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4720 pDbgc->apHardInts, iInt, cInts); 4721 else 4722 dbgcEventDisplayRange(pCmdHlp, g_aDbgcSxEvents[iEvt].pszName, g_aDbgcSxEvents[iEvt].enmDefault, 4723 pDbgc->apSoftInts, iInt, cInts); 4724 cHits++; 4725 } 4726 } 4727 if (cHits == 0) 4728 return DBGCCmdHlpVBoxError(pCmdHlp, VERR_INVALID_PARAMETER, "Unknown event: '%s'\n", paArgs[iArg].u.pszString); 4729 } 4169 4730 } 4170 4731 4171 4732 return VINF_SUCCESS; 4172 }4173 4174 4175 /**4176 * @callback_method_impl{FNDBGCCMD, The 'sx' commands.}4177 */4178 static DECLCALLBACK(int) dbgcCmdEventCtrlList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)4179 {4180 return VERR_NOT_IMPLEMENTED;4181 }4182 4183 4184 /**4185 * @callback_method_impl{FNDBGCCMD, The 'sxr' commands.}4186 */4187 static DECLCALLBACK(int) dbgcCmdEventCtrlReset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)4188 {4189 return VERR_NOT_IMPLEMENTED;4190 4733 } 4191 4734 -
trunk/src/VBox/Debugger/DBGCInternal.h
r55881 r59072 48 48 /** Pointer to a breakpoint. */ 49 49 typedef DBGCBP *PDBGCBP; 50 51 52 typedef enum DBGCEVTSTATE 53 { 54 kDbgcEvtState_Invalid = 0, 55 kDbgcEvtState_Disabled, 56 kDbgcEvtState_Enabled, 57 kDbgcEvtState_Notify 58 } DBGCEVTSTATE; 59 60 /** 61 * Debugger console per event configuration. 62 */ 63 typedef struct DBGCEVTCFG 64 { 65 /** The event state. */ 66 DBGCEVTSTATE enmState; 67 /** The size of the command. */ 68 size_t cchCmd; 69 /** The command to execute when the event occurs. */ 70 char szCmd[1]; 71 } DBGCEVTCFG; 72 /** Pointer to a event configuration. */ 73 typedef DBGCEVTCFG *PDBGCEVTCFG; 74 /** Pointer to a const event configuration. */ 75 typedef DBGCEVTCFG const *PCDBGCEVTCFG; 50 76 51 77 … … 140 166 /** The list of breakpoints. (singly linked) */ 141 167 PDBGCBP pFirstBp; 168 169 /** Software interrupt events. */ 170 PDBGCEVTCFG apSoftInts[256]; 171 /** Hardware interrupt events. */ 172 PDBGCEVTCFG apHardInts[256]; 173 /** Selectable events (first few entries are unused). */ 174 PDBGCEVTCFG apEventCfgs[DBGFEVENT_END]; 142 175 143 176 /** Save search pattern. */ … … 347 380 348 381 382 /** Selectable debug event kind. */ 383 typedef enum 384 { 385 kDbgcSxEventKind_Plain, 386 kDbgcSxEventKind_Interrupt 387 } DBGCSXEVENTKIND; 388 389 /** 390 * Selectable debug event name / type lookup table entry. 391 * 392 * This also contains the default setting and an alternative name. 393 */ 394 typedef struct DBGCSXEVT 395 { 396 DBGFEVENTTYPE enmType; 397 const char *pszName; 398 const char *pszAltNm; 399 DBGCSXEVENTKIND enmKind; 400 DBGCEVTSTATE enmDefault; 401 } DBGCSXEVT; 402 /** Pointer to a constant selectable debug event descriptor. */ 403 typedef DBGCSXEVT const *PCDBGCSXEVT; 404 405 349 406 /******************************************************************************* 350 407 * Internal Functions * … … 373 430 374 431 void dbgcInitCmdHlp(PDBGC pDbgc); 432 433 void dbgcEventInit(PDBGC pDbgc); 434 void dbgcEventTerm(PDBGC pDbgc); 435 375 436 376 437 /* For tstDBGCParser: */ … … 394 455 extern const DBGCOP g_aDbgcOps[]; 395 456 extern const uint32_t g_cDbgcOps; 457 extern const DBGCSXEVT g_aDbgcSxEvents[]; 458 extern const uint32_t g_cDbgcSxEvents; 396 459 397 460 -
trunk/src/VBox/Debugger/DBGConsole.cpp
r58909 r59072 1056 1056 if (pVM) 1057 1057 DBGFR3PlugInLoadAll(pDbgc->pUVM); 1058 dbgcEventInit(pDbgc); 1059 1058 1060 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> "); 1059 1061 if (RT_SUCCESS(rc)) … … 1092 1094 } 1093 1095 } 1096 dbgcEventTerm(pDbgc); 1094 1097 } 1095 1098 else -
trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp
r56296 r59072 98 98 return VERR_INTERNAL_ERROR; 99 99 } 100 VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs) 101 { 102 return VERR_INTERNAL_ERROR; 103 } 104 VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs) 105 { 106 return VERR_INTERNAL_ERROR; 107 } 108 100 109 VMMR3DECL(int) DBGFR3Halt(PUVM pUVM) 101 110 {
注意:
瀏覽 TracChangeset
來幫助您使用更動檢視器