VirtualBox

vbox的更動 59072 路徑 trunk/src/VBox/Debugger


忽略:
時間撮記:
2015-12-9 下午10:58:30 (9 年 以前)
作者:
vboxsync
訊息:

DBGC: Implemented the DBGC side of the sx* commands. (DBGF isn't quite there yet.)

位置:
trunk/src/VBox/Debugger
檔案:
修改 4 筆資料

圖例:

未更動
新增
刪除
  • trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp

    r59062 r59072  
    288288    {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "-c",           "The -c option, requires <cmds>." },
    289289    {  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." },
    291291};
    292292
     
    382382    { "su",         2,       ~0U,       &g_aArgSearchMemType[0], RT_ELEMENTS(g_aArgSearchMemType),0, dbgcCmdSearchMemType, "<range> <pattern>",  "Search memory for an unicode string." },
    383383    { "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." },
    389389    { "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." },
    390390    { "t",          0,        0,        NULL,               0,                              0,       dbgcCmdTrace,       "",                     "Instruction trace (step into)." },
     
    400400
    401401
    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.
    663404 *
    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 */
     407const 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 },
    4004445#if 0 /** @todo later */
    4005446    { DBGFEVENT_INSTR_MWAIT,                "",
     
    4115556#endif
    4116557};
     558/** Number of entries in g_aDbgcSxEvents.  */
     559const uint32_t   g_cDbgcSxEvents = RT_ELEMENTS(g_aDbgcSxEvents);
     560
     561
     562
     563/**
     564 * @callback_method_impl{FNDBGCCMD, The 'go' command.}
     565 */
     566static 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 */
     588static 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 */
     685static 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 */
     737static 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 */
     779static 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 */
     828static 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 */
     946static 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 */
     966static 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 */
     1026static 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 */
     1093static 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 */
     1127static 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 */
     1350static 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 */
     1539static 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 */
     1552static 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 */
     1660static 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 */
     1760static 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 */
     1810static 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 */
     1823static 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 */
     1841static 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
     1943static 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 */
     2091static 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 */
     2236static 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 */
     2349static 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 */
     2464static 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 */
     2658static 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 */
     2689static 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 */
     2725static 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 */
     2978static 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 */
     2993static 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 */
     3109static 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 */
     3330static 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 */
     3345static 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 */
     3671static 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 */
     3695int 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 */
     3819static 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 */
     3886static 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 */
     3967static 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 */
     4014static 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 */
     4082static 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 */
     4106static 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 */
     4126static 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 */
     4174static 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 */
     4241static 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 */
     4274static 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 */
     4332static 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}
    41174397
    41184398
     
    41254405     * Figure out which command this is.
    41264406     */
    4127     enum
    4128     {
    4129         kEventEnable,
    4130         kEventNotify,
    4131         kEventIgnore,
    4132         kEventChangeCmd
    4133     } enmSubOp;
     4407    uint8_t         bIntOp;
     4408    DBGCEVTSTATE    enmEvtState;
     4409    bool            fChangeCmdOnly;
    41344410    switch (pCmd->pszCmd[2])
    41354411    {
    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;
    41404416        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);
    41424418    }
    41434419
     
    41464422     */
    41474423    unsigned    iArg = 0;
    4148     const char *pszCommand = NULL;
     4424    const char *pszCmd = NULL;
    41494425    if (   cArgs >= iArg + 2
    41504426        && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING
     
    41524428        && strcmp(paArgs[iArg].u.pszString, "-c") == 0)
    41534429    {
    4154         pszCommand = paArgs[iArg + 1].u.pszString;
     4430        pszCmd = paArgs[iArg + 1].u.pszString;
    41554431        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");
    41604435
    41614436    /*
    41624437     * The remaining arguments are event specifiers to which the operation should be applied.
    41634438     */
     4439    uint32_t            cIntCfgs   = 0;
     4440    DBGFINTERRUPTCONFIG aIntCfgs[256];
     4441    uint32_t            cEventCfgs = 0;
     4442    DBGFEVENTCONFIG     aEventCfgs[DBGFEVENT_END];
     4443
    41644444    for (; iArg < cArgs; iArg++)
    41654445    {
    41664446        DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, paArgs[iArg].enmType == DBGCVAR_TYPE_STRING
    41674447                                                        || 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 */
     4487static 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 */
     4582void 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 */
     4594void 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
     4602static 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
     4625static 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 */
     4671static 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        }
    41694730    }
    41704731
    41714732    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;
    41904733}
    41914734
  • trunk/src/VBox/Debugger/DBGCInternal.h

    r55881 r59072  
    4848/** Pointer to a breakpoint. */
    4949typedef DBGCBP *PDBGCBP;
     50
     51
     52typedef 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 */
     63typedef 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. */
     73typedef DBGCEVTCFG *PDBGCEVTCFG;
     74/** Pointer to a const event configuration. */
     75typedef DBGCEVTCFG const *PCDBGCEVTCFG;
    5076
    5177
     
    140166    /** The list of breakpoints. (singly linked) */
    141167    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];
    142175
    143176    /** Save search pattern. */
     
    347380
    348381
     382/** Selectable debug event kind. */
     383typedef 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 */
     394typedef 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. */
     403typedef DBGCSXEVT const *PCDBGCSXEVT;
     404
     405
    349406/*******************************************************************************
    350407*   Internal Functions                                                         *
     
    373430
    374431void    dbgcInitCmdHlp(PDBGC pDbgc);
     432
     433void    dbgcEventInit(PDBGC pDbgc);
     434void    dbgcEventTerm(PDBGC pDbgc);
     435
    375436
    376437/* For tstDBGCParser: */
     
    394455extern const DBGCOP     g_aDbgcOps[];
    395456extern const uint32_t   g_cDbgcOps;
     457extern const DBGCSXEVT  g_aDbgcSxEvents[];
     458extern const uint32_t   g_cDbgcSxEvents;
    396459
    397460
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r58909 r59072  
    10561056        if (pVM)
    10571057            DBGFR3PlugInLoadAll(pDbgc->pUVM);
     1058        dbgcEventInit(pDbgc);
     1059
    10581060        rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    10591061        if (RT_SUCCESS(rc))
     
    10921094            }
    10931095        }
     1096        dbgcEventTerm(pDbgc);
    10941097    }
    10951098    else
  • trunk/src/VBox/Debugger/testcase/tstDBGCStubs.cpp

    r56296 r59072  
    9898    return VERR_INTERNAL_ERROR;
    9999}
     100VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs)
     101{
     102    return VERR_INTERNAL_ERROR;
     103}
     104VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs)
     105{
     106    return VERR_INTERNAL_ERROR;
     107}
     108
    100109VMMR3DECL(int) DBGFR3Halt(PUVM pUVM)
    101110{
注意: 瀏覽 TracChangeset 來幫助您使用更動檢視器

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette