VirtualBox

Changeset 5668 in vbox


Ignore:
Timestamp:
Nov 11, 2007 4:36:28 AM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
26012
Message:

Split out the core structures, defines and stuff into DBGCInternal.h

Location:
trunk/src/VBox/Debugger
Files:
1 edited
1 copied

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGCInternal.h

    r5666 r5668  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Internal Header File.
    44 */
    55
     
    1616 */
    1717
    18 
    19 /** @page pg_dbgc                       DBGC - The Debug Console
    20  *
    21  * The debugger console is a first attempt to make some interactive
    22  * debugging facilities for the VirtualBox backend (i.e. the VM). At a later
    23  * stage we'll make a fancy gui around this, but for the present a telnet (or
    24  * serial terminal) will have to suffice.
    25  *
    26  * The debugger is only built into the VM with debug builds or when
    27  * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this
    28  * define to enable special debugger hooks, but the general approach is to
    29  * make generic interfaces. The individual components also can register
    30  * external commands, and such code must be within \#ifdef.
    31  *
    32  *
    33  * @section sec_dbgc_op                 Operation (intentions)
    34  *
    35  * The console will process commands in a manner similar to the OS/2 and
    36  * windows kernel debuggers. This means ';' is a command separator and
    37  * that when possible we'll use the same command names as these two uses.
    38  *
    39  *
    40  * @subsection sec_dbg_op_numbers       Numbers
    41  *
    42  * Numbers are hexadecimal unless specified with a prefix indicating
    43  * elsewise. Prefixes:
    44  *      - '0x' - hexadecimal.
    45  *      - '0i' - decimal
    46  *      - '0t' - octal.
    47  *      - '0y' - binary.
    48  *
    49  *
    50  * @subsection sec_dbg_op_address       Addressing modes
    51  *
    52  *      - Default is flat. For compatability '%' also means flat.
    53  *      - Segmented addresses are specified selector:offset.
    54  *      - Physical addresses are specified using '%%'.
    55  *      - The default target for the addressing is the guest context, the '#'
    56  *        will override this and set it to the host.
    57  *
    58  *
    59  * @subsection sec_dbg_op_evalution     Evaluation
    60  *
    61  * As time permits support will be implemented support for a subset of the C
    62  * binary operators, starting with '+', '-', '*' and '/'. Support for variables
    63  * are provided thru commands 'set' and 'unset' and the unary operator '$'. The
    64  * unary '@' operator will indicate function calls. The debugger needs a set of
    65  * memory read functions, but we might later extend this to allow registration of
    66  * external functions too.
    67  *
    68  * A special command '?' will then be added which evalutates a given expression
    69  * and prints it in all the different formats.
    70  *
    71  *
    72  * @subsection sec_dbg_op_registers     Registers
    73  *
    74  * Registers are addressed using their name. Some registers which have several fields
    75  * (like gdtr) will have separate names indicating the different fields. The default
    76  * register set is the guest one. To access the hypervisor register one have to
    77  * prefix the register names with '.'.
    78  *
    79  *
    80  * @subsection sec_dbg_op_commands      Commands
    81  *
    82  * The commands are all lowercase, case sensitive, and starting with a letter. We will
    83  * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')
    84  *
    85  *
    86  * @section sec_dbg_tasks               Tasks
    87  *
    88  * To implement DBGT and instrument VMM for basic state inspection and log
    89  * viewing, the follwing task must be executed:
    90  *
    91  *      -# Basic threading layer in RT.
    92  *      -# Basic tcpip server abstration in RT.
    93  *      -# Write DBGC.
    94  *      -# Write DBCTCP.
    95  *      -# Integrate with VMM and the rest.
    96  *      -# Start writing DBGF (VMM).
    97  */
    98 
    99 
     18#ifndef ___DBGCInternal_h
     19#define ___DBGCInternal_h
    10020
    10121
     
    10323*   Header Files                                                               *
    10424*******************************************************************************/
    105 #define LOG_GROUP LOG_GROUP_DBGC
    10625#include <VBox/dbg.h>
    10726#include <VBox/dbgf.h>
     
    11433#include <VBox/param.h>
    11534#include <VBox/err.h>
    116 #include <VBox/log.h>
    117 
    118 #include <iprt/alloc.h>
    119 #include <iprt/alloca.h>
    120 #include <iprt/string.h>
    121 #include <iprt/assert.h>
    122 #include <iprt/ctype.h>
    123 
    124 #include <stdlib.h>
    125 #include <stdio.h>
    126 
     35
     36
     37/*******************************************************************************
     38*   Defined Constants And Macros                                               *
     39*******************************************************************************/
    12740/* to err.h! */
    12841#define VERR_DBGC_QUIT                          (-11999)
     
    16073
    16174
    162 
    163 /*******************************************************************************
    164 *   Defined Constants And Macros                                               *
    165 *******************************************************************************/
    166 /** Makes a DBGC variable type pair.
    167  * Typically used by binary operators. */
    168 #define BINARY_TYPE_PAIR(type1, type2)   (type1 | (type2 << 16))
    169 
    170 
    17175/*******************************************************************************
    17276*   Structures and Typedefs                                                    *
     
    433337*   Internal Functions                                                         *
    434338*******************************************************************************/
    435 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    436 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    437 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    438 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    439 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    440 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    441 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    442 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    443 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    444 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    445 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    446 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    447 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    448 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    449 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    450 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    451 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    452 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    453 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    454 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    455 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    456 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    457 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    458 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    459 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    460 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    461 
    462 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    463 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    464 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    465 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    466 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    467 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    468 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    469 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    470 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    471 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    472 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    473 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    474 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    475 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    476 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    477 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    478 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    479 
    480 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    481 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    482 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    483 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    484 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    485 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    486 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    487 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    488 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    489 
    490 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    491 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    492 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    493 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    494 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    495 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    496 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    497 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    498 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    499 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    500 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    501 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    502 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    503 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    504 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    505 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    506 
    507 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    508 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    509 
     339#if 0
    510340static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat);
    511341static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb);
     
    525355static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    526356static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
     357#endif
    527358
    528359
     
    530361*   Global Variables                                                           *
    531362*******************************************************************************/
    532 /**
    533  * Pointer to head of the list of external commands.
    534  */
    535 static PDBGCEXTCMDS     g_pExtCmdsHead;     /** @todo rw protect g_pExtCmdsHead! */
    536 /** Locks the g_pExtCmdsHead list for reading. */
    537 #define DBGCEXTCMDS_LOCK_RD()       do { } while (0)
    538 /** Locks the g_pExtCmdsHead list for writing. */
    539 #define DBGCEXTCMDS_LOCK_WR()       do { } while (0)
    540 /** UnLocks the g_pExtCmdsHead list after reading. */
    541 #define DBGCEXTCMDS_UNLOCK_RD()     do { } while (0)
    542 /** UnLocks the g_pExtCmdsHead list after writing. */
    543 #define DBGCEXTCMDS_UNLOCK_WR()     do { } while (0)
    544 
    545 
    546 /** One argument of any kind. */
    547 static const DBGCVARDESC    g_aArgAny[] =
    548 {
    549     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    550     {  0,           1,          DBGCVAR_CAT_ANY,        0,                              "var",          "Any type of argument." },
    551 };
    552 
    553 /** Multiple string arguments (min 1). */
    554 static const DBGCVARDESC    g_aArgMultiStr[] =
    555 {
    556     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    557     {  1,           ~0,         DBGCVAR_CAT_STRING,     0,                              "strings",      "One or more strings." },
    558 };
    559 
    560 /** Filename string. */
    561 static const DBGCVARDESC    g_aArgFilename[] =
    562 {
    563     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    564     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    565 };
    566 
    567 
    568 /** 'br' arguments. */
    569 static const DBGCVARDESC    g_aArgBrkREM[] =
    570 {
    571     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    572     {  1,           1,          DBGCVAR_CAT_GC_POINTER, 0,                              "address",      "The address." },
    573     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "passes",       "The number of passes before we trigger the breakpoint. (0 is default)" },
    574     {  0,           1,          DBGCVAR_CAT_NUMBER,     DBGCVD_FLAGS_DEP_PREV,          "max passes",   "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
    575     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "cmds",         "String of commands to be executed when the breakpoint is hit. Quote it!" },
    576 };
    577 
    578 
    579 /** 'dg', 'dga', 'dl', 'dla' arguments. */
    580 static const DBGCVARDESC    g_aArgDumpDT[] =
    581 {
    582     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    583     {  0,           ~0,         DBGCVAR_CAT_NUMBER,     0,                              "sel",          "Selector or selector range." },
    584     {  0,           ~0,         DBGCVAR_CAT_POINTER,    0,                              "address",      "Far address which selector should be dumped." },
    585 };
    586 
    587 
    588 /** 'di', 'dia' arguments. */
    589 static const DBGCVARDESC    g_aArgDumpIDT[] =
    590 {
    591     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    592     {  0,           ~0,         DBGCVAR_CAT_NUMBER,     0,                              "int",          "The interrupt vector or interrupt vector range." },
    593 };
    594 
    595 
    596 /** 'dpd*' arguments. */
    597 static const DBGCVARDESC    g_aArgDumpPD[] =
    598 {
    599     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    600     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "index",        "Index into the page directory." },
    601     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address which page directory entry to start dumping from. Range is applied to the page directory." },
    602 };
    603 
    604 
    605 /** 'dpda' arguments. */
    606 static const DBGCVARDESC    g_aArgDumpPDAddr[] =
    607 {
    608     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    609     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address of the page directory entry to start dumping from." },
    610 };
    611 
    612 
    613 /** 'dpt?' arguments. */
    614 static const DBGCVARDESC    g_aArgDumpPT[] =
    615 {
    616     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    617     {  1,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address which page directory entry to start dumping from." },
    618 };
    619 
    620 
    621 /** 'dpta' arguments. */
    622 static const DBGCVARDESC    g_aArgDumpPTAddr[] =
    623 {
    624     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    625     {  1,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address of the page table entry to start dumping from." },
    626 };
    627 
    628 
    629 /** 'dt' arguments. */
    630 static const DBGCVARDESC    g_aArgDumpTSS[] =
    631 {
    632     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    633     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "tss",          "TSS selector number." },
    634     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }
    635 };
    636 
    637 
    638 /** 'help' arguments. */
    639 static const DBGCVARDESC    g_aArgHelp[] =
    640 {
    641     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    642     {  0,           ~0,         DBGCVAR_CAT_STRING,     0,                              "cmd/op",       "Zero or more command or operator names." },
    643 };
    644 
    645 
    646 /** 'info' arguments. */
    647 static const DBGCVARDESC    g_aArgInfo[] =
    648 {
    649     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    650     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "info",         "The name of the info to display." },
    651     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "args",         "String arguments to the handler." },
    652 };
    653 
    654 
    655 /** loadsyms arguments. */
    656 static const DBGCVARDESC    g_aArgLoadSyms[] =
    657 {
    658     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    659     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    660     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "delta",        "Delta to add to the loaded symbols. (optional)" },
    661     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "module name",  "Module name." },
    662     {  0,           1,          DBGCVAR_CAT_POINTER,    DBGCVD_FLAGS_DEP_PREV,          "module address", "Module address." },
    663     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "module size",  "The module size. (optional)" },
    664 };
    665 
    666 
    667 /** log arguments. */
    668 static const DBGCVARDESC    g_aArgLog[] =
    669 {
    670     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    671     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "groups",       "Group modifier string (quote it!)." }
    672 };
    673 
    674 
    675 /** logdest arguments. */
    676 static const DBGCVARDESC    g_aArgLogDest[] =
    677 {
    678     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    679     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "dests",        "Destination modifier string (quote it!)." }
    680 };
    681 
    682 
    683 /** logflags arguments. */
    684 static const DBGCVARDESC    g_aArgLogFlags[] =
    685 {
    686     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    687     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "flags",        "Flag modifier string (quote it!)." }
    688 };
    689 
    690 
    691 /** 'set' arguments */
    692 static const DBGCVARDESC    g_aArgSet[] =
    693 {
    694     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    695     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "var",          "Variable name." },
    696     {  1,           1,          DBGCVAR_CAT_ANY,        0,                              "value",        "Value to assign to the variable." },
    697 };
    698 
    699 
    700 
    701 
    702 
    703363/** Command descriptors for the basic commands. */
    704 static const DBGCCMD    g_aCmds[] =
    705 {
    706     /* pszCmd,      cArgsMin, cArgsMax, paArgDescs,         cArgDescs,                  pResultDesc,        fFlags,     pfnHandler          pszSyntax,          ....pszDescription */
    707     { "br",         1,        4,        &g_aArgBrkREM[0],   ELEMENTS(g_aArgBrkREM),     NULL,               0,          dbgcCmdBrkREM,      "<address> [passes [max passes]] [cmds]",
    708                                                                                                                                                                     "Sets a recompiler specific breakpoint." },
    709     { "bye",        0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    710     { "dg",         0,       ~0,        &g_aArgDumpDT[0],   ELEMENTS(g_aArgDumpDT),     NULL,               0,          dbgcCmdDumpDT,      "[sel [..]]",           "Dump the global descriptor table (GDT)." },
    711     { "dga",        0,       ~0,        &g_aArgDumpDT[0],   ELEMENTS(g_aArgDumpDT),     NULL,               0,          dbgcCmdDumpDT,      "[sel [..]]",           "Dump the global descriptor table (GDT) including not-present entries." },
    712     { "di",         0,       ~0,        &g_aArgDumpIDT[0],  ELEMENTS(g_aArgDumpIDT),    NULL,               0,          dbgcCmdDumpIDT,     "[int [..]]",           "Dump the interrupt descriptor table (IDT)." },
    713     { "dia",        0,       ~0,        &g_aArgDumpIDT[0],  ELEMENTS(g_aArgDumpIDT),    NULL,               0,          dbgcCmdDumpIDT,     "[int [..]]",           "Dump the interrupt descriptor table (IDT) including not-present entries." },
    714     { "dl",         0,       ~0,        &g_aArgDumpDT[0],   ELEMENTS(g_aArgDumpDT),     NULL,               0,          dbgcCmdDumpDT,      "[sel [..]]",           "Dump the local descriptor table (LDT)." },
    715     { "dla",        0,       ~0,        &g_aArgDumpDT[0],   ELEMENTS(g_aArgDumpDT),     NULL,               0,          dbgcCmdDumpDT,      "[sel [..]]",           "Dump the local descriptor table (LDT) including not-present entries." },
    716     { "dpd",        0,        1,        &g_aArgDumpPD[0],   ELEMENTS(g_aArgDumpPD),     NULL,               0,          dbgcCmdDumpPageDir, "[addr] [index]",       "Dumps page directory entries of the default context." },
    717     { "dpda",       0,        1,        &g_aArgDumpPDAddr[0],ELEMENTS(g_aArgDumpPDAddr),NULL,               0,          dbgcCmdDumpPageDir, "[addr]",               "Dumps specified page directory." },
    718     { "dpdb",       1,        1,        &g_aArgDumpPD[0],   ELEMENTS(g_aArgDumpPD),     NULL,               0,          dbgcCmdDumpPageDirBoth, "[addr] [index]",   "Dumps page directory entries of the guest and the hypervisor. " },
    719     { "dpdg",       0,        1,        &g_aArgDumpPD[0],   ELEMENTS(g_aArgDumpPD),     NULL,               0,          dbgcCmdDumpPageDir, "[addr] [index]",       "Dumps page directory entries of the guest." },
    720     { "dpdh",       0,        1,        &g_aArgDumpPD[0],   ELEMENTS(g_aArgDumpPD),     NULL,               0,          dbgcCmdDumpPageDir, "[addr] [index]",       "Dumps page directory entries of the hypervisor. " },
    721     { "dpt",        1,        1,        &g_aArgDumpPT[0],   ELEMENTS(g_aArgDumpPT),     NULL,               0,          dbgcCmdDumpPageTable,"<addr>",              "Dumps page table entries of the default context." },
    722     { "dpta",       1,        1,        &g_aArgDumpPTAddr[0],ELEMENTS(g_aArgDumpPTAddr), NULL,              0,          dbgcCmdDumpPageTable,"<addr>",              "Dumps specified page table." },
    723     { "dptb",       1,        1,        &g_aArgDumpPT[0],   ELEMENTS(g_aArgDumpPT),     NULL,               0,          dbgcCmdDumpPageTableBoth,"<addr>",          "Dumps page table entries of the guest and the hypervisor." },
    724     { "dptg",       1,        1,        &g_aArgDumpPT[0],   ELEMENTS(g_aArgDumpPT),     NULL,               0,          dbgcCmdDumpPageTable,"<addr>",              "Dumps page table entries of the guest." },
    725     { "dpth",       1,        1,        &g_aArgDumpPT[0],   ELEMENTS(g_aArgDumpPT),     NULL,               0,          dbgcCmdDumpPageTable,"<addr>",              "Dumps page table entries of the hypervisor." },
    726     { "dt",         0,        1,        &g_aArgDumpTSS[0],  ELEMENTS(g_aArgDumpTSS),    NULL,               0,          dbgcCmdDumpTSS,     "[tss|tss:ign|addr]",   "Dump the task state segment (TSS)." },
    727     { "echo",       1,        ~0,       &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr),   NULL,               0,          dbgcCmdEcho,        "<str1> [str2..[strN]]", "Displays the strings separated by one blank space and the last one followed by a newline." },
    728     { "exit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    729     { "format",     1,        1,        &g_aArgAny[0],      ELEMENTS(g_aArgAny),        NULL,               0,          dbgcCmdFormat,      "",                     "Evaluates an expression and formats it." },
    730     { "harakiri",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdHarakiri,    "",                     "Kills debugger process." },
    731     { "help",       0,        ~0,       &g_aArgHelp[0],     ELEMENTS(g_aArgHelp),       NULL,               0,          dbgcCmdHelp,        "[cmd/op [..]]",        "Display help. For help about info items try 'info help'." },
    732     { "info",       1,        2,        &g_aArgInfo[0],     ELEMENTS(g_aArgInfo),       NULL,               0,          dbgcCmdInfo,        "<info> [args]",        "Display info register in the DBGF. For a list of info items try 'info help'." },
    733     { "loadsyms",   1,        5,        &g_aArgLoadSyms[0], ELEMENTS(g_aArgLoadSyms),   NULL,               0,          dbgcCmdLoadSyms,    "<filename> [delta] [module] [module address]", "Loads symbols from a text file. Optionally giving a delta and a module." },
    734     { "loadvars",   1,        1,        &g_aArgFilename[0], ELEMENTS(g_aArgFilename),   NULL,               0,          dbgcCmdLoadVars,    "<filename>",           "Load variables from file. One per line, same as the args to the set command." },
    735     { "log",        1,        1,        &g_aArgLog[0],      ELEMENTS(g_aArgLog),        NULL,               0,          dbgcCmdLog,         "<group string>",       "Modifies the logging group settings (VBOX_LOG)" },
    736     { "logdest",    1,        1,        &g_aArgLogDest[0],  ELEMENTS(g_aArgLogDest),    NULL,               0,          dbgcCmdLogDest,     "<dest string>",        "Modifies the logging destination (VBOX_LOG_DEST)." },
    737     { "logflags",   1,        1,        &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags),   NULL,               0,          dbgcCmdLogFlags,    "<flags string>",       "Modifies the logging flags (VBOX_LOG_FLAGS)." },
    738     { "quit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    739     { "runscript",  1,        1,        &g_aArgFilename[0], ELEMENTS(g_aArgFilename),   NULL,               0,          dbgcCmdRunScript,   "<filename>",           "Runs the command listed in the script. Lines starting with '#' (after removing blanks) are comment. blank lines are ignored. Stops on failure." },
    740     { "set",        2,        2,        &g_aArgSet[0],      ELEMENTS(g_aArgSet),        NULL,               0,          dbgcCmdSet,         "<var> <value>",        "Sets a global variable." },
    741     { "showvars",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdShowVars,    "",                     "List all the defined variables." },
    742     { "stop",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdStop,        "",                     "Stop execution." },
    743     { "unset",      1,        ~0,       &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr),   NULL,               0,          dbgcCmdUnset,       "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
    744 };
    745 
    746 
    747 /** 'ba' arguments. */
    748 static const DBGCVARDESC    g_aArgBrkAcc[] =
    749 {
    750     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    751     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "access",       "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." },
    752     {  1,           1,          DBGCVAR_CAT_NUMBER,     0,                              "size",         "The access size: 1, 2, 4, or 8. 'x' access requires 1, and 8 requires amd64 long mode." },
    753     {  1,           1,          DBGCVAR_CAT_GC_POINTER, 0,                              "address",      "The address." },
    754     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "passes",       "The number of passes before we trigger the breakpoint. (0 is default)" },
    755     {  0,           1,          DBGCVAR_CAT_NUMBER,     DBGCVD_FLAGS_DEP_PREV,          "max passes",   "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
    756     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "cmds",         "String of commands to be executed when the breakpoint is hit. Quote it!" },
    757 };
    758 
    759 
    760 /** 'bc', 'bd', 'be' arguments. */
    761 static const DBGCVARDESC    g_aArgBrks[] =
    762 {
    763     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    764     {  0,           ~0,         DBGCVAR_CAT_NUMBER,     0,                              "#bp",          "Breakpoint number." },
    765     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "all",          "All breakpoints." },
    766 };
    767 
    768 
    769 /** 'bp' arguments. */
    770 static const DBGCVARDESC    g_aArgBrkSet[] =
    771 {
    772     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    773     {  1,           1,          DBGCVAR_CAT_GC_POINTER, 0,                              "address",      "The address." },
    774     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "passes",       "The number of passes before we trigger the breakpoint. (0 is default)" },
    775     {  0,           1,          DBGCVAR_CAT_NUMBER,     DBGCVD_FLAGS_DEP_PREV,          "max passes",   "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
    776     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "cmds",         "String of commands to be executed when the breakpoint is hit. Quote it!" },
    777 };
    778 
    779 
    780 /** 'd?' arguments. */
    781 static const DBGCVARDESC    g_aArgDumpMem[] =
    782 {
    783     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    784     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address where to start dumping memory." },
    785 };
    786 
    787 
    788 /** 'ln' arguments. */
    789 static const DBGCVARDESC    g_aArgListNear[] =
    790 {
    791     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    792     {  0,           ~0,         DBGCVAR_CAT_POINTER,    0,                              "address",      "Address of the symbol to look up." },
    793     {  0,           ~0,         DBGCVAR_CAT_SYMBOL,     0,                              "symbol",       "Symbol to lookup." },
    794 };
    795 
    796 /** 'ln' return. */
    797 static const DBGCVARDESC    g_RetListNear =
    798 {
    799        1,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "The last resolved symbol/address with adjusted range."
    800 };
    801 
    802 
    803 /** 'ls' arguments. */
    804 static const DBGCVARDESC    g_aArgListSource[] =
    805 {
    806     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    807     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address where to start looking for source lines." },
    808 };
    809 
    810 
    811 /** 'm' argument. */
    812 static const DBGCVARDESC    g_aArgMemoryInfo[] =
    813 {
    814     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    815     {  1,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Pointer to obtain info about." },
    816 };
    817 
    818 
    819 /** 'r' arguments. */
    820 static const DBGCVARDESC    g_aArgReg[] =
    821 {
    822     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    823     {  0,           1,          DBGCVAR_CAT_SYMBOL,     0,                              "register",     "Register to show or set." },
    824     {  0,           1,     DBGCVAR_CAT_NUMBER_NO_RANGE, DBGCVD_FLAGS_DEP_PREV,          "value",        "New register value." },
    825 };
    826 
    827 
    828 /** 's' arguments. */
    829 static const DBGCVARDESC    g_aArgSearchMem[] =
    830 {
    831     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    832     {  1,           1,          DBGCVAR_CAT_GC_POINTER, 0,                              "range",        "Register to show or set." },
    833     {  1,           ~0,         DBGCVAR_CAT_ANY,        0,                              "pattern",      "Pattern to search for." },
    834 };
    835 
    836 
    837 /** 'u' arguments. */
    838 static const DBGCVARDESC    g_aArgUnassemble[] =
    839 {
    840     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    841     {  0,           1,          DBGCVAR_CAT_POINTER,    0,                              "address",      "Address where to start disassembling." },
    842 };
    843 
    844 
     364extern const DBGCCMD    g_aCmds[];
    845365/** Command descriptors for the CodeView / WinDbg emulation.
    846366 * The emulation isn't attempting to be identical, only somewhat similar.
    847367 */
    848 static const DBGCCMD    g_aCmdsCodeView[] =
    849 {
    850     /* pszCmd,      cArgsMin, cArgsMax, paArgDescs,         cArgDescs,                     pResultDesc,        fFlags,  pfnHandler          pszSyntax,          ....pszDescription */
    851     { "ba",         3,        6,        &g_aArgBrkAcc[0],   RT_ELEMENTS(g_aArgBrkAcc),     NULL,               0,       dbgcCmdBrkAccess,   "<access> <size> <address> [passes [max passes]] [cmds]",
    852                                                                                                                                                                     "Sets a data access breakpoint." },
    853     { "bc",         1,       ~0,        &g_aArgBrks[0],     RT_ELEMENTS(g_aArgBrks),       NULL,               0,       dbgcCmdBrkClear,    "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
    854     { "bd",         1,       ~0,        &g_aArgBrks[0],     RT_ELEMENTS(g_aArgBrks),       NULL,               0,       dbgcCmdBrkDisable,  "all | <bp#> [bp# []]", "Disables a set of breakpoints." },
    855     { "be",         1,       ~0,        &g_aArgBrks[0],     RT_ELEMENTS(g_aArgBrks),       NULL,               0,       dbgcCmdBrkEnable,   "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
    856     { "bl",         0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdBrkList,     "",                     "Lists all the breakpoints." },
    857     { "bp",         1,        4,        &g_aArgBrkSet[0],   RT_ELEMENTS(g_aArgBrkSet),     NULL,               0,       dbgcCmdBrkSet,      "<address> [passes [max passes]] [cmds]",
    858                                                                                                                                                                  "Sets a breakpoint (int 3)." },
    859     { "d",          0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory using last element size." },
    860     { "da",         0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory as ascii string." },
    861     { "db",         0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory in bytes." },
    862     { "dd",         0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory in double words." },
    863     { "dq",         0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory in quad words." },
    864     { "dw",         0,        1,        &g_aArgDumpMem[0],  RT_ELEMENTS(g_aArgDumpMem),    NULL,               0,       dbgcCmdDumpMem,     "[addr]",               "Dump memory in words." },
    865     { "g",          0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdGo,          "",                     "Continue execution." },
    866     { "k",          0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdStack,       "",                     "Callstack." },
    867     { "kg",         0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdStack,       "",                     "Callstack - guest." },
    868     { "kh",         0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdStack,       "",                     "Callstack - hypervisor." },
    869     { "ln",         0,        ~0,       &g_aArgListNear[0], RT_ELEMENTS(g_aArgListNear),   &g_RetListNear,     0,       dbgcCmdListNear,    "[addr/sym [..]]",      "List symbols near to the address. Default address is CS:EIP." },
    870     { "ls",         0,        1,        &g_aArgListSource[0],RT_ELEMENTS(g_aArgListSource),NULL,               0,       dbgcCmdListSource,  "[addr]",               "Source." },
    871     { "m",          1,        1,        &g_aArgMemoryInfo[0],RT_ELEMENTS(g_aArgMemoryInfo),NULL,               0,       dbgcCmdMemoryInfo,  "<addr>",               "Display information about that piece of memory." },
    872     { "r",          0,        2,        &g_aArgReg[0],      RT_ELEMENTS(g_aArgReg),        NULL,               0,       dbgcCmdReg,         "[reg [newval]]",       "Show or set register(s) - active reg set." },
    873     { "rg",         0,        2,        &g_aArgReg[0],      RT_ELEMENTS(g_aArgReg),        NULL,               0,       dbgcCmdRegGuest,    "[reg [newval]]",       "Show or set register(s) - guest reg set." },
    874     { "rh",         0,        2,        &g_aArgReg[0],      RT_ELEMENTS(g_aArgReg),        NULL,               0,       dbgcCmdRegHyper,    "[reg [newval]]",       "Show or set register(s) - hypervisor reg set." },
    875     { "rt",         0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdRegTerse,    "",                     "Toggles terse / verbose register info." },
    876     //{ "s",          2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Continue last search." },
    877     { "sa",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for an ascii string." },
    878     { "sb",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for one or more bytes." },
    879     { "sd",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for one or more double words." },
    880     { "sq",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for one or more quad words." },
    881     { "su",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for an unicode string." },
    882     { "sw",         2,       ~0,        &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem),  NULL,               0,       dbgcCmdSearchMem,   "<range> <pattern>",    "Search memory for one or more words." },
    883     { "t",          0,        0,        NULL,               0,                             NULL,               0,       dbgcCmdTrace,       "",                     "Instruction trace (step into)." },
    884     { "u",          0,        1,        &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL,               0,       dbgcCmdUnassemble,  "[addr]",               "Unassemble." },
    885 };
    886 
    887 
    888 /** Operators. */
    889 static const DBGCOP g_aOps[] =
    890 {
    891     /* szName is initialized as a 4 char array because of M$C elsewise optimizing it away in /Ox mode (the 'const char' vs 'char' problem). */
    892     /* szName,          cchName, fBinary,    iPrecedence,    pfnHandlerUnary,    pfnHandlerBitwise  */
    893     { {'-'},            1,       false,      1,              dbgcOpMinus,        NULL,                       "Unary minus." },
    894     { {'+'},            1,       false,      1,              dbgcOpPluss,        NULL,                       "Unary pluss." },
    895     { {'!'},            1,       false,      1,              dbgcOpBooleanNot,   NULL,                       "Boolean not." },
    896     { {'~'},            1,       false,      1,              dbgcOpBitwiseNot,   NULL,                       "Bitwise complement." },
    897     { {':'},            1,       true,       2,              NULL,               dbgcOpAddrFar,              "Far pointer." },
    898     { {'%'},            1,       false,      3,              dbgcOpAddrFlat,     NULL,                       "Flat address." },
    899     { {'%','%'},        2,       false,      3,              dbgcOpAddrPhys,     NULL,                       "Physical address." },
    900     { {'#'},            1,       false,      3,              dbgcOpAddrHost,     NULL,                       "Flat host address." },
    901     { {'#','%','%'},    3,       false,      3,              dbgcOpAddrHostPhys, NULL,                       "Physical host address." },
    902     { {'$'},            1,       false,      3,              dbgcOpVar,          NULL,                       "Reference a variable." },
    903     { {'*'},            1,       true,       10,             NULL,               dbgcOpMult,                 "Multiplication." },
    904     { {'/'},            1,       true,       11,             NULL,               dbgcOpDiv,                  "Division." },
    905     { {'%'},            1,       true,       12,             NULL,               dbgcOpMod,                  "Modulus." },
    906     { {'+'},            1,       true,       13,             NULL,               dbgcOpAdd,                  "Addition." },
    907     { {'-'},            1,       true,       14,             NULL,               dbgcOpSub,                  "Subtraction." },
    908     { {'<','<'},        2,       true,       15,             NULL,               dbgcOpBitwiseShiftLeft,     "Bitwise left shift." },
    909     { {'>','>'},        2,       true,       16,             NULL,               dbgcOpBitwiseShiftRight,    "Bitwise right shift." },
    910     { {'&'},            1,       true,       17,             NULL,               dbgcOpBitwiseAnd,           "Bitwise and." },
    911     { {'^'},            1,       true,       18,             NULL,               dbgcOpBitwiseXor,           "Bitwise exclusiv or." },
    912     { {'|'},            1,       true,       19,             NULL,               dbgcOpBitwiseOr,            "Bitwise inclusive or." },
    913     { {'&','&'},        2,       true,       20,             NULL,               dbgcOpBooleanAnd,           "Boolean and." },
    914     { {'|','|'},        2,       true,       21,             NULL,               dbgcOpBooleanOr,            "Boolean or." },
    915     { {'L'},            1,       true,       22,             NULL,               dbgcOpRangeLength,          "Range elements." },
    916     { {'L','B'},        2,       true,       23,             NULL,               dbgcOpRangeLengthBytes,     "Range bytes." },
    917     { {'T'},            1,       true,       24,             NULL,               dbgcOpRangeTo,              "Range to." }
    918 };
    919 
    920 /** Bitmap where set bits indicates the characters the may start an operator name. */
    921 static uint32_t g_bmOperatorChars[256 / (4*8)];
    922 
    923 /** Register symbol uUser value.
    924  * @{
    925  */
    926 /** If set the register set is the hypervisor and not the guest one. */
    927 #define SYMREG_FLAGS_HYPER      RT_BIT(20)
    928 /** If set a far conversion of the value will use the high 16 bit for the selector.
    929  * If clear the low 16 bit will be used. */
    930 #define SYMREG_FLAGS_HIGH_SEL   RT_BIT(21)
    931 /** The shift value to calc the size of a register symbol from the uUser value. */
    932 #define SYMREG_SIZE_SHIFT       (24)
    933 /** Get the offset */
    934 #define SYMREG_OFFSET(uUser)    (uUser & ((1 << 20) - 1))
    935 /** Get the size. */
    936 #define SYMREG_SIZE(uUser)      ((uUser >> SYMREG_SIZE_SHIFT) & 0xff)
    937 /** 1 byte. */
    938 #define SYMREG_SIZE_1           ( 1 << SYMREG_SIZE_SHIFT)
    939 /** 2 byte. */
    940 #define SYMREG_SIZE_2           ( 2 << SYMREG_SIZE_SHIFT)
    941 /** 4 byte. */
    942 #define SYMREG_SIZE_4           ( 4 << SYMREG_SIZE_SHIFT)
    943 /** 6 byte. */
    944 #define SYMREG_SIZE_6           ( 6 << SYMREG_SIZE_SHIFT)
    945 /** 8 byte. */
    946 #define SYMREG_SIZE_8           ( 8 << SYMREG_SIZE_SHIFT)
    947 /** 12 byte. */
    948 #define SYMREG_SIZE_12          (12 << SYMREG_SIZE_SHIFT)
    949 /** 16 byte. */
    950 #define SYMREG_SIZE_16          (16 << SYMREG_SIZE_SHIFT)
    951 /** @} */
    952 
    953 /** Builtin Symbols.
    954  * ASSUMES little endian register representation!
    955  */
    956 static const DBGCSYM    g_aSyms[] =
    957 {
    958     { "eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 },
    959     { "ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 },
    960     { "al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 },
    961     { "ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 },
    962 
    963     { "ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 },
    964     { "bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 },
    965     { "bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 },
    966     { "bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 },
    967 
    968     { "ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 },
    969     { "cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 },
    970     { "cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 },
    971     { "ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 },
    972 
    973     { "edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 },
    974     { "dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 },
    975     { "dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 },
    976     { "dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 },
    977 
    978     { "edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 },
    979     { "di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 },
    980 
    981     { "esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 },
    982     { "si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 },
    983 
    984     { "ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 },
    985     { "bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 },
    986 
    987     { "esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 },
    988     { "sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 },
    989 
    990     { "eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 },
    991     { "ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 },
    992 
    993     { "efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    994     { "eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    995     { "fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    996     { "flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    997 
    998     { "cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 },
    999     { "ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 },
    1000     { "es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 },
    1001     { "fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 },
    1002     { "gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 },
    1003     { "ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 },
    1004 
    1005     { "cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 },
    1006     { "cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 },
    1007     { "cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 },
    1008     { "cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 },
    1009 
    1010     { "tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 },
    1011     { "ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 },
    1012 
    1013     { "gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 },
    1014     { "gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 },
    1015     { "gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 },
    1016 
    1017     { "idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 },
    1018     { "idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 },
    1019     { "idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 },
    1020 
    1021     /* hypervisor */
    1022 
    1023     {".eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1024     {".ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1025     {".al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1026     {".ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1027 
    1028     {".ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1029     {".bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1030     {".bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1031     {".bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1032 
    1033     {".ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1034     {".cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1035     {".cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1036     {".ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1037 
    1038     {".edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1039     {".dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1040     {".dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1041     {".dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    1042 
    1043     {".edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1044     {".di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1045 
    1046     {".esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1047     {".si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1048 
    1049     {".ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1050     {".bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1051 
    1052     {".esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1053     {".sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1054 
    1055     {".eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1056     {".ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1057 
    1058     {".efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1059     {".eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1060     {".fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1061     {".flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1062 
    1063     {".cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1064     {".ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1065     {".es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1066     {".fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1067     {".gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1068     {".ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1069 
    1070     {".cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1071     {".cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1072     {".cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1073     {".cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1074 
    1075     {".tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1076     {".ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    1077 
    1078     {".gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    1079     {".gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    1080     {".gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1081 
    1082     {".idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    1083     {".idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    1084     {".idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    1085 
    1086 };
    1087 
    1088 
    1089 /**
    1090  * Prints full command help.
    1091  */
    1092 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal)
    1093 {
    1094     int rc;
    1095 
    1096     /* the command */
    1097     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1098                             "%s%-*s %-30s %s",
    1099                             fExternal ? "." : "",
    1100                             fExternal ? 10 : 11,
    1101                             pCmd->pszCmd,
    1102                             pCmd->pszSyntax,
    1103                             pCmd->pszDescription);
    1104     if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax)
    1105         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n");
    1106     else if (pCmd->cArgsMin == pCmd->cArgsMax)
    1107         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin);
    1108     else if (pCmd->cArgsMax == ~0U)
    1109         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin);
    1110     else
    1111         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax);
    1112 
    1113     /* argument descriptions. */
    1114     for (unsigned i = 0; i < pCmd->cArgDescs; i++)
    1115     {
    1116         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1117                                 "    %-12s %s",
    1118                                 pCmd->paArgDescs[i].pszName,
    1119                                 pCmd->paArgDescs[i].pszDescription);
    1120         if (!pCmd->paArgDescs[i].cTimesMin)
    1121         {
    1122             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    1123                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n");
    1124             else
    1125                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax);
    1126         }
    1127         else
    1128         {
    1129             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    1130                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin);
    1131             else
    1132                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
    1133         }
    1134     }
    1135     return rc;
    1136 }
    1137 
    1138 
    1139 /**
    1140  * The 'help' command.
    1141  *
    1142  * @returns VBox status.
    1143  * @param   pCmd        Pointer to the command descriptor (as registered).
    1144  * @param   pCmdHlp     Pointer to command helper functions.
    1145  * @param   pVM         Pointer to the current VM (if any).
    1146  * @param   paArgs      Pointer to (readonly) array of arguments.
    1147  * @param   cArgs       Number of arguments in the array.
    1148  */
    1149 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1150 {
    1151     PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1152     int         rc = VINF_SUCCESS;
    1153     unsigned    i;
    1154 
    1155     if (!cArgs)
    1156     {
    1157         /*
    1158          * All the stuff.
    1159          */
    1160         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1161                                 "VirtualBox Debugger\n"
    1162                                 "-------------------\n"
    1163                                 "\n"
    1164                                 "Commands and Functions:\n");
    1165         for (i = 0; i < ELEMENTS(g_aCmds); i++)
    1166             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1167                                     "%-11s %-30s %s\n",
    1168                                     g_aCmds[i].pszCmd,
    1169                                     g_aCmds[i].pszSyntax,
    1170                                     g_aCmds[i].pszDescription);
    1171         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1172                                 "\n"
    1173                                 "Emulation: %s\n", pDbgc->pszEmulation);
    1174         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    1175         for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++)
    1176             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1177                                     "%-11s %-30s %s\n",
    1178                                     pCmd->pszCmd,
    1179                                     pCmd->pszSyntax,
    1180                                     pCmd->pszDescription);
    1181 
    1182         if (g_pExtCmdsHead)
    1183         {
    1184             DBGCEXTCMDS_LOCK_RD();
    1185             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1186                                     "\n"
    1187                                     "External Commands and Functions:\n");
    1188             for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    1189                 for (i = 0; i < pExtCmd->cCmds; i++)
    1190                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1191                                             ".%-10s %-30s %s\n",
    1192                                             pExtCmd->paCmds[i].pszCmd,
    1193                                             pExtCmd->paCmds[i].pszSyntax,
    1194                                             pExtCmd->paCmds[i].pszDescription);
    1195             DBGCEXTCMDS_UNLOCK_RD();
    1196         }
    1197 
    1198         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1199                                 "\n"
    1200                                 "Operators:\n");
    1201         unsigned iPrecedence = 0;
    1202         unsigned cLeft = ELEMENTS(g_aOps);
    1203         while (cLeft > 0)
    1204         {
    1205             for (i = 0; i < ELEMENTS(g_aOps); i++)
    1206                 if (g_aOps[i].iPrecedence == iPrecedence)
    1207                 {
    1208                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1209                                             "%-10s  %s  %s\n",
    1210                                             g_aOps[i].szName,
    1211                                             g_aOps[i].fBinary ? "Binary" : "Unary ",
    1212                                             g_aOps[i].pszDescription);
    1213                     cLeft--;
    1214                 }
    1215             iPrecedence++;
    1216         }
    1217     }
    1218     else
    1219     {
    1220         /*
    1221          * Search for the arguments (strings).
    1222          */
    1223         for (unsigned iArg = 0; iArg < cArgs; iArg++)
    1224         {
    1225             Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);
    1226             bool fFound = false;
    1227 
    1228             /* lookup in the emulation command list first */
    1229             for (i = 0; i < pDbgc->cEmulationCmds; i++)
    1230                 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString))
    1231                 {
    1232                     rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);
    1233                     fFound = true;
    1234                     break;
    1235                 }
    1236 
    1237             /* lookup in the command list (even when found in the emulation) */
    1238             for (i = 0; i < ELEMENTS(g_aCmds); i++)
    1239                 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString))
    1240                 {
    1241                     rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);
    1242                     fFound = true;
    1243                     break;
    1244                 }
    1245 
    1246            /* external commands */
    1247            if (     !fFound
    1248                &&   g_pExtCmdsHead
    1249                &&   paArgs[iArg].u.pszString[0] == '.')
    1250            {
    1251                DBGCEXTCMDS_LOCK_RD();
    1252                for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    1253                    for (i = 0; i < pExtCmd->cCmds; i++)
    1254                        if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1))
    1255                        {
    1256                            rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true);
    1257                            fFound = true;
    1258                            break;
    1259                        }
    1260                DBGCEXTCMDS_UNLOCK_RD();
    1261            }
    1262 
    1263            /* operators */
    1264            if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
    1265            {
    1266                for (i = 0; i < ELEMENTS(g_aOps); i++)
    1267                    if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))
    1268                    {
    1269                        rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1270                                                "%-10s  %s  %s\n",
    1271                                                g_aOps[i].szName,
    1272                                                g_aOps[i].fBinary ? "Binary" : "Unary ",
    1273                                                g_aOps[i].pszDescription);
    1274                        fFound = true;
    1275                        break;
    1276                    }
    1277            }
    1278 
    1279            /* found? */
    1280            if (!fFound)
    1281                rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1282                                        "error: '%s' was not found!\n",
    1283                                        paArgs[iArg].u.pszString);
    1284         } /* foreach argument */
    1285     }
    1286 
    1287     NOREF(pCmd);
    1288     NOREF(pVM);
    1289     NOREF(pResult);
    1290     return rc;
    1291 }
    1292 
    1293 
    1294 /**
    1295  * The 'quit', 'exit' and 'bye' commands.
    1296  *
    1297  * @returns VBox status.
    1298  * @param   pCmd        Pointer to the command descriptor (as registered).
    1299  * @param   pCmdHlp     Pointer to command helper functions.
    1300  * @param   pVM         Pointer to the current VM (if any).
    1301  * @param   paArgs      Pointer to (readonly) array of arguments.
    1302  * @param   cArgs       Number of arguments in the array.
    1303  */
    1304 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1305 {
    1306     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
    1307     NOREF(pCmd);
    1308     NOREF(pVM);
    1309     NOREF(paArgs);
    1310     NOREF(cArgs);
    1311     NOREF(pResult);
    1312     return VERR_DBGC_QUIT;
    1313 }
    1314 
    1315 
    1316 /**
    1317  * The 'go' command.
    1318  *
    1319  * @returns VBox status.
    1320  * @param   pCmd        Pointer to the command descriptor (as registered).
    1321  * @param   pCmdHlp     Pointer to command helper functions.
    1322  * @param   pVM         Pointer to the current VM (if any).
    1323  * @param   paArgs      Pointer to (readonly) array of arguments.
    1324  * @param   cArgs       Number of arguments in the array.
    1325  */
    1326 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1327 {
    1328     /*
    1329      * Check if the VM is halted or not before trying to resume it.
    1330      */
    1331     if (!DBGFR3IsHalted(pVM))
    1332         pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already running...\n");
    1333     else
    1334     {
    1335         int rc = DBGFR3Resume(pVM);
    1336         if (VBOX_FAILURE(rc))
    1337             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Resume().");
    1338     }
    1339 
    1340     NOREF(pCmd);
    1341     NOREF(paArgs);
    1342     NOREF(cArgs);
    1343     NOREF(pResult);
    1344     return 0;
    1345 }
    1346 
    1347 /**
    1348  * The 'stop' command.
    1349  *
    1350  * @returns VBox status.
    1351  * @param   pCmd        Pointer to the command descriptor (as registered).
    1352  * @param   pCmdHlp     Pointer to command helper functions.
    1353  * @param   pVM         Pointer to the current VM (if any).
    1354  * @param   paArgs      Pointer to (readonly) array of arguments.
    1355  * @param   cArgs       Number of arguments in the array.
    1356  */
    1357 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1358 {
    1359     /*
    1360      * Check if the VM is halted or not before trying to halt it.
    1361      */
    1362     int rc;
    1363     if (DBGFR3IsHalted(pVM))
    1364         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
    1365     else
    1366     {
    1367         rc = DBGFR3Halt(pVM);
    1368         if (VBOX_SUCCESS(rc))
    1369             rc = VWRN_DBGC_CMD_PENDING;
    1370         else
    1371             rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
    1372     }
    1373 
    1374     NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    1375     return rc;
    1376 }
    1377 
    1378 
    1379 /**
    1380  * The 'ba' command.
    1381  *
    1382  * @returns VBox status.
    1383  * @param   pCmd        Pointer to the command descriptor (as registered).
    1384  * @param   pCmdHlp     Pointer to command helper functions.
    1385  * @param   pVM         Pointer to the current VM (if any).
    1386  * @param   paArgs      Pointer to (readonly) array of arguments.
    1387  * @param   cArgs       Number of arguments in the array.
    1388  */
    1389 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1390 {
    1391     /*
    1392      * Interpret access type.
    1393      */
    1394     if (    !strchr("xrwi", paArgs[0].u.pszString[0])
    1395         ||  paArgs[0].u.pszString[1])
    1396         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n",
    1397                                   paArgs[0].u.pszString, pCmd->pszCmd);
    1398     uint8_t fType = 0;
    1399     switch (paArgs[0].u.pszString[0])
    1400     {
    1401         case 'x':  fType = X86_DR7_RW_EO; break;
    1402         case 'r':  fType = X86_DR7_RW_RW; break;
    1403         case 'w':  fType = X86_DR7_RW_WO; break;
    1404         case 'i':  fType = X86_DR7_RW_IO; break;
    1405     }
    1406 
    1407     /*
    1408      * Validate size.
    1409      */
    1410     if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1)
    1411         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n",
    1412                                   paArgs[1].u.u64Number, pCmd->pszCmd);
    1413     switch (paArgs[1].u.u64Number)
    1414     {
    1415         case 1:
    1416         case 2:
    1417         case 4:
    1418             break;
    1419         /*case 8: - later*/
    1420         default:
    1421             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 1, 2 or 4!\n",
    1422                                       paArgs[1].u.u64Number, pCmd->pszCmd);
    1423     }
    1424     uint8_t cb = (uint8_t)paArgs[1].u.u64Number;
    1425 
    1426     /*
    1427      * Convert the pointer to a DBGF address.
    1428      */
    1429     DBGFADDRESS Address;
    1430     int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address);
    1431     if (VBOX_FAILURE(rc))
    1432         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[2], rc);
    1433 
    1434     /*
    1435      * Pick out the optional arguments.
    1436      */
    1437     uint64_t iHitTrigger = 0;
    1438     uint64_t iHitDisable = ~0;
    1439     const char *pszCmds = NULL;
    1440     unsigned iArg = 3;
    1441     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1442     {
    1443         iHitTrigger = paArgs[iArg].u.u64Number;
    1444         iArg++;
    1445         if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1446         {
    1447             iHitDisable = paArgs[iArg].u.u64Number;
    1448             iArg++;
    1449         }
    1450     }
    1451     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
    1452     {
    1453         pszCmds = paArgs[iArg].u.pszString;
    1454         iArg++;
    1455     }
    1456 
    1457     /*
    1458      * Try set the breakpoint.
    1459      */
    1460     RTUINT iBp;
    1461     rc = DBGFR3BpSetReg(pVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp);
    1462     if (VBOX_SUCCESS(rc))
    1463     {
    1464         PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1465         rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
    1466         if (VBOX_SUCCESS(rc))
    1467             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1468         if (rc == VERR_DBGC_BP_EXISTS)
    1469         {
    1470             rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
    1471             if (VBOX_SUCCESS(rc))
    1472                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1473         }
    1474         int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
    1475         AssertRC(rc2);
    1476     }
    1477     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
    1478 }
    1479 
    1480 
    1481 /**
    1482  * The 'bc' command.
    1483  *
    1484  * @returns VBox status.
    1485  * @param   pCmd        Pointer to the command descriptor (as registered).
    1486  * @param   pCmdHlp     Pointer to command helper functions.
    1487  * @param   pVM         Pointer to the current VM (if any).
    1488  * @param   paArgs      Pointer to (readonly) array of arguments.
    1489  * @param   cArgs       Number of arguments in the array.
    1490  */
    1491 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1492 {
    1493     /*
    1494      * Enumerate the arguments.
    1495      */
    1496     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1497     int     rc = VINF_SUCCESS;
    1498     for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
    1499     {
    1500         if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    1501         {
    1502             /* one */
    1503             RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
    1504             if (iBp != paArgs[iArg].u.u64Number)
    1505             {
    1506                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
    1507                 break;
    1508             }
    1509             int rc2 = DBGFR3BpClear(pVM, iBp);
    1510             if (VBOX_FAILURE(rc2))
    1511                 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
    1512             if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
    1513                 dbgcBpDelete(pDbgc, iBp);
    1514         }
    1515         else if (!strcmp(paArgs[iArg].u.pszString, "all"))
    1516         {
    1517             /* all */
    1518             PDBGCBP pBp = pDbgc->pFirstBp;
    1519             while (pBp)
    1520             {
    1521                 RTUINT iBp = pBp->iBp;
    1522                 pBp = pBp->pNext;
    1523 
    1524                 int rc2 = DBGFR3BpClear(pVM, iBp);
    1525                 if (VBOX_FAILURE(rc2))
    1526                     rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);
    1527                 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)
    1528                     dbgcBpDelete(pDbgc, iBp);
    1529             }
    1530         }
    1531         else
    1532         {
    1533             /* invalid parameter */
    1534             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
    1535             break;
    1536         }
    1537     }
    1538     return rc;
    1539 }
    1540 
    1541 
    1542 /**
    1543  * The 'bd' command.
    1544  *
    1545  * @returns VBox status.
    1546  * @param   pCmd        Pointer to the command descriptor (as registered).
    1547  * @param   pCmdHlp     Pointer to command helper functions.
    1548  * @param   pVM         Pointer to the current VM (if any).
    1549  * @param   paArgs      Pointer to (readonly) array of arguments.
    1550  * @param   cArgs       Number of arguments in the array.
    1551  */
    1552 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1553 {
    1554     /*
    1555      * Enumerate the arguments.
    1556      */
    1557     int rc = VINF_SUCCESS;
    1558     for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
    1559     {
    1560         if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    1561         {
    1562             /* one */
    1563             RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
    1564             if (iBp != paArgs[iArg].u.u64Number)
    1565             {
    1566                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
    1567                 break;
    1568             }
    1569             rc = DBGFR3BpDisable(pVM, iBp);
    1570             if (VBOX_FAILURE(rc))
    1571                 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", iBp);
    1572         }
    1573         else if (!strcmp(paArgs[iArg].u.pszString, "all"))
    1574         {
    1575             /* all */
    1576             PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1577             for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
    1578             {
    1579                 rc = DBGFR3BpDisable(pVM, pBp->iBp);
    1580                 if (VBOX_FAILURE(rc))
    1581                     rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", pBp->iBp);
    1582             }
    1583         }
    1584         else
    1585         {
    1586             /* invalid parameter */
    1587             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
    1588             break;
    1589         }
    1590     }
    1591     return rc;
    1592 }
    1593 
    1594 
    1595 /**
    1596  * The 'be' command.
    1597  *
    1598  * @returns VBox status.
    1599  * @param   pCmd        Pointer to the command descriptor (as registered).
    1600  * @param   pCmdHlp     Pointer to command helper functions.
    1601  * @param   pVM         Pointer to the current VM (if any).
    1602  * @param   paArgs      Pointer to (readonly) array of arguments.
    1603  * @param   cArgs       Number of arguments in the array.
    1604  */
    1605 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1606 {
    1607     /*
    1608      * Enumerate the arguments.
    1609      */
    1610     int rc = VINF_SUCCESS;
    1611     for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)
    1612     {
    1613         if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    1614         {
    1615             /* one */
    1616             RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;
    1617             if (iBp != paArgs[iArg].u.u64Number)
    1618             {
    1619                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
    1620                 break;
    1621             }
    1622             rc = DBGFR3BpEnable(pVM, iBp);
    1623             if (VBOX_FAILURE(rc))
    1624                 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", iBp);
    1625         }
    1626         else if (!strcmp(paArgs[iArg].u.pszString, "all"))
    1627         {
    1628             /* all */
    1629             PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1630             for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)
    1631             {
    1632                 rc = DBGFR3BpEnable(pVM, pBp->iBp);
    1633                 if (VBOX_FAILURE(rc))
    1634                     rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", pBp->iBp);
    1635             }
    1636         }
    1637         else
    1638         {
    1639             /* invalid parameter */
    1640             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
    1641             break;
    1642         }
    1643     }
    1644     return rc;
    1645 }
    1646 
    1647 
    1648 /**
    1649  * Breakpoint enumeration callback function.
    1650  *
    1651  * @returns VBox status code. Any failure will stop the enumeration.
    1652  * @param   pVM         The VM handle.
    1653  * @param   pvUser      The user argument.
    1654  * @param   pBp         Pointer to the breakpoint information. (readonly)
    1655  */
    1656 static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PVM pVM, void *pvUser, PCDBGFBP pBp)
    1657 {
    1658     PDBGC pDbgc = (PDBGC)pvUser;
    1659     PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp);
    1660 
    1661     /*
    1662      * BP type and size.
    1663      */
    1664     char chType;
    1665     char cb = 1;
    1666     switch (pBp->enmType)
    1667     {
    1668         case DBGFBPTYPE_INT3:
    1669             chType = 'p';
    1670             break;
    1671         case DBGFBPTYPE_REG:
    1672             switch (pBp->u.Reg.fType)
    1673             {
    1674                 case X86_DR7_RW_EO: chType = 'x'; break;
    1675                 case X86_DR7_RW_WO: chType = 'w'; break;
    1676                 case X86_DR7_RW_IO: chType = 'i'; break;
    1677                 case X86_DR7_RW_RW: chType = 'r'; break;
    1678                 default:            chType = '?'; break;
    1679 
    1680             }
    1681             cb = pBp->u.Reg.cb;
    1682             break;
    1683         case DBGFBPTYPE_REM:
    1684             chType = 'r';
    1685             break;
    1686         default:
    1687             chType = '?';
    1688             break;
    1689     }
    1690 
    1691     pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%2u %c %d %c %VGv %04RX64 (%04RX64 to ",
    1692                             pBp->iBp, pBp->fEnabled ? 'e' : 'd', cb, chType,
    1693                             pBp->GCPtr, pBp->cHits, pBp->iHitTrigger);
    1694     if (pBp->iHitDisable == ~(uint64_t)0)
    1695         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "~0)  ");
    1696     else
    1697         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%04RX64)");
    1698 
    1699     /*
    1700      * Try resolve the address.
    1701      */
    1702     DBGFSYMBOL Sym;
    1703     RTGCINTPTR off;
    1704     int rc = DBGFR3SymbolByAddr(pVM, pBp->GCPtr, &off, &Sym);
    1705     if (VBOX_SUCCESS(rc))
    1706     {
    1707         if (!off)
    1708             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", Sym.szName);
    1709         else if (off > 0)
    1710             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, off);
    1711         else
    1712             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, -off);
    1713     }
    1714 
    1715     /*
    1716      * The commands.
    1717      */
    1718     if (pDbgcBp)
    1719     {
    1720         if (pDbgcBp->cchCmd)
    1721             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n  cmds: '%s'\n",
    1722                                     pDbgcBp->szCmd);
    1723         else
    1724             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");
    1725     }
    1726     else
    1727         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " [unknown bp]\n");
    1728 
    1729     return VINF_SUCCESS;
    1730 }
    1731 
    1732 
    1733 /**
    1734  * The 'bl' command.
    1735  *
    1736  * @returns VBox status.
    1737  * @param   pCmd        Pointer to the command descriptor (as registered).
    1738  * @param   pCmdHlp     Pointer to command helper functions.
    1739  * @param   pVM         Pointer to the current VM (if any).
    1740  * @param   paArgs      Pointer to (readonly) array of arguments.
    1741  * @param   cArgs       Number of arguments in the array.
    1742  */
    1743 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
    1744 {
    1745     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1746 
    1747     /*
    1748      * Enumerate the breakpoints.
    1749      */
    1750     int rc = DBGFR3BpEnum(pVM, dbgcEnumBreakpointsCallback, pDbgc);
    1751     if (VBOX_FAILURE(rc))
    1752         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnum failed.\n");
    1753     return rc;
    1754 }
    1755 
    1756 
    1757 /**
    1758  * The 'bp' command.
    1759  *
    1760  * @returns VBox status.
    1761  * @param   pCmd        Pointer to the command descriptor (as registered).
    1762  * @param   pCmdHlp     Pointer to command helper functions.
    1763  * @param   pVM         Pointer to the current VM (if any).
    1764  * @param   paArgs      Pointer to (readonly) array of arguments.
    1765  * @param   cArgs       Number of arguments in the array.
    1766  */
    1767 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1768 {
    1769     /*
    1770      * Convert the pointer to a DBGF address.
    1771      */
    1772     DBGFADDRESS Address;
    1773     int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
    1774     if (VBOX_FAILURE(rc))
    1775         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
    1776 
    1777     /*
    1778      * Pick out the optional arguments.
    1779      */
    1780     uint64_t iHitTrigger = 0;
    1781     uint64_t iHitDisable = ~0;
    1782     const char *pszCmds = NULL;
    1783     unsigned iArg = 1;
    1784     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1785     {
    1786         iHitTrigger = paArgs[iArg].u.u64Number;
    1787         iArg++;
    1788         if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1789         {
    1790             iHitDisable = paArgs[iArg].u.u64Number;
    1791             iArg++;
    1792         }
    1793     }
    1794     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
    1795     {
    1796         pszCmds = paArgs[iArg].u.pszString;
    1797         iArg++;
    1798     }
    1799 
    1800     /*
    1801      * Try set the breakpoint.
    1802      */
    1803     RTUINT iBp;
    1804     rc = DBGFR3BpSet(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
    1805     if (VBOX_SUCCESS(rc))
    1806     {
    1807         PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1808         rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
    1809         if (VBOX_SUCCESS(rc))
    1810             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1811         if (rc == VERR_DBGC_BP_EXISTS)
    1812         {
    1813             rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
    1814             if (VBOX_SUCCESS(rc))
    1815                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1816         }
    1817         int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
    1818         AssertRC(rc2);
    1819     }
    1820     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
    1821 }
    1822 
    1823 
    1824 /**
    1825  * The 'br' command.
    1826  *
    1827  * @returns VBox status.
    1828  * @param   pCmd        Pointer to the command descriptor (as registered).
    1829  * @param   pCmdHlp     Pointer to command helper functions.
    1830  * @param   pVM         Pointer to the current VM (if any).
    1831  * @param   paArgs      Pointer to (readonly) array of arguments.
    1832  * @param   cArgs       Number of arguments in the array.
    1833  */
    1834 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
    1835 {
    1836     /*
    1837      * Convert the pointer to a DBGF address.
    1838      */
    1839     DBGFADDRESS Address;
    1840     int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);
    1841     if (VBOX_FAILURE(rc))
    1842         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
    1843 
    1844     /*
    1845      * Pick out the optional arguments.
    1846      */
    1847     uint64_t iHitTrigger = 0;
    1848     uint64_t iHitDisable = ~0;
    1849     const char *pszCmds = NULL;
    1850     unsigned iArg = 1;
    1851     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1852     {
    1853         iHitTrigger = paArgs[iArg].u.u64Number;
    1854         iArg++;
    1855         if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1856         {
    1857             iHitDisable = paArgs[iArg].u.u64Number;
    1858             iArg++;
    1859         }
    1860     }
    1861     if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)
    1862     {
    1863         pszCmds = paArgs[iArg].u.pszString;
    1864         iArg++;
    1865     }
    1866 
    1867     /*
    1868      * Try set the breakpoint.
    1869      */
    1870     RTUINT iBp;
    1871     rc = DBGFR3BpSetREM(pVM, &Address, iHitTrigger, iHitDisable, &iBp);
    1872     if (VBOX_SUCCESS(rc))
    1873     {
    1874         PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1875         rc = dbgcBpAdd(pDbgc, iBp, pszCmds);
    1876         if (VBOX_SUCCESS(rc))
    1877             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1878         if (rc == VERR_DBGC_BP_EXISTS)
    1879         {
    1880             rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);
    1881             if (VBOX_SUCCESS(rc))
    1882                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
    1883         }
    1884         int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);
    1885         AssertRC(rc2);
    1886     }
    1887     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
    1888 }
    1889 
    1890 
    1891 /**
    1892  * The 'u' command.
    1893  *
    1894  * @returns VBox status.
    1895  * @param   pCmd        Pointer to the command descriptor (as registered).
    1896  * @param   pCmdHlp     Pointer to command helper functions.
    1897  * @param   pVM         Pointer to the current VM (if any).
    1898  * @param   paArgs      Pointer to (readonly) array of arguments.
    1899  * @param   cArgs       Number of arguments in the array.
    1900  */
    1901 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1902 {
    1903     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1904 
    1905     /*
    1906      * Validate input.
    1907      */
    1908     if (    cArgs > 1
    1909         ||  (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
    1910         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
    1911     if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
    1912         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
    1913     if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
    1914         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
    1915 
    1916     /*
    1917      * Find address.
    1918      */
    1919     unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS;
    1920     if (!cArgs)
    1921     {
    1922         if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))
    1923         {
    1924             pDbgc->DisasmPos.enmType     = DBGCVAR_TYPE_GC_FAR;
    1925             pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);
    1926             pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM)  : CPUMGetHyperCS(pVM);
    1927             if (pDbgc->fRegCtxGuest)
    1928                 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST;
    1929             else
    1930                 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER;
    1931         }
    1932         pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE;
    1933     }
    1934     else
    1935         pDbgc->DisasmPos = paArgs[0];
    1936 
    1937     /*
    1938      * Range.
    1939      */
    1940     switch (pDbgc->DisasmPos.enmRangeType)
    1941     {
    1942         case DBGCVAR_RANGE_NONE:
    1943             pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    1944             pDbgc->DisasmPos.u64Range     = 10;
    1945             break;
    1946 
    1947         case DBGCVAR_RANGE_ELEMENTS:
    1948             if (pDbgc->DisasmPos.u64Range > 2048)
    1949                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
    1950             break;
    1951 
    1952         case DBGCVAR_RANGE_BYTES:
    1953             if (pDbgc->DisasmPos.u64Range > 65536)
    1954                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
    1955             break;
    1956 
    1957         default:
    1958             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType);
    1959     }
    1960 
    1961     /*
    1962      * Convert physical and host addresses to guest addresses.
    1963      */
    1964     int rc;
    1965     switch (pDbgc->DisasmPos.enmType)
    1966     {
    1967         case DBGCVAR_TYPE_GC_FLAT:
    1968         case DBGCVAR_TYPE_GC_FAR:
    1969             break;
    1970         case DBGCVAR_TYPE_GC_PHYS:
    1971         case DBGCVAR_TYPE_HC_FLAT:
    1972         case DBGCVAR_TYPE_HC_PHYS:
    1973         case DBGCVAR_TYPE_HC_FAR:
    1974         {
    1975             DBGCVAR VarTmp;
    1976             rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos);
    1977             if (VBOX_FAILURE(rc))
    1978                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Vrc .\n", pDbgc->DisasmPos, rc);
    1979             pDbgc->DisasmPos = VarTmp;
    1980             break;
    1981         }
    1982         default: AssertFailed(); break;
    1983     }
    1984 
    1985     /*
    1986      * Print address.
    1987      * todo: Change to list near.
    1988      */
    1989 #if 0
    1990     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DisasmPos);
    1991     if (VBOX_FAILURE(rc))
    1992         return rc;
     368extern const DBGCCMD    g_aCmdsCodeView[];
     369
    1993370#endif
    1994 
    1995     /*
    1996      * Do the disassembling.
    1997      */
    1998     unsigned    cTries = 32;
    1999     int         iRangeLeft = (int)pDbgc->DisasmPos.u64Range;
    2000     if (iRangeLeft == 0)                /* klugde for 'r'. */
    2001         iRangeLeft = -1;
    2002     for (;;)
    2003     {
    2004         /*
    2005          * Disassemble the instruction.
    2006          */
    2007         char        szDis[256];
    2008         uint32_t    cbInstr = 1;
    2009         if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT)
    2010             rc = DBGFR3DisasInstrEx(pVM, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
    2011         else
    2012             rc = DBGFR3DisasInstrEx(pVM, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
    2013         if (VBOX_SUCCESS(rc))
    2014         {
    2015             /* print it */
    2016             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]);
    2017             if (VBOX_FAILURE(rc))
    2018                 return rc;
    2019         }
    2020         else
    2021         {
    2022             /* bitch. */
    2023             int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");
    2024             if (VBOX_FAILURE(rc))
    2025                 return rc;
    2026             if (cTries-- > 0)
    2027                 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Too many disassembly failures. Giving up.\n");
    2028             cbInstr = 1;
    2029         }
    2030 
    2031         /* advance */
    2032         if (iRangeLeft < 0)             /* 'r' */
    2033             break;
    2034         if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
    2035             iRangeLeft--;
    2036         else
    2037             iRangeLeft -= cbInstr;
    2038         rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr);
    2039         if (VBOX_FAILURE(rc))
    2040             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DisasmPos, cbInstr);
    2041         if (iRangeLeft <= 0)
    2042             break;
    2043         fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER);
    2044     }
    2045 
    2046     NOREF(pCmd); NOREF(pResult);
    2047     return 0;
    2048 }
    2049 
    2050 
    2051 /**
    2052  * The 'ls' command.
    2053  *
    2054  * @returns VBox status.
    2055  * @param   pCmd        Pointer to the command descriptor (as registered).
    2056  * @param   pCmdHlp     Pointer to command helper functions.
    2057  * @param   pVM         Pointer to the current VM (if any).
    2058  * @param   paArgs      Pointer to (readonly) array of arguments.
    2059  * @param   cArgs       Number of arguments in the array.
    2060  */
    2061 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2062 {
    2063     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2064 
    2065     /*
    2066      * Validate input.
    2067      */
    2068     if (    cArgs > 1
    2069         ||  (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
    2070         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
    2071     if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
    2072         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");
    2073     if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))
    2074         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");
    2075 
    2076     /*
    2077      * Find address.
    2078      */
    2079     if (!cArgs)
    2080     {
    2081         if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))
    2082         {
    2083             pDbgc->SourcePos.enmType     = DBGCVAR_TYPE_GC_FAR;
    2084             pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);
    2085             pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM)  : CPUMGetHyperCS(pVM);
    2086         }
    2087         pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE;
    2088     }
    2089     else
    2090         pDbgc->SourcePos = paArgs[0];
    2091 
    2092     /*
    2093      * Ensure the the source address is flat GC.
    2094      */
    2095     switch (pDbgc->SourcePos.enmType)
    2096     {
    2097         case DBGCVAR_TYPE_GC_FLAT:
    2098             break;
    2099         case DBGCVAR_TYPE_GC_PHYS:
    2100         case DBGCVAR_TYPE_GC_FAR:
    2101         case DBGCVAR_TYPE_HC_FLAT:
    2102         case DBGCVAR_TYPE_HC_PHYS:
    2103         case DBGCVAR_TYPE_HC_FAR:
    2104         {
    2105             int rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos);
    2106             if (VBOX_FAILURE(rc))
    2107                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid address or address type. (rc=%d)\n", rc);
    2108             break;
    2109         }
    2110         default: AssertFailed(); break;
    2111     }
    2112 
    2113     /*
    2114      * Range.
    2115      */
    2116     switch (pDbgc->SourcePos.enmRangeType)
    2117     {
    2118         case DBGCVAR_RANGE_NONE:
    2119             pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    2120             pDbgc->SourcePos.u64Range     = 10;
    2121             break;
    2122 
    2123         case DBGCVAR_RANGE_ELEMENTS:
    2124             if (pDbgc->SourcePos.u64Range > 2048)
    2125                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");
    2126             break;
    2127 
    2128         case DBGCVAR_RANGE_BYTES:
    2129             if (pDbgc->SourcePos.u64Range > 65536)
    2130                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
    2131             break;
    2132 
    2133         default:
    2134             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);
    2135     }
    2136 
    2137     /*
    2138      * Do the disassembling.
    2139      */
    2140     bool        fFirst = 1;
    2141     DBGFLINE    LinePrev = { 0, 0, "" };
    2142     int         iRangeLeft = (int)pDbgc->SourcePos.u64Range;
    2143     if (iRangeLeft == 0)                /* klugde for 'r'. */
    2144         iRangeLeft = -1;
    2145     for (;;)
    2146     {
    2147         /*
    2148          * Get line info.
    2149          */
    2150         DBGFLINE    Line;
    2151         RTGCINTPTR  off;
    2152         int rc = DBGFR3LineByAddr(pVM, pDbgc->SourcePos.u.GCFlat, &off, &Line);
    2153         if (VBOX_FAILURE(rc))
    2154             return VINF_SUCCESS;
    2155 
    2156         unsigned cLines = 0;
    2157         if (memcmp(&Line, &LinePrev, sizeof(Line)))
    2158         {
    2159             /*
    2160              * Print filenamename
    2161              */
    2162             if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename))
    2163                 fFirst = true;
    2164             if (fFirst)
    2165             {
    2166                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "[%s @ %d]\n", Line.szFilename, Line.uLineNo);
    2167                 if (VBOX_FAILURE(rc))
    2168                     return rc;
    2169             }
    2170 
    2171             /*
    2172              * Try open the file and read the line.
    2173              */
    2174             FILE *phFile = fopen(Line.szFilename, "r");
    2175             if (phFile)
    2176             {
    2177                 /* Skip ahead to the desired line. */
    2178                 char szLine[4096];
    2179                 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1;
    2180                 if (cBefore > 7)
    2181                     cBefore = 0;
    2182                 unsigned cLeft = Line.uLineNo - cBefore;
    2183                 while (cLeft > 0)
    2184                 {
    2185                     szLine[0] = '\0';
    2186                     if (!fgets(szLine, sizeof(szLine), phFile))
    2187                         break;
    2188                     cLeft--;
    2189                 }
    2190                 if (!cLeft)
    2191                 {
    2192                     /* print the before lines */
    2193                     for (;;)
    2194                     {
    2195                         size_t cch = strlen(szLine);
    2196                         while (cch > 0 && (szLine[cch - 1] == '\r' ||  szLine[cch - 1] == '\n' || isspace(szLine[cch - 1])) )
    2197                             szLine[--cch] = '\0';
    2198                         if (cBefore-- <= 0)
    2199                             break;
    2200 
    2201                         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "         %4d: %s\n", Line.uLineNo - cBefore - 1, szLine);
    2202                         szLine[0] = '\0';
    2203                         fgets(szLine, sizeof(szLine), phFile);
    2204                         cLines++;
    2205                     }
    2206                     /* print the actual line */
    2207                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine);
    2208                 }
    2209                 fclose(phFile);
    2210                 if (VBOX_FAILURE(rc))
    2211                     return rc;
    2212                 fFirst = false;
    2213             }
    2214             else
    2215                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);
    2216 
    2217             LinePrev = Line;
    2218         }
    2219 
    2220 
    2221         /*
    2222          * Advance
    2223          */
    2224         if (iRangeLeft < 0)             /* 'r' */
    2225             break;
    2226         if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)
    2227             iRangeLeft -= cLines;
    2228         else
    2229             iRangeLeft -= 1;
    2230         rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1);
    2231         if (VBOX_FAILURE(rc))
    2232             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1);
    2233         if (iRangeLeft <= 0)
    2234             break;
    2235     }
    2236 
    2237     NOREF(pCmd); NOREF(pResult);
    2238     return 0;
    2239 }
    2240 
    2241 
    2242 /**
    2243  * The 'r' command.
    2244  *
    2245  * @returns VBox status.
    2246  * @param   pCmd        Pointer to the command descriptor (as registered).
    2247  * @param   pCmdHlp     Pointer to command helper functions.
    2248  * @param   pVM         Pointer to the current VM (if any).
    2249  * @param   paArgs      Pointer to (readonly) array of arguments.
    2250  * @param   cArgs       Number of arguments in the array.
    2251  */
    2252 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2253 {
    2254     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2255 
    2256     if (pDbgc->fRegCtxGuest)
    2257         return dbgcCmdRegGuest(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
    2258     else
    2259         return dbgcCmdRegHyper(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);
    2260 }
    2261 
    2262 
    2263 /**
    2264  * Common worker for the dbgcCmdReg*() commands.
    2265  *
    2266  * @returns VBox status.
    2267  * @param   pCmd        Pointer to the command descriptor (as registered).
    2268  * @param   pCmdHlp     Pointer to command helper functions.
    2269  * @param   pVM         Pointer to the current VM (if any).
    2270  * @param   paArgs      Pointer to (readonly) array of arguments.
    2271  * @param   cArgs       Number of arguments in the array.
    2272  * @param   pszPrefix   The symbol prefix.
    2273  */
    2274 static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult, const char *pszPrefix)
    2275 {
    2276     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2277 
    2278     /*
    2279      * cArgs == 0: Show all
    2280      */
    2281     if (cArgs == 0)
    2282     {
    2283         /*
    2284          * Get register context.
    2285          */
    2286         int             rc;
    2287         PCPUMCTX        pCtx;
    2288         PCCPUMCTXCORE   pCtxCore;
    2289         if (!*pszPrefix)
    2290         {
    2291             rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);
    2292             pCtxCore = CPUMGetGuestCtxCore(pVM);
    2293         }
    2294         else
    2295         {
    2296             rc = CPUMQueryHyperCtxPtr(pVM, &pCtx);
    2297             pCtxCore = CPUMGetHyperCtxCore(pVM);
    2298         }
    2299         if (VBOX_FAILURE(rc))
    2300             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Getting register context\n");
    2301 
    2302         /*
    2303          * Format the flags.
    2304          */
    2305         static struct
    2306         {
    2307             const char *pszSet; const char *pszClear; uint32_t fFlag;
    2308         }   aFlags[] =
    2309         {
    2310             { "vip",NULL, X86_EFL_VIP },
    2311             { "vif",NULL, X86_EFL_VIF },
    2312             { "ac", NULL, X86_EFL_AC },
    2313             { "vm", NULL, X86_EFL_VM },
    2314             { "rf", NULL, X86_EFL_RF },
    2315             { "nt", NULL, X86_EFL_NT },
    2316             { "ov", "nv", X86_EFL_OF },
    2317             { "dn", "up", X86_EFL_DF },
    2318             { "ei", "di", X86_EFL_IF },
    2319             { "tf", NULL, X86_EFL_TF },
    2320             { "nt", "pl", X86_EFL_SF },
    2321             { "nz", "zr", X86_EFL_ZF },
    2322             { "ac", "na", X86_EFL_AF },
    2323             { "po", "pe", X86_EFL_PF },
    2324             { "cy", "nc", X86_EFL_CF },
    2325         };
    2326         char szEFlags[80];
    2327         char *psz = szEFlags;
    2328         uint32_t efl = pCtxCore->eflags.u32;
    2329         for (unsigned i = 0; i < ELEMENTS(aFlags); i++)
    2330         {
    2331             const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
    2332             if (pszAdd)
    2333             {
    2334                 strcpy(psz, pszAdd);
    2335                 psz += strlen(pszAdd);
    2336                 *psz++ = ' ';
    2337             }
    2338         }
    2339         psz[-1] = '\0';
    2340 
    2341 
    2342         /*
    2343          * Format the registers.
    2344          */
    2345         if (pDbgc->fRegTerse)
    2346         {
    2347             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    2348                 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
    2349                 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
    2350                 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x               %seflags=%08x\n",
    2351                 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
    2352                 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,
    2353                 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,
    2354                 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);
    2355         }
    2356         else
    2357         {
    2358             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    2359                 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
    2360                 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
    2361                 "%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"
    2362                 "%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"
    2363                 "%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"
    2364                 "%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"
    2365                 "%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"
    2366                 "%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"
    2367                 "%sgdtr=%08x:%04x  %sidtr=%08x:%04x  %seflags=%08x\n"
    2368                 "%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"
    2369                 "%str  ={%04x base=%08x limit=%08x flags=%08x}\n"
    2370                 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
    2371                 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"
    2372                 ,
    2373                 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,
    2374                 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
    2375                 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0,  pszPrefix, pCtx->dr1,
    2376                 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2,  pszPrefix, pCtx->dr3,
    2377                 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4,  pszPrefix, pCtx->dr5,
    2378                 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6,  pszPrefix, pCtx->dr7,
    2379                 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0,  pszPrefix, pCtx->cr2,
    2380                 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3,  pszPrefix, pCtx->cr4,
    2381                 pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,
    2382                 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,
    2383                 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,
    2384                 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,
    2385                 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);
    2386         }
    2387 
    2388         /*
    2389          * Disassemble one instruction at cs:eip.
    2390          */
    2391         return pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pCtx->cs, pCtx->eip);
    2392     }
    2393 
    2394     /*
    2395      * cArgs == 1: Show the register.
    2396      * cArgs == 2: Modify the register.
    2397      */
    2398     if (    cArgs == 1
    2399         ||  cArgs == 2)
    2400     {
    2401         /* locate the register symbol. */
    2402         const char *pszReg = paArgs[0].u.pszString;
    2403         if (    *pszPrefix
    2404             &&  pszReg[0] != *pszPrefix)
    2405         {
    2406             /* prepend the prefix. */
    2407             char *psz = (char *)alloca(strlen(pszReg) + 2);
    2408             psz[0] = *pszPrefix;
    2409             strcpy(psz + 1, paArgs[0].u.pszString);
    2410             pszReg = psz;
    2411         }
    2412         PCDBGCSYM pSym = dbgcLookupRegisterSymbol(pDbgc, pszReg);
    2413         if (!pSym)
    2414             return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);
    2415 
    2416         /* show the register */
    2417         if (cArgs == 1)
    2418         {
    2419             DBGCVAR Var;
    2420             memset(&Var, 0, sizeof(Var));
    2421             int rc = pSym->pfnGet(pSym, pCmdHlp, DBGCVAR_TYPE_NUMBER, &Var);
    2422             if (VBOX_FAILURE(rc))
    2423                 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed getting value for register '%s'.\n", pszReg);
    2424             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s=%Dv\n", pszReg, &Var);
    2425         }
    2426 
    2427         /* change the register */
    2428         int rc = pSym->pfnSet(pSym, pCmdHlp, &paArgs[1]);
    2429         if (VBOX_FAILURE(rc))
    2430             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed setting value for register '%s'.\n", pszReg);
    2431         return VINF_SUCCESS;
    2432     }
    2433 
    2434 
    2435     NOREF(pCmd); NOREF(paArgs); NOREF(pResult);
    2436     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Huh? cArgs=%d Expected 0, 1 or 2!\n", cArgs);
    2437 }
    2438 
    2439 
    2440 /**
    2441  * The 'rg' command.
    2442  *
    2443  * @returns VBox status.
    2444  * @param   pCmd        Pointer to the command descriptor (as registered).
    2445  * @param   pCmdHlp     Pointer to command helper functions.
    2446  * @param   pVM         Pointer to the current VM (if any).
    2447  * @param   paArgs      Pointer to (readonly) array of arguments.
    2448  * @param   cArgs       Number of arguments in the array.
    2449  */
    2450 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2451 {
    2452     return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, "");
    2453 }
    2454 
    2455 
    2456 /**
    2457  * The 'rh' command.
    2458  *
    2459  * @returns VBox status.
    2460  * @param   pCmd        Pointer to the command descriptor (as registered).
    2461  * @param   pCmdHlp     Pointer to command helper functions.
    2462  * @param   pVM         Pointer to the current VM (if any).
    2463  * @param   paArgs      Pointer to (readonly) array of arguments.
    2464  * @param   cArgs       Number of arguments in the array.
    2465  */
    2466 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2467 {
    2468     return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, ".");
    2469 }
    2470 
    2471 
    2472 /**
    2473  * The 'rt' command.
    2474  *
    2475  * @returns VBox status.
    2476  * @param   pCmd        Pointer to the command descriptor (as registered).
    2477  * @param   pCmdHlp     Pointer to command helper functions.
    2478  * @param   pVM         Pointer to the current VM (if any).
    2479  * @param   paArgs      Pointer to (readonly) array of arguments.
    2480  * @param   cArgs       Number of arguments in the array.
    2481  */
    2482 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2483 {
    2484     NOREF(pCmd); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    2485 
    2486     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2487     pDbgc->fRegTerse = !pDbgc->fRegTerse;
    2488     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");
    2489 }
    2490 
    2491 
    2492 /**
    2493  * The 't' command.
    2494  *
    2495  * @returns VBox status.
    2496  * @param   pCmd        Pointer to the command descriptor (as registered).
    2497  * @param   pCmdHlp     Pointer to command helper functions.
    2498  * @param   pVM         Pointer to the current VM (if any).
    2499  * @param   paArgs      Pointer to (readonly) array of arguments.
    2500  * @param   cArgs       Number of arguments in the array.
    2501  */
    2502 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2503 {
    2504     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2505 
    2506     int rc = DBGFR3Step(pVM);
    2507     if (VBOX_SUCCESS(rc))
    2508         pDbgc->fReady = false;
    2509     else
    2510         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);
    2511 
    2512     NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    2513     return rc;
    2514 }
    2515 
    2516 
    2517 /**
    2518  * The 'k', 'kg' and 'kh' commands.
    2519  *
    2520  * @returns VBox status.
    2521  * @param   pCmd        Pointer to the command descriptor (as registered).
    2522  * @param   pCmdHlp     Pointer to command helper functions.
    2523  * @param   pVM         Pointer to the current VM (if any).
    2524  * @param   paArgs      Pointer to (readonly) array of arguments.
    2525  * @param   cArgs       Number of arguments in the array.
    2526  */
    2527 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2528 {
    2529     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2530 
    2531     /*
    2532      * Figure which context we're called for.
    2533      */
    2534     bool fGuest = pCmd->pszCmd[1] == 'g'
    2535                || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest);
    2536 
    2537 
    2538     DBGFSTACKFRAME Frame;
    2539     memset(&Frame, 0, sizeof(Frame));
    2540     int rc;
    2541     if (fGuest)
    2542         rc = DBGFR3StackWalkBeginGuest(pVM, &Frame);
    2543     else
    2544         rc = DBGFR3StackWalkBeginHyper(pVM, &Frame);
    2545     if (VBOX_FAILURE(rc))
    2546         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to begin stack walk, rc=%Vrc\n", rc);
    2547 
    2548     /*
    2549      * Print header.
    2550      *                                      12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol
    2551      */
    2552     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP      Ret EBP  Ret CS:EIP    Arg0     Arg1     Arg2     Arg3     CS:EIP / Symbol [line]\n");
    2553     if (VBOX_FAILURE(rc))
    2554         return rc;
    2555     do
    2556     {
    2557         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
    2558                                 (uint32_t)Frame.AddrFrame.off,
    2559                                 (uint32_t)Frame.AddrReturnFrame.off,
    2560                                 (uint32_t)Frame.AddrReturnPC.Sel,
    2561                                 (uint32_t)Frame.AddrReturnPC.off,
    2562                                 Frame.Args.au32[0],
    2563                                 Frame.Args.au32[1],
    2564                                 Frame.Args.au32[2],
    2565                                 Frame.Args.au32[3]);
    2566         if (VBOX_FAILURE(rc))
    2567             return rc;
    2568         if (!Frame.pSymPC)
    2569             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);
    2570         else
    2571         {
    2572             RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */
    2573             if (offDisp > 0)
    2574                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);
    2575             else if (offDisp < 0)
    2576                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);
    2577             else
    2578                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s", Frame.pSymPC->szName);
    2579         }
    2580         if (VBOX_SUCCESS(rc) && Frame.pLinePC)
    2581             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);
    2582         if (VBOX_SUCCESS(rc))
    2583             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    2584         if (VBOX_FAILURE(rc))
    2585             return rc;
    2586 
    2587         /* next */
    2588         rc = DBGFR3StackWalkNext(pVM, &Frame);
    2589     } while (VBOX_SUCCESS(rc));
    2590 
    2591     NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    2592     return VINF_SUCCESS;
    2593 }
    2594 
    2595 
    2596 static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP /*pCmdHlp*/, PCX86DESC64 /*pDesc*/, unsigned /*iEntry*/, bool /* fHyper */, bool * /*fDblEntry*/)
    2597 {
    2598     /* GUEST64 */
    2599     return VINF_SUCCESS;
    2600 }
    2601 
    2602 
    2603 /**
    2604  * Wroker function that displays one descriptor entry (GDT, LDT, IDT).
    2605  *
    2606  * @returns pfnPrintf status code.
    2607  * @param   pCmdHlp     The DBGC command helpers.
    2608  * @param   pDesc       The descriptor to display.
    2609  * @param   iEntry      The descriptor entry number.
    2610  * @param   fHyper      Whether the selector belongs to the hypervisor or not.
    2611  */
    2612 static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper)
    2613 {
    2614     int rc;
    2615 
    2616     const char *pszHyper = fHyper ? " HYPER" : "";
    2617     const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";
    2618     if (pDesc->Gen.u1DescType)
    2619     {
    2620         static const char * const s_apszTypes[] =
    2621         {
    2622             "DataRO", /* 0 Read-Only */
    2623             "DataRO", /* 1 Read-Only - Accessed */
    2624             "DataRW", /* 2 Read/Write  */
    2625             "DataRW", /* 3 Read/Write - Accessed  */
    2626             "DownRO", /* 4 Expand-down, Read-Only  */
    2627             "DownRO", /* 5 Expand-down, Read-Only - Accessed */
    2628             "DownRW", /* 6 Expand-down, Read/Write  */
    2629             "DownRO", /* 7 Expand-down, Read/Write - Accessed */
    2630             "CodeEO", /* 8 Execute-Only */
    2631             "CodeEO", /* 9 Execute-Only - Accessed */
    2632             "CodeER", /* A Execute/Readable */
    2633             "CodeER", /* B Execute/Readable - Accessed */
    2634             "ConfE0", /* C Conforming, Execute-Only */
    2635             "ConfE0", /* D Conforming, Execute-Only - Accessed */
    2636             "ConfER", /* E Conforming, Execute/Readable */
    2637             "ConfER"  /* F Conforming, Execute/Readable - Accessed */
    2638         };
    2639         const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";
    2640         const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
    2641         const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : "   ";
    2642         uint32_t u32Base = pDesc->Gen.u16BaseLow
    2643                          | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
    2644                          | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
    2645         uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
    2646         if (pDesc->Gen.u1Granularity)
    2647             cbLimit <<= PAGE_SHIFT;
    2648 
    2649         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",
    2650                                 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
    2651                                 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,
    2652                                 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved, pszHyper);
    2653     }
    2654     else
    2655     {
    2656         static const char * const s_apszTypes[] =
    2657         {
    2658             "Ill-0 ", /* 0 0000 Reserved (Illegal) */
    2659             "Tss16A", /* 1 0001 Available 16-bit TSS */
    2660             "LDT   ", /* 2 0010 LDT */
    2661             "Tss16B", /* 3 0011 Busy 16-bit TSS */
    2662             "Call16", /* 4 0100 16-bit Call Gate */
    2663             "TaskG ", /* 5 0101 Task Gate */
    2664             "Int16 ", /* 6 0110 16-bit Interrupt Gate */
    2665             "Trap16", /* 7 0111 16-bit Trap Gate */
    2666             "Ill-8 ", /* 8 1000 Reserved (Illegal) */
    2667             "Tss32A", /* 9 1001 Available 32-bit TSS */
    2668             "Ill-A ", /* A 1010 Reserved (Illegal) */
    2669             "Tss32B", /* B 1011 Busy 32-bit TSS */
    2670             "Call32", /* C 1100 32-bit Call Gate */
    2671             "Ill-D ", /* D 1101 Reserved (Illegal) */
    2672             "Int32 ", /* E 1110 32-bit Interrupt Gate */
    2673             "Trap32"  /* F 1111 32-bit Trap Gate */
    2674         };
    2675         switch (pDesc->Gen.u4Type)
    2676         {
    2677             /* raw */
    2678             case X86_SEL_TYPE_SYS_UNDEFINED:
    2679             case X86_SEL_TYPE_SYS_UNDEFINED2:
    2680             case X86_SEL_TYPE_SYS_UNDEFINED4:
    2681             case X86_SEL_TYPE_SYS_UNDEFINED3:
    2682                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs   DPL=%d %s%s\n",
    2683                                         iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,
    2684                                         pDesc->Gen.u2Dpl, pszPresent, pszHyper);
    2685                 break;
    2686 
    2687             case X86_SEL_TYPE_SYS_286_TSS_AVAIL:
    2688             case X86_SEL_TYPE_SYS_386_TSS_AVAIL:
    2689             case X86_SEL_TYPE_SYS_286_TSS_BUSY:
    2690             case X86_SEL_TYPE_SYS_386_TSS_BUSY:
    2691             case X86_SEL_TYPE_SYS_LDT:
    2692             {
    2693                 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";
    2694                 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";
    2695                 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : "   ";
    2696                 uint32_t u32Base = pDesc->Gen.u16BaseLow
    2697                                  | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)
    2698                                  | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);
    2699                 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);
    2700                 if (pDesc->Gen.u1Granularity)
    2701                     cbLimit <<= PAGE_SHIFT;
    2702 
    2703                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",
    2704                                         iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,
    2705                                         pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig,
    2706                                         pDesc->Gen.u1Available, pDesc->Gen.u1Reserved | (pDesc->Gen.u1DefBig << 1),
    2707                                         pszHyper);
    2708                 break;
    2709             }
    2710 
    2711             case X86_SEL_TYPE_SYS_TASK_GATE:
    2712             {
    2713                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s TSS=%04x                  DPL=%d %s%s\n",
    2714                                         iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1],
    2715                                         pDesc->Gen.u2Dpl, pszPresent, pszHyper);
    2716                 break;
    2717             }
    2718 
    2719             case X86_SEL_TYPE_SYS_286_CALL_GATE:
    2720             case X86_SEL_TYPE_SYS_386_CALL_GATE:
    2721             {
    2722                 unsigned cParams = pDesc->au8[0] & 0x1f;
    2723                 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";
    2724                 RTSEL sel = pDesc->au16[1];
    2725                 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
    2726                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x     DPL=%d %s %s=%d%s\n",
    2727                                         iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
    2728                                         pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);
    2729                 break;
    2730             }
    2731 
    2732             case X86_SEL_TYPE_SYS_286_INT_GATE:
    2733             case X86_SEL_TYPE_SYS_386_INT_GATE:
    2734             case X86_SEL_TYPE_SYS_286_TRAP_GATE:
    2735             case X86_SEL_TYPE_SYS_386_TRAP_GATE:
    2736             {
    2737                 RTSEL sel = pDesc->au16[1];
    2738                 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);
    2739                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x     DPL=%d %s%s\n",
    2740                                         iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,
    2741                                         pDesc->Gen.u2Dpl, pszPresent, pszHyper);
    2742                 break;
    2743             }
    2744 
    2745             /* impossible, just it's necessary to keep gcc happy. */
    2746             default:
    2747                 return VINF_SUCCESS;
    2748         }
    2749     }
    2750     return rc;
    2751 }
    2752 
    2753 
    2754 /**
    2755  * The 'dg', 'dga', 'dl' and 'dla' commands.
    2756  *
    2757  * @returns VBox status.
    2758  * @param   pCmd        Pointer to the command descriptor (as registered).
    2759  * @param   pCmdHlp     Pointer to command helper functions.
    2760  * @param   pVM         Pointer to the current VM (if any).
    2761  * @param   paArgs      Pointer to (readonly) array of arguments.
    2762  * @param   cArgs       Number of arguments in the array.
    2763  */
    2764 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2765 {
    2766     /*
    2767      * Validate input.
    2768      */
    2769     if (!pVM)
    2770         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    2771 
    2772     /*
    2773      * Get the CPU mode, check which command variation this is
    2774      * and fix a default parameter if needed.
    2775      */
    2776     CPUMMODE enmMode = CPUMGetGuestMode(pVM);
    2777     bool fGdt = pCmd->pszCmd[1] == 'g';
    2778     bool fAll = pCmd->pszCmd[2] == 'a';
    2779 
    2780     DBGCVAR Var;
    2781     if (!cArgs)
    2782     {
    2783         cArgs = 1;
    2784         paArgs = &Var;
    2785         Var.enmType = DBGCVAR_TYPE_NUMBER;
    2786         Var.u.u64Number = fGdt ? 0 : 4;
    2787         Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    2788         Var.u64Range = 1024;
    2789     }
    2790 
    2791     /*
    2792      * Process the arguments.
    2793      */
    2794     for (unsigned i = 0; i < cArgs; i++)
    2795     {
    2796          /*
    2797           * Retrive the selector value from the argument.
    2798           * The parser may confuse pointers and numbers if more than one
    2799           * argument is given, that that into account.
    2800           */
    2801         /* check that what've got makes sense as we don't trust the parser yet. */
    2802         if (    paArgs[i].enmType != DBGCVAR_TYPE_NUMBER
    2803             &&  !DBGCVAR_ISPOINTER(paArgs[i].enmType))
    2804             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number or pointer type but %d.\n", i, paArgs[i].enmType);
    2805         uint64_t u64;
    2806         unsigned cSels = 1;
    2807         switch (paArgs[i].enmType)
    2808         {
    2809             case DBGCVAR_TYPE_NUMBER:
    2810                 u64 = paArgs[i].u.u64Number;
    2811                 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE)
    2812                     cSels = RT_MIN(paArgs[i].u64Range, 1024);
    2813                 break;
    2814             case DBGCVAR_TYPE_GC_FAR:   u64 = paArgs[i].u.GCFar.sel; break;
    2815             case DBGCVAR_TYPE_GC_FLAT:  u64 = paArgs[i].u.GCFlat; break;
    2816             case DBGCVAR_TYPE_GC_PHYS:  u64 = paArgs[i].u.GCPhys; break;
    2817             case DBGCVAR_TYPE_HC_FAR:   u64 = paArgs[i].u.HCFar.sel; break;
    2818             case DBGCVAR_TYPE_HC_FLAT:  u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break;
    2819             case DBGCVAR_TYPE_HC_PHYS:  u64 = paArgs[i].u.HCPhys; break;
    2820             default:                    u64 = _64K; break;
    2821         }
    2822         if (u64 < _64K)
    2823         {
    2824             unsigned Sel = (RTSEL)u64;
    2825 
    2826             /*
    2827              * Dump the specified range.
    2828              */
    2829             bool fSingle = cSels == 1;
    2830             while (     cSels-- > 0
    2831                    &&   Sel < _64K)
    2832             {
    2833                 SELMSELINFO SelInfo;
    2834                 int rc = SELMR3GetSelectorInfo(pVM, Sel, &SelInfo);
    2835                 if (RT_SUCCESS(rc))
    2836                 {
    2837                     if (SelInfo.fRealMode)
    2838                         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x RealM   Bas=%04x     Lim=%04x\n",
    2839                                                 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit);
    2840                     else if (fAll || fSingle || SelInfo.Raw.Gen.u1Present)
    2841                     {
    2842                         if (enmMode == CPUMMODE_PROTECTED)
    2843                             rc = dbgcCmdDumpDTWorker32(pCmdHlp, (PX86DESC)&SelInfo.Raw, Sel, SelInfo.fHyper);
    2844                         else
    2845                         {
    2846                             bool fDblSkip = false;
    2847                             rc = dbgcCmdDumpDTWorker64(pCmdHlp, (PX86DESC64)&SelInfo.Raw, Sel, SelInfo.fHyper, &fDblSkip);
    2848                             if (fDblSkip)
    2849                                 Sel += 4;
    2850                         }
    2851                     }
    2852                 }
    2853                 else
    2854                 {
    2855                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %Vrc\n", Sel, rc);
    2856                     if (!fAll)
    2857                         return rc;
    2858                 }
    2859                 if (RT_FAILURE(rc))
    2860                     return rc;
    2861 
    2862                 /* next */
    2863                 Sel += 4;
    2864             }
    2865         }
    2866         else
    2867             pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds\n", u64);
    2868     }
    2869 
    2870     NOREF(pResult);
    2871     return VINF_SUCCESS;
    2872 }
    2873 
    2874 
    2875 /**
    2876  * The 'di' and 'dia' commands.
    2877  *
    2878  * @returns VBox status.
    2879  * @param   pCmd        Pointer to the command descriptor (as registered).
    2880  * @param   pCmdHlp     Pointer to command helper functions.
    2881  * @param   pVM         Pointer to the current VM (if any).
    2882  * @param   paArgs      Pointer to (readonly) array of arguments.
    2883  * @param   cArgs       Number of arguments in the array.
    2884  */
    2885 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    2886 {
    2887     /*
    2888      * Validate input.
    2889      */
    2890     if (!pVM)
    2891         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    2892 
    2893     /*
    2894      * Establish some stuff like the current IDTR and CPU mode,
    2895      * and fix a default parameter.
    2896      */
    2897     uint16_t cbLimit;
    2898     RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVM, &cbLimit);
    2899     CPUMMODE enmMode = CPUMGetGuestMode(pVM);
    2900     unsigned cbEntry;
    2901     switch (enmMode)
    2902     {
    2903         case CPUMMODE_REAL:         cbEntry = sizeof(RTFAR16); break;
    2904         case CPUMMODE_PROTECTED:    cbEntry = sizeof(X86DESC); break;
    2905         case CPUMMODE_LONG:         cbEntry = sizeof(X86DESC64); break;
    2906         default:
    2907             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid CPU mode %d.\n", enmMode);
    2908     }
    2909 
    2910     bool fAll = pCmd->pszCmd[2] == 'a';
    2911     DBGCVAR Var;
    2912     if (!cArgs)
    2913     {
    2914         cArgs = 1;
    2915         paArgs = &Var;
    2916         Var.enmType = DBGCVAR_TYPE_NUMBER;
    2917         Var.u.u64Number = 0;
    2918         Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    2919         Var.u64Range = 256;
    2920     }
    2921 
    2922     /*
    2923      * Process the arguments.
    2924      */
    2925     for (unsigned i = 0; i < cArgs; i++)
    2926     {
    2927         /* check that what've got makes sense as we don't trust the parser yet. */
    2928         if (paArgs[i].enmType != DBGCVAR_TYPE_NUMBER)
    2929             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number type but %d.\n", i, paArgs[i].enmType);
    2930         if (paArgs[i].u.u64Number < 256)
    2931         {
    2932             RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number;
    2933             unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE
    2934                            ? paArgs[i].u64Range
    2935                            : 1;
    2936             bool fSingle = cInts == 1;
    2937             while (     cInts-- > 0
    2938                    &&   iInt < 256)
    2939             {
    2940                 /*
    2941                  * Try read it.
    2942                  */
    2943                 union
    2944                 {
    2945                     RTFAR16 Real;
    2946                     X86DESC Prot;
    2947                     X86DESC64 Long;
    2948                 } u;
    2949                 if (iInt * cbEntry  + (cbEntry - 1) > cbLimit)
    2950                 {
    2951                     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x not within the IDT\n", (unsigned)iInt);
    2952                     if (!fAll && !fSingle)
    2953                         return VINF_SUCCESS;
    2954                 }
    2955                 DBGCVAR AddrVar;
    2956                 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT;
    2957                 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry;
    2958                 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE;
    2959                 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &u, cbEntry, &AddrVar, NULL);
    2960                 if (VBOX_FAILURE(rc))
    2961                     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt);
    2962 
    2963                 /*
    2964                  * Display it.
    2965                  */
    2966                 switch (enmMode)
    2967                 {
    2968                     case CPUMMODE_REAL:
    2969                         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %RTfp16\n", (unsigned)iInt, u.Real);
    2970                         /** @todo resolve 16:16 IDTE to a symbol */
    2971                         break;
    2972                     case CPUMMODE_PROTECTED:
    2973                         if (fAll || fSingle || u.Prot.Gen.u1Present)
    2974                             rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false);
    2975                         break;
    2976                     case CPUMMODE_LONG:
    2977                         if (fAll || fSingle || u.Long.Gen.u1Present)
    2978                             rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL);
    2979                         break;
    2980                     default: break; /* to shut up gcc */
    2981                 }
    2982                 if (RT_FAILURE(rc))
    2983                     return rc;
    2984 
    2985                 /* next */
    2986                 iInt++;
    2987             }
    2988         }
    2989         else
    2990             pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number);
    2991     }
    2992 
    2993     NOREF(pResult);
    2994     return VINF_SUCCESS;
    2995 }
    2996 
    2997 
    2998 /**
    2999  * The 'da', 'dq', 'dd', 'dw' and 'db' commands.
    3000  *
    3001  * @returns VBox status.
    3002  * @param   pCmd        Pointer to the command descriptor (as registered).
    3003  * @param   pCmdHlp     Pointer to command helper functions.
    3004  * @param   pVM         Pointer to the current VM (if any).
    3005  * @param   paArgs      Pointer to (readonly) array of arguments.
    3006  * @param   cArgs       Number of arguments in the array.
    3007  */
    3008 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3009 {
    3010     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3011 
    3012     /*
    3013      * Validate input.
    3014      */
    3015     if (    cArgs > 1
    3016         ||  (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))
    3017         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
    3018     if (!pVM)
    3019         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    3020 
    3021     /*
    3022      * Figure out the element size.
    3023      */
    3024     unsigned    cbElement;
    3025     bool        fAscii = false;
    3026     switch (pCmd->pszCmd[1])
    3027     {
    3028         default:
    3029         case 'b':   cbElement = 1; break;
    3030         case 'w':   cbElement = 2; break;
    3031         case 'd':   cbElement = 4; break;
    3032         case 'q':   cbElement = 8; break;
    3033         case 'a':
    3034             cbElement = 1;
    3035             fAscii = true;
    3036             break;
    3037         case '\0':
    3038             fAscii = !!(pDbgc->cbDumpElement & 0x80000000);
    3039             cbElement = pDbgc->cbDumpElement & 0x7fffffff;
    3040             if (!cbElement)
    3041                 cbElement = 1;
    3042             break;
    3043     }
    3044 
    3045     /*
    3046      * Find address.
    3047      */
    3048     if (!cArgs)
    3049         pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE;
    3050     else
    3051         pDbgc->DumpPos = paArgs[0];
    3052 
    3053     /*
    3054      * Range.
    3055      */
    3056     switch (pDbgc->DumpPos.enmRangeType)
    3057     {
    3058         case DBGCVAR_RANGE_NONE:
    3059             pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
    3060             pDbgc->DumpPos.u64Range     = 0x60;
    3061             break;
    3062 
    3063         case DBGCVAR_RANGE_ELEMENTS:
    3064             if (pDbgc->DumpPos.u64Range > 2048)
    3065                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");
    3066             pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;
    3067             pDbgc->DumpPos.u64Range     = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range;
    3068             break;
    3069 
    3070         case DBGCVAR_RANGE_BYTES:
    3071             if (pDbgc->DumpPos.u64Range > 65536)
    3072                 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");
    3073             break;
    3074 
    3075         default:
    3076             return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);
    3077     }
    3078 
    3079     /*
    3080      * Do the dumping.
    3081      */
    3082     pDbgc->cbDumpElement = cbElement | (fAscii << 31);
    3083     int     cbLeft = (int)pDbgc->DumpPos.u64Range;
    3084     uint8_t u8Prev = '\0';
    3085     for (;;)
    3086     {
    3087         /*
    3088          * Read memory.
    3089          */
    3090         char    achBuffer[16];
    3091         size_t  cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft);
    3092         size_t  cb = RT_MIN((int)sizeof(achBuffer), cbLeft);
    3093         int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &achBuffer, cbReq, &pDbgc->DumpPos, &cb);
    3094         if (VBOX_FAILURE(rc))
    3095         {
    3096             if (u8Prev && u8Prev != '\n')
    3097                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    3098             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos);
    3099         }
    3100 
    3101         /*
    3102          * Display it.
    3103          */
    3104         memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb);
    3105         if (!fAscii)
    3106         {
    3107             pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:", &pDbgc->DumpPos);
    3108             unsigned i;
    3109             for (i = 0; i < cb; i += cbElement)
    3110             {
    3111                 const char *pszSpace = " ";
    3112                 if (cbElement <= 2 && i == 8 && !fAscii)
    3113                     pszSpace = "-";
    3114                 switch (cbElement)
    3115                 {
    3116                     case 1: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%02x",    pszSpace, *(uint8_t *)&achBuffer[i]); break;
    3117                     case 2: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%04x",    pszSpace, *(uint16_t *)&achBuffer[i]); break;
    3118                     case 4: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%08x",    pszSpace, *(uint32_t *)&achBuffer[i]); break;
    3119                     case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;
    3120                 }
    3121             }
    3122 
    3123             /* chars column */
    3124             if (pDbgc->cbDumpElement == 1)
    3125             {
    3126                 while (i++ < sizeof(achBuffer))
    3127                     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "   ");
    3128                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "  ");
    3129                 for (i = 0; i < cb; i += cbElement)
    3130                 {
    3131                     uint8_t u8 = *(uint8_t *)&achBuffer[i];
    3132                     if (isprint(u8) && u8 < 127)
    3133                         pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
    3134                     else
    3135                         pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");
    3136                 }
    3137             }
    3138             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    3139         }
    3140         else
    3141         {
    3142             /*
    3143              * We print up to the first zero and stop there.
    3144              * Only printables + '\t' and '\n' are printed.
    3145              */
    3146             if (!u8Prev)
    3147                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DumpPos);
    3148             uint8_t u8 = '\0';
    3149             unsigned i;
    3150             for (i = 0; i < cb; i++)
    3151             {
    3152                 u8Prev = u8;
    3153                 u8 = *(uint8_t *)&achBuffer[i];
    3154                 if (    u8 < 127
    3155                     && (    isprint(u8)
    3156                         ||  u8 == '\t'
    3157                         ||  u8 == '\n'))
    3158                     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);
    3159                 else if (!u8)
    3160                     break;
    3161                 else
    3162                     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\\x%x", u8);
    3163             }
    3164             if (u8 == '\0')
    3165                 cb = cbLeft = i + 1;
    3166             if (cbLeft - cb <= 0 && u8Prev != '\n')
    3167                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    3168         }
    3169 
    3170         /*
    3171          * Advance
    3172          */
    3173         cbLeft -= (int)cb;
    3174         rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb);
    3175         if (VBOX_FAILURE(rc))
    3176             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb);
    3177         if (cbLeft <= 0)
    3178             break;
    3179     }
    3180 
    3181     NOREF(pCmd); NOREF(pResult);
    3182     return VINF_SUCCESS;
    3183 }
    3184 
    3185 
    3186 /**
    3187  * Best guess at which paging mode currently applies to the guest
    3188  * paging structures.
    3189  *
    3190  * This have to come up with a decent answer even when the guest
    3191  * is in non-paged protected mode or real mode.
    3192  *
    3193  * @returns cr3.
    3194  * @param   pDbgc   The DBGC instance.
    3195  * @param   pfPAE   Where to store the page address extension indicator.
    3196  * @param   pfLME   Where to store the long mode enabled indicator.
    3197  * @param   pfPSE   Where to store the page size extension indicator.
    3198  * @param   pfPGE   Where to store the page global enabled indicator.
    3199  * @param   pfNXE   Where to store the no-execution enabled inidicator.
    3200  */
    3201 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
    3202 {
    3203     RTGCUINTREG cr4 = CPUMGetGuestCR4(pDbgc->pVM);
    3204     *pfPSE = !!(cr4 & X86_CR4_PSE);
    3205     *pfPGE = !!(cr4 & X86_CR4_PGE);
    3206     *pfPAE = !!(cr4 & X86_CR4_PAE);
    3207     *pfLME = CPUMGetGuestMode(pDbgc->pVM) == CPUMMODE_LONG;
    3208     *pfNXE = false; /* GUEST64 GUESTNX */
    3209     return CPUMGetGuestCR3(pDbgc->pVM);
    3210 }
    3211 
    3212 
    3213 /**
    3214  * Determin the shadow paging mode.
    3215  *
    3216  * @returns cr3.
    3217  * @param   pDbgc   The DBGC instance.
    3218  * @param   pfPAE   Where to store the page address extension indicator.
    3219  * @param   pfLME   Where to store the long mode enabled indicator.
    3220  * @param   pfPSE   Where to store the page size extension indicator.
    3221  * @param   pfPGE   Where to store the page global enabled indicator.
    3222  * @param   pfNXE   Where to store the no-execution enabled inidicator.
    3223  */
    3224 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)
    3225 {
    3226     *pfPSE = true;
    3227     *pfPGE = false;
    3228     switch (PGMGetShadowMode(pDbgc->pVM))
    3229     {
    3230         default:
    3231         case PGMMODE_32_BIT:
    3232             *pfPAE = *pfLME = *pfNXE = false;
    3233             break;
    3234         case PGMMODE_PAE:
    3235             *pfLME = *pfNXE = false;
    3236             *pfPAE = true;
    3237             break;
    3238         case PGMMODE_PAE_NX:
    3239             *pfLME = false;
    3240             *pfPAE = *pfNXE = true;
    3241             break;
    3242         case PGMMODE_AMD64:
    3243             *pfNXE = false;
    3244             *pfPAE = *pfLME = true;
    3245             break;
    3246         case PGMMODE_AMD64_NX:
    3247             *pfPAE = *pfLME = *pfNXE = true;
    3248             break;
    3249     }
    3250     return PGMGetHyperCR3(pDbgc->pVM);
    3251 }
    3252 
    3253 
    3254 /**
    3255  * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands.
    3256  *
    3257  * @returns VBox status.
    3258  * @param   pCmd        Pointer to the command descriptor (as registered).
    3259  * @param   pCmdHlp     Pointer to command helper functions.
    3260  * @param   pVM         Pointer to the current VM (if any).
    3261  * @param   paArgs      Pointer to (readonly) array of arguments.
    3262  * @param   cArgs       Number of arguments in the array.
    3263  */
    3264 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3265 {
    3266     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3267 
    3268     /*
    3269      * Validate input.
    3270      */
    3271     if (    cArgs > 1
    3272         ||  (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
    3273         ||  (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
    3274         )
    3275         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
    3276     if (!pVM)
    3277         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    3278 
    3279     /*
    3280      * Guest or shadow page directories? Get the paging parameters.
    3281      */
    3282     bool fGuest = pCmd->pszCmd[3] != 'h';
    3283     if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
    3284         fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
    3285                ? pDbgc->fRegCtxGuest
    3286                : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
    3287 
    3288     bool fPAE, fLME, fPSE, fPGE, fNXE;
    3289     uint64_t cr3 = fGuest
    3290                  ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
    3291                  : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
    3292     const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
    3293 
    3294     /*
    3295      * Setup default arugment if none was specified.
    3296      * Fix address / index confusion.
    3297      */
    3298     DBGCVAR VarDefault;
    3299     if (!cArgs)
    3300     {
    3301         if (pCmd->pszCmd[3] == 'a')
    3302         {
    3303             if (fLME || fPAE)
    3304                 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");
    3305             if (fGuest)
    3306                 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3);
    3307             else
    3308                 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3);
    3309         }
    3310         else
    3311             DBGCVAR_INIT_GC_FLAT(&VarDefault, 0);
    3312         paArgs = &VarDefault;
    3313         cArgs = 1;
    3314     }
    3315     else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)
    3316     {
    3317         Assert(pCmd->pszCmd[3] != 'a');
    3318         VarDefault = paArgs[0];
    3319         if (VarDefault.u.u64Number <= 1024)
    3320         {
    3321             if (fPAE)
    3322                 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n");
    3323             if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry)
    3324                 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1);
    3325             VarDefault.u.u64Number <<= X86_PD_SHIFT;
    3326         }
    3327         VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT;
    3328         paArgs = &VarDefault;
    3329     }
    3330 
    3331     /*
    3332      * Locate the PDE to start displaying at.
    3333      *
    3334      * The 'dpda' command takes the address of a PDE, while the others are guest
    3335      * virtual address which PDEs should be displayed. So, 'dpda' is rather simple
    3336      * while the others require us to do all the tedious walking thru the paging
    3337      * hierarchy to find the intended PDE.
    3338      */
    3339     unsigned    iEntry = ~0U;           /* The page directory index. ~0U for 'dpta'. */
    3340     DBGCVAR     VarGCPtr;               /* The GC address corresponding to the current PDE (iEntry != ~0U). */
    3341     DBGCVAR     VarPDEAddr;             /* The address of the current PDE. */
    3342     unsigned    cEntries;               /* The number of entries to display. */
    3343     unsigned    cEntriesMax;            /* The max number of entries to display. */
    3344     int         rc;
    3345     if (pCmd->pszCmd[3] == 'a')
    3346     {
    3347         VarPDEAddr = paArgs[0];
    3348         switch (VarPDEAddr.enmRangeType)
    3349         {
    3350             case DBGCVAR_RANGE_BYTES:       cEntries = VarPDEAddr.u64Range / cbEntry; break;
    3351             case DBGCVAR_RANGE_ELEMENTS:    cEntries = VarPDEAddr.u64Range; break;
    3352             default:                        cEntries = 10; break;
    3353         }
    3354         cEntriesMax = PAGE_SIZE / cbEntry;
    3355     }
    3356     else
    3357     {
    3358         /*
    3359          * Determin the range.
    3360          */
    3361         switch (paArgs[0].enmRangeType)
    3362         {
    3363             case DBGCVAR_RANGE_BYTES:       cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
    3364             case DBGCVAR_RANGE_ELEMENTS:    cEntries = paArgs[0].u64Range; break;
    3365             default:                        cEntries = 10; break;
    3366         }
    3367 
    3368         /*
    3369          * Normalize the input address, it must be a flat GC address.
    3370          */
    3371         rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
    3372         if (VBOX_FAILURE(rc))
    3373             return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
    3374         if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
    3375         {
    3376             VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
    3377             VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
    3378         }
    3379         if (fPAE)
    3380             VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1);
    3381         else
    3382             VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1);
    3383 
    3384         /*
    3385          * Do the paging walk until we get to the page directory.
    3386          */
    3387         DBGCVAR VarCur;
    3388         if (fGuest)
    3389             DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
    3390         else
    3391             DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
    3392         if (fLME)
    3393         {
    3394             /* Page Map Level 4 Lookup. */
    3395             /* Check if it's a valid address first? */
    3396             VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
    3397             VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
    3398             X86PML4E Pml4e;
    3399             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
    3400             if (VBOX_FAILURE(rc))
    3401                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
    3402             if (!Pml4e.n.u1Present)
    3403                 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
    3404 
    3405             VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
    3406             Assert(fPAE);
    3407         }
    3408         if (fPAE)
    3409         {
    3410             /* Page directory pointer table. */
    3411             X86PDPE Pdpe;
    3412             VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);
    3413             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
    3414             if (VBOX_FAILURE(rc))
    3415                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
    3416             if (!Pdpe.n.u1Present)
    3417                 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
    3418 
    3419             iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;
    3420             VarPDEAddr = VarCur;
    3421             VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
    3422             VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE);
    3423         }
    3424         else
    3425         {
    3426             /* 32-bit legacy - CR3 == page directory. */
    3427             iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK;
    3428             VarPDEAddr = VarCur;
    3429             VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE);
    3430         }
    3431         cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
    3432         iEntry /= cbEntry;
    3433     }
    3434 
    3435     /* adjust cEntries */
    3436     cEntries = RT_MAX(1, cEntries);
    3437     cEntries = RT_MIN(cEntries, cEntriesMax);
    3438 
    3439     /*
    3440      * The display loop.
    3441      */
    3442     DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n",
    3443                      &VarPDEAddr, iEntry);
    3444     do
    3445     {
    3446         /*
    3447          * Read.
    3448          */
    3449         X86PDEPAE Pde;
    3450         Pde.u = 0;
    3451         rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL);
    3452         if (VBOX_FAILURE(rc))
    3453             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr);
    3454 
    3455         /*
    3456          * Display.
    3457          */
    3458         if (iEntry != ~0U)
    3459         {
    3460             DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
    3461             iEntry++;
    3462         }
    3463         if (fPSE && Pde.b.u1Size)
    3464             DBGCCmdHlpPrintf(pCmdHlp,
    3465                              fPAE
    3466                              ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
    3467                              :   "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
    3468                              Pde.u,
    3469                              Pde.u & X86_PDE_PAE_PG_MASK,
    3470                              Pde.b.u1Present        ? "p "  : "np",
    3471                              Pde.b.u1Write          ? "w"   : "r",
    3472                              Pde.b.u1User           ? "u"   : "s",
    3473                              Pde.b.u1Accessed       ? "a "  : "na",
    3474                              Pde.b.u1Dirty          ? "d "  : "nd",
    3475                              Pde.b.u3Available,
    3476                              Pde.b.u1Global         ? (fPGE ? "g" : "G") : " ",
    3477                              Pde.b.u1WriteThru      ? "pwt" : "   ",
    3478                              Pde.b.u1CacheDisable   ? "pcd" : "   ",
    3479                              Pde.b.u1PAT            ? "pat" : "",
    3480                              Pde.b.u1NoExecute      ? (fNXE ? "nx" : "NX") : "  ");
    3481         else
    3482             DBGCCmdHlpPrintf(pCmdHlp,
    3483                              fPAE
    3484                              ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s"
    3485                              :   "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s",
    3486                              Pde.u,
    3487                              Pde.u & X86_PDE_PAE_PG_MASK,
    3488                              Pde.n.u1Present        ? "p "  : "np",
    3489                              Pde.n.u1Write          ? "w"   : "r",
    3490                              Pde.n.u1User           ? "u"   : "s",
    3491                              Pde.n.u1Accessed       ? "a "  : "na",
    3492                              Pde.u & RT_BIT(6)      ? "6 "  : "  ",
    3493                              Pde.n.u3Available,
    3494                              Pde.u & RT_BIT(8)      ? "8"   : " ",
    3495                              Pde.n.u1WriteThru      ? "pwt" : "   ",
    3496                              Pde.n.u1CacheDisable   ? "pcd" : "   ",
    3497                              Pde.u & RT_BIT(7)      ? "7"   : "",
    3498                              Pde.n.u1NoExecute      ? (fNXE ? "nx" : "NX") : "  ");
    3499         if (Pde.u & UINT64_C(0x7fff000000000000))
    3500             DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000)));
    3501         rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
    3502         if (VBOX_FAILURE(rc))
    3503             return rc;
    3504 
    3505         /*
    3506          * Advance.
    3507          */
    3508         VarPDEAddr.u.u64Number += cbEntry;
    3509         if (iEntry != ~0U)
    3510             VarGCPtr.u.GCFlat += 1 << (fPAE ? X86_PD_PAE_SHIFT : X86_PD_SHIFT);
    3511     } while (cEntries-- > 0);
    3512 
    3513     NOREF(pResult);
    3514     return VINF_SUCCESS;
    3515 }
    3516 
    3517 
    3518 /**
    3519  * The 'dpdb' command.
    3520  *
    3521  * @returns VBox status.
    3522  * @param   pCmd        Pointer to the command descriptor (as registered).
    3523  * @param   pCmdHlp     Pointer to command helper functions.
    3524  * @param   pVM         Pointer to the current VM (if any).
    3525  * @param   paArgs      Pointer to (readonly) array of arguments.
    3526  * @param   cArgs       Number of arguments in the array.
    3527  */
    3528 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3529 {
    3530     if (!pVM)
    3531         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    3532     int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
    3533     int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
    3534     if (VBOX_FAILURE(rc1))
    3535         return rc1;
    3536     NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    3537     return rc2;
    3538 }
    3539 
    3540 
    3541 /**
    3542  * The 'dpg*' commands.
    3543  *
    3544  * @returns VBox status.
    3545  * @param   pCmd        Pointer to the command descriptor (as registered).
    3546  * @param   pCmdHlp     Pointer to command helper functions.
    3547  * @param   pVM         Pointer to the current VM (if any).
    3548  * @param   paArgs      Pointer to (readonly) array of arguments.
    3549  * @param   cArgs       Number of arguments in the array.
    3550  */
    3551 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3552 {
    3553     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3554 
    3555     /*
    3556      * Validate input.
    3557      */
    3558     if (    cArgs != 1
    3559         ||  (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
    3560         ||  (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
    3561         )
    3562         return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
    3563     if (!pVM)
    3564         return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n");
    3565 
    3566     /*
    3567      * Guest or shadow page tables? Get the paging parameters.
    3568      */
    3569     bool fGuest = pCmd->pszCmd[3] != 'h';
    3570     if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')
    3571         fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER
    3572                ? pDbgc->fRegCtxGuest
    3573                : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);
    3574 
    3575     bool fPAE, fLME, fPSE, fPGE, fNXE;
    3576     uint64_t cr3 = fGuest
    3577                  ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)
    3578                  : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);
    3579     const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);
    3580 
    3581     /*
    3582      * Locate the PTE to start displaying at.
    3583      *
    3584      * The 'dpta' command takes the address of a PTE, while the others are guest
    3585      * virtual address which PTEs should be displayed. So, 'pdta' is rather simple
    3586      * while the others require us to do all the tedious walking thru the paging
    3587      * hierarchy to find the intended PTE.
    3588      */
    3589     unsigned    iEntry = ~0U;           /* The page table index. ~0U for 'dpta'. */
    3590     DBGCVAR     VarGCPtr;               /* The GC address corresponding to the current PTE (iEntry != ~0U). */
    3591     DBGCVAR     VarPTEAddr;             /* The address of the current PTE. */
    3592     unsigned    cEntries;               /* The number of entries to display. */
    3593     unsigned    cEntriesMax;            /* The max number of entries to display. */
    3594     int         rc;
    3595     if (pCmd->pszCmd[3] == 'a')
    3596     {
    3597         VarPTEAddr = paArgs[0];
    3598         switch (VarPTEAddr.enmRangeType)
    3599         {
    3600             case DBGCVAR_RANGE_BYTES:       cEntries = VarPTEAddr.u64Range / cbEntry; break;
    3601             case DBGCVAR_RANGE_ELEMENTS:    cEntries = VarPTEAddr.u64Range; break;
    3602             default:                        cEntries = 10; break;
    3603         }
    3604         cEntriesMax = PAGE_SIZE / cbEntry;
    3605     }
    3606     else
    3607     {
    3608         /*
    3609          * Determin the range.
    3610          */
    3611         switch (paArgs[0].enmRangeType)
    3612         {
    3613             case DBGCVAR_RANGE_BYTES:       cEntries = paArgs[0].u64Range / PAGE_SIZE; break;
    3614             case DBGCVAR_RANGE_ELEMENTS:    cEntries = paArgs[0].u64Range; break;
    3615             default:                        cEntries = 10; break;
    3616         }
    3617 
    3618         /*
    3619          * Normalize the input address, it must be a flat GC address.
    3620          */
    3621         rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
    3622         if (VBOX_FAILURE(rc))
    3623             return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
    3624         if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)
    3625         {
    3626             VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;
    3627             VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;
    3628         }
    3629         VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;
    3630 
    3631         /*
    3632          * Do the paging walk until we get to the page table.
    3633          */
    3634         DBGCVAR VarCur;
    3635         if (fGuest)
    3636             DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);
    3637         else
    3638             DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);
    3639         if (fLME)
    3640         {
    3641             /* Page Map Level 4 Lookup. */
    3642             /* Check if it's a valid address first? */
    3643             VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;
    3644             VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);
    3645             X86PML4E Pml4e;
    3646             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);
    3647             if (VBOX_FAILURE(rc))
    3648                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);
    3649             if (!Pml4e.n.u1Present)
    3650                 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);
    3651 
    3652             VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;
    3653             Assert(fPAE);
    3654         }
    3655         if (fPAE)
    3656         {
    3657             /* Page directory pointer table. */
    3658             X86PDPE Pdpe;
    3659             VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);
    3660             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);
    3661             if (VBOX_FAILURE(rc))
    3662                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);
    3663             if (!Pdpe.n.u1Present)
    3664                 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);
    3665 
    3666             VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;
    3667 
    3668             /* Page directory (PAE). */
    3669             X86PDEPAE Pde;
    3670             VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);
    3671             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
    3672             if (VBOX_FAILURE(rc))
    3673                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
    3674             if (!Pde.n.u1Present)
    3675                 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
    3676             if (fPSE && Pde.n.u1Size)
    3677                 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
    3678 
    3679             iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;
    3680             VarPTEAddr = VarCur;
    3681             VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;
    3682             VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);
    3683         }
    3684         else
    3685         {
    3686             /* Page directory (legacy). */
    3687             X86PDE Pde;
    3688             VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);
    3689             rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);
    3690             if (VBOX_FAILURE(rc))
    3691                 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);
    3692             if (!Pde.n.u1Present)
    3693                 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);
    3694             if (fPSE && Pde.n.u1Size)
    3695                 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
    3696 
    3697             iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;
    3698             VarPTEAddr = VarCur;
    3699             VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;
    3700             VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);
    3701         }
    3702         cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;
    3703         iEntry /= cbEntry;
    3704     }
    3705 
    3706     /* adjust cEntries */
    3707     cEntries = RT_MAX(1, cEntries);
    3708     cEntries = RT_MIN(cEntries, cEntriesMax);
    3709 
    3710     /*
    3711      * The display loop.
    3712      */
    3713     DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",
    3714                      &VarPTEAddr, &VarGCPtr, iEntry);
    3715     do
    3716     {
    3717         /*
    3718          * Read.
    3719          */
    3720         X86PTEPAE Pte;
    3721         Pte.u = 0;
    3722         rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL);
    3723         if (VBOX_FAILURE(rc))
    3724             return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);
    3725 
    3726         /*
    3727          * Display.
    3728          */
    3729         if (iEntry != ~0U)
    3730         {
    3731             DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);
    3732             iEntry++;
    3733         }
    3734         DBGCCmdHlpPrintf(pCmdHlp,
    3735                          fPAE
    3736                          ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"
    3737                          :   "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",
    3738                          Pte.u,
    3739                          Pte.u & X86_PTE_PAE_PG_MASK,
    3740                          Pte.n.u1Present         ? "p " : "np",
    3741                          Pte.n.u1Write           ? "w" : "r",
    3742                          Pte.n.u1User            ? "u" : "s",
    3743                          Pte.n.u1Accessed        ? "a " : "na",
    3744                          Pte.n.u1Dirty           ? "d " : "nd",
    3745                          Pte.n.u3Available,
    3746                          Pte.n.u1Global          ? (fPGE ? "g" : "G") : " ",
    3747                          Pte.n.u1WriteThru       ? "pwt" : "   ",
    3748                          Pte.n.u1CacheDisable    ? "pcd" : "   ",
    3749                          Pte.n.u1PAT             ? "pat" : "   ",
    3750                          Pte.n.u1NoExecute       ? (fNXE ? "nx" : "NX") : "  "
    3751                          );
    3752         if (Pte.u & UINT64_C(0x7fff000000000000))
    3753             DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));
    3754         rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");
    3755         if (VBOX_FAILURE(rc))
    3756             return rc;
    3757 
    3758         /*
    3759          * Advance.
    3760          */
    3761         VarPTEAddr.u.u64Number += cbEntry;
    3762         if (iEntry != ~0U)
    3763             VarGCPtr.u.GCFlat += PAGE_SIZE;
    3764     } while (cEntries-- > 0);
    3765 
    3766     NOREF(pResult);
    3767     return VINF_SUCCESS;
    3768 }
    3769 
    3770 
    3771 /**
    3772  * The 'dptb' command.
    3773  *
    3774  * @returns VBox status.
    3775  * @param   pCmd        Pointer to the command descriptor (as registered).
    3776  * @param   pCmdHlp     Pointer to command helper functions.
    3777  * @param   pVM         Pointer to the current VM (if any).
    3778  * @param   paArgs      Pointer to (readonly) array of arguments.
    3779  * @param   cArgs       Number of arguments in the array.
    3780  */
    3781 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3782 {
    3783     if (!pVM)
    3784         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    3785     int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
    3786     int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
    3787     if (VBOX_FAILURE(rc1))
    3788         return rc1;
    3789     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    3790     return rc2;
    3791 }
    3792 
    3793 
    3794 /**
    3795  * The 'dt' command.
    3796  *
    3797  * @returns VBox status.
    3798  * @param   pCmd        Pointer to the command descriptor (as registered).
    3799  * @param   pCmdHlp     Pointer to command helper functions.
    3800  * @param   pVM         Pointer to the current VM (if any).
    3801  * @param   paArgs      Pointer to (readonly) array of arguments.
    3802  * @param   cArgs       Number of arguments in the array.
    3803  */
    3804 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM /*pVM*/, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
    3805 {
    3806     /*
    3807      * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.
    3808      */
    3809 
    3810     /** @todo */
    3811     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dt is not implemented yet, feel free to do it. \n");
    3812 }
    3813 
    3814 
    3815 /**
    3816  * The 'm' command.
    3817  *
    3818  * @returns VBox status.
    3819  * @param   pCmd        Pointer to the command descriptor (as registered).
    3820  * @param   pCmdHlp     Pointer to command helper functions.
    3821  * @param   pVM         Pointer to the current VM (if any).
    3822  * @param   paArgs      Pointer to (readonly) array of arguments.
    3823  * @param   cArgs       Number of arguments in the array.
    3824  */
    3825 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3826 {
    3827     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Address: %DV\n", &paArgs[0]);
    3828     if (!pVM)
    3829         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    3830     int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
    3831     int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
    3832     int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
    3833     int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
    3834     if (VBOX_FAILURE(rc1))
    3835         return rc1;
    3836     if (VBOX_FAILURE(rc2))
    3837         return rc2;
    3838     if (VBOX_FAILURE(rc3))
    3839         return rc3;
    3840     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    3841     return rc4;
    3842 }
    3843 
    3844 
    3845 /**
    3846  * The 'echo' command.
    3847  *
    3848  * @returns VBox status.
    3849  * @param   pCmd        Pointer to the command descriptor (as registered).
    3850  * @param   pCmdHlp     Pointer to command helper functions.
    3851  * @param   pVM         Pointer to the current VM (if any).
    3852  * @param   paArgs      Pointer to (readonly) array of arguments.
    3853  * @param   cArgs       Number of arguments in the array.
    3854  */
    3855 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3856 {
    3857     /*
    3858      * Loop thru the arguments and print them with one space between.
    3859      */
    3860     int rc = 0;
    3861     for (unsigned i = 0; i < cArgs; i++)
    3862     {
    3863         if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
    3864             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
    3865         else
    3866             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
    3867         if (VBOX_FAILURE(rc))
    3868             return rc;
    3869     }
    3870     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    3871     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    3872 }
    3873 
    3874 
    3875 /**
    3876  * The 'runscript' command.
    3877  *
    3878  * @returns VBox status.
    3879  * @param   pCmd        Pointer to the command descriptor (as registered).
    3880  * @param   pCmdHlp     Pointer to command helper functions.
    3881  * @param   pVM         Pointer to the current VM (if any).
    3882  * @param   paArgs      Pointer to (readonly) array of arguments.
    3883  * @param   cArgs       Number of arguments in the array.
    3884  */
    3885 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3886 {
    3887     /* check that the parser did what it's supposed to do. */
    3888     if (    cArgs != 1
    3889         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    3890         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
    3891 
    3892     /*
    3893      * Try open the script.
    3894      */
    3895     const char *pszFilename = paArgs[0].u.pszString;
    3896     FILE *pFile = fopen(pszFilename, "r");
    3897     if (!pFile)
    3898         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
    3899 
    3900     /*
    3901      * Execute it line by line.
    3902      */
    3903     int rc = 0;
    3904     unsigned iLine = 0;
    3905     char szLine[8192];
    3906     while (fgets(szLine, sizeof(szLine), pFile))
    3907     {
    3908         /* check that the line isn't too long. */
    3909         char *pszEnd = strchr(szLine, '\0');
    3910         if (pszEnd == &szLine[sizeof(szLine) - 1])
    3911         {
    3912             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
    3913             break;
    3914         }
    3915         iLine++;
    3916 
    3917         /* strip leading blanks and check for comment / blank line. */
    3918         char *psz = RTStrStripL(szLine);
    3919         if (    *psz == '\0'
    3920             ||  *psz == '\n'
    3921             ||  *psz == '#')
    3922             continue;
    3923 
    3924         /* strip trailing blanks and check for empty line (\r case). */
    3925         while (     pszEnd > psz
    3926                &&   isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */
    3927             *--pszEnd = '\0';
    3928 
    3929         /** @todo check for Control-C / Cancel at this point... */
    3930 
    3931         /*
    3932          * Execute the command.
    3933          *
    3934          * This is a bit wasteful with scratch space btw., can fix it later.
    3935          * The whole return code crap should be fixed too, so that it's possible
    3936          * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and
    3937          * more importantly why it failed.
    3938          */
    3939         rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
    3940         if (VBOX_FAILURE(rc))
    3941         {
    3942             if (rc == VERR_BUFFER_OVERFLOW)
    3943                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
    3944             break;
    3945         }
    3946         if (rc == VWRN_DBGC_CMD_PENDING)
    3947         {
    3948             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
    3949             break;
    3950         }
    3951     }
    3952 
    3953     fclose(pFile);
    3954 
    3955     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    3956     return rc;
    3957 }
    3958 
    3959 
    3960 /**
    3961  * The 's' command.
    3962  *
    3963  * @returns VBox status.
    3964  * @param   pCmd        Pointer to the command descriptor (as registered).
    3965  * @param   pCmdHlp     Pointer to command helper functions.
    3966  * @param   pVM         Pointer to the current VM (if any).
    3967  * @param   paArgs      Pointer to (readonly) array of arguments.
    3968  * @param   cArgs       Number of arguments in the array.
    3969  */
    3970 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    3971 {
    3972     /* check that the parser did what it's supposed to do. */
    3973     if (    cArgs != 1
    3974         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    3975         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
    3976     return -1;
    3977 }
    3978 
    3979 
    3980 
    3981 /**
    3982  * Print formatted string.
    3983  *
    3984  * @param   pHlp        Pointer to this structure.
    3985  * @param   pszFormat   The format string.
    3986  * @param   ...         Arguments.
    3987  */
    3988 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
    3989 {
    3990     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    3991     va_list args;
    3992     va_start(args,  pszFormat);
    3993     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    3994     va_end(args);
    3995 }
    3996 
    3997 
    3998 /**
    3999  * Print formatted string.
    4000  *
    4001  * @param   pHlp        Pointer to this structure.
    4002  * @param   pszFormat   The format string.
    4003  * @param   args        Argument list.
    4004  */
    4005 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
    4006 {
    4007     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    4008     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    4009 }
    4010 
    4011 
    4012 /**
    4013  * The 'info' command.
    4014  *
    4015  * @returns VBox status.
    4016  * @param   pCmd        Pointer to the command descriptor (as registered).
    4017  * @param   pCmdHlp     Pointer to command helper functions.
    4018  * @param   pVM         Pointer to the current VM (if any).
    4019  * @param   paArgs      Pointer to (readonly) array of arguments.
    4020  * @param   cArgs       Number of arguments in the array.
    4021  */
    4022 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4023 {
    4024     /*
    4025      * Validate input.
    4026      */
    4027     if (    cArgs < 1
    4028         ||  cArgs > 2
    4029         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING
    4030         ||  paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
    4031         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
    4032     if (!pVM)
    4033         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    4034 
    4035     /*
    4036      * Dump it.
    4037      */
    4038     struct
    4039     {
    4040         DBGFINFOHLP Hlp;
    4041         PDBGCCMDHLP pCmdHlp;
    4042     } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
    4043     int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
    4044     if (VBOX_FAILURE(rc))
    4045         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
    4046 
    4047     NOREF(pCmd); NOREF(pResult);
    4048     return 0;
    4049 }
    4050 
    4051 
    4052 /**
    4053  * The 'log' command.
    4054  *
    4055  * @returns VBox status.
    4056  * @param   pCmd        Pointer to the command descriptor (as registered).
    4057  * @param   pCmdHlp     Pointer to command helper functions.
    4058  * @param   pVM         Pointer to the current VM (if any).
    4059  * @param   paArgs      Pointer to (readonly) array of arguments.
    4060  * @param   cArgs       Number of arguments in the array.
    4061  */
    4062 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4063 {
    4064     int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
    4065     if (VBOX_SUCCESS(rc))
    4066         return VINF_SUCCESS;
    4067     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    4068     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    4069 }
    4070 
    4071 
    4072 /**
    4073  * The 'logdest' command.
    4074  *
    4075  * @returns VBox status.
    4076  * @param   pCmd        Pointer to the command descriptor (as registered).
    4077  * @param   pCmdHlp     Pointer to command helper functions.
    4078  * @param   pVM         Pointer to the current VM (if any).
    4079  * @param   paArgs      Pointer to (readonly) array of arguments.
    4080  * @param   cArgs       Number of arguments in the array.
    4081  */
    4082 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4083 {
    4084     int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
    4085     if (VBOX_SUCCESS(rc))
    4086         return VINF_SUCCESS;
    4087     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    4088     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    4089 }
    4090 
    4091 
    4092 /**
    4093  * The 'logflags' command.
    4094  *
    4095  * @returns VBox status.
    4096  * @param   pCmd        Pointer to the command descriptor (as registered).
    4097  * @param   pCmdHlp     Pointer to command helper functions.
    4098  * @param   pVM         Pointer to the current VM (if any).
    4099  * @param   paArgs      Pointer to (readonly) array of arguments.
    4100  * @param   cArgs       Number of arguments in the array.
    4101  */
    4102 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4103 {
    4104     int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
    4105     if (VBOX_SUCCESS(rc))
    4106         return VINF_SUCCESS;
    4107     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    4108     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    4109 }
    4110 
    4111 
    4112 /**
    4113  * The 'format' command.
    4114  *
    4115  * @returns VBox status.
    4116  * @param   pCmd        Pointer to the command descriptor (as registered).
    4117  * @param   pCmdHlp     Pointer to command helper functions.
    4118  * @param   pVM         Pointer to the current VM (if any).
    4119  * @param   paArgs      Pointer to (readonly) array of arguments.
    4120  * @param   cArgs       Number of arguments in the array.
    4121  */
    4122 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4123 {
    4124     LogFlow(("dbgcCmdFormat\n"));
    4125     static const char *apszRangeDesc[] =
    4126     {
    4127         "none", "bytes", "elements"
    4128     };
    4129     int rc;
    4130 
    4131     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    4132     {
    4133         switch (paArgs[iArg].enmType)
    4134         {
    4135             case DBGCVAR_TYPE_UNKNOWN:
    4136                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4137                     "Unknown variable type!\n");
    4138                 break;
    4139             case DBGCVAR_TYPE_GC_FLAT:
    4140                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4141                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4142                         "Guest flat address: %%%08x range %lld %s\n",
    4143                         paArgs[iArg].u.GCFlat,
    4144                         paArgs[iArg].u64Range,
    4145                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4146                 else
    4147                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4148                         "Guest flat address: %%%08x\n",
    4149                         paArgs[iArg].u.GCFlat);
    4150                 break;
    4151             case DBGCVAR_TYPE_GC_FAR:
    4152                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4153                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4154                         "Guest far address: %04x:%08x range %lld %s\n",
    4155                         paArgs[iArg].u.GCFar.sel,
    4156                         paArgs[iArg].u.GCFar.off,
    4157                         paArgs[iArg].u64Range,
    4158                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4159                 else
    4160                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4161                         "Guest far address: %04x:%08x\n",
    4162                         paArgs[iArg].u.GCFar.sel,
    4163                         paArgs[iArg].u.GCFar.off);
    4164                 break;
    4165             case DBGCVAR_TYPE_GC_PHYS:
    4166                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4167                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4168                         "Guest physical address: %%%%%08x range %lld %s\n",
    4169                         paArgs[iArg].u.GCPhys,
    4170                         paArgs[iArg].u64Range,
    4171                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4172                 else
    4173                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4174                         "Guest physical address: %%%%%08x\n",
    4175                         paArgs[iArg].u.GCPhys);
    4176                 break;
    4177             case DBGCVAR_TYPE_HC_FLAT:
    4178                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4179                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4180                         "Host flat address: %%%08x range %lld %s\n",
    4181                         paArgs[iArg].u.pvHCFlat,
    4182                         paArgs[iArg].u64Range,
    4183                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4184                 else
    4185                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4186                         "Host flat address: %%%08x\n",
    4187                         paArgs[iArg].u.pvHCFlat);
    4188                 break;
    4189             case DBGCVAR_TYPE_HC_FAR:
    4190                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4191                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4192                         "Host far address: %04x:%08x range %lld %s\n",
    4193                         paArgs[iArg].u.HCFar.sel,
    4194                         paArgs[iArg].u.HCFar.off,
    4195                         paArgs[iArg].u64Range,
    4196                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4197                 else
    4198                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4199                         "Host far address: %04x:%08x\n",
    4200                         paArgs[iArg].u.HCFar.sel,
    4201                         paArgs[iArg].u.HCFar.off);
    4202                 break;
    4203             case DBGCVAR_TYPE_HC_PHYS:
    4204                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4205                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4206                         "Host physical address: %VHp range %lld %s\n",
    4207                         paArgs[iArg].u.HCPhys,
    4208                         paArgs[iArg].u64Range,
    4209                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4210                 else
    4211                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4212                         "Host physical address: %VHp\n",
    4213                         paArgs[iArg].u.HCPhys);
    4214                 break;
    4215 
    4216             case DBGCVAR_TYPE_STRING:
    4217                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4218                     "String, %lld bytes long: %s\n",
    4219                     paArgs[iArg].u64Range,
    4220                     paArgs[iArg].u.pszString);
    4221                 break;
    4222 
    4223             case DBGCVAR_TYPE_NUMBER:
    4224                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    4225                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4226                         "Number: hex %llx  dec 0i%lld  oct 0t%llo  range %lld %s\n",
    4227                         paArgs[iArg].u.u64Number,
    4228                         paArgs[iArg].u.u64Number,
    4229                         paArgs[iArg].u.u64Number,
    4230                         paArgs[iArg].u64Range,
    4231                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    4232                 else
    4233                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4234                         "Number: hex %llx  dec 0i%lld  oct 0t%llo\n",
    4235                         paArgs[iArg].u.u64Number,
    4236                         paArgs[iArg].u.u64Number,
    4237                         paArgs[iArg].u.u64Number);
    4238                 break;
    4239 
    4240             default:
    4241                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4242                     "Invalid argument type %d\n",
    4243                     paArgs[iArg].enmType);
    4244                 break;
    4245         }
    4246     } /* arg loop */
    4247 
    4248     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    4249     return 0;
    4250 }
    4251 
    4252 
    4253 /**
    4254  * List near symbol.
    4255  *
    4256  * @returns VBox status code.
    4257  * @param   pCmdHlp     Pointer to command helper functions.
    4258  * @param   pVM         Pointer to the current VM (if any).
    4259  * @param   pArg        Pointer to the address or symbol to lookup.
    4260  */
    4261 static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)
    4262 {
    4263     dbgcVarSetGCFlat(pResult, 0);
    4264 
    4265     DBGFSYMBOL  Symbol;
    4266     int         rc;
    4267     if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)
    4268     {
    4269         /*
    4270          * Lookup the symbol address.
    4271          */
    4272         rc = DBGFR3SymbolByName(pVM, pArg->u.pszString, &Symbol);
    4273         if (VBOX_FAILURE(rc))
    4274             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByName(, %s,)\n", pArg->u.pszString);
    4275 
    4276         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */
    4277         dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);
    4278     }
    4279     else
    4280     {
    4281         /*
    4282          * Convert it to a flat GC address and lookup that address.
    4283          */
    4284         DBGCVAR AddrVar;
    4285         rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);
    4286         if (VBOX_FAILURE(rc))
    4287             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);
    4288 
    4289         dbgcVarSetVar(pResult, &AddrVar);
    4290 
    4291         RTGCINTPTR offDisp = 0;
    4292         rc = DBGFR3SymbolByAddr(pVM, AddrVar.u.GCFlat, &offDisp, &Symbol);
    4293         if (VBOX_FAILURE(rc))
    4294             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByAddr(, %VGv,,)\n", AddrVar.u.GCFlat);
    4295 
    4296         if (!offDisp)
    4297             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);
    4298         else if (offDisp > 0)
    4299             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);
    4300         else
    4301             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);
    4302         if ((RTGCINTPTR)Symbol.cb > -offDisp)
    4303         {
    4304             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);
    4305             dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);
    4306         }
    4307         else
    4308         {
    4309             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    4310             dbgcVarSetNoRange(pResult);
    4311         }
    4312     }
    4313 
    4314     return rc;
    4315 }
    4316 
    4317 
    4318 /**
    4319  * The 'ln' (listnear) command.
    4320  *
    4321  * @returns VBox status.
    4322  * @param   pCmd        Pointer to the command descriptor (as registered).
    4323  * @param   pCmdHlp     Pointer to command helper functions.
    4324  * @param   pVM         Pointer to the current VM (if any).
    4325  * @param   paArgs      Pointer to (readonly) array of arguments.
    4326  * @param   cArgs       Number of arguments in the array.
    4327  */
    4328 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4329 {
    4330     dbgcVarSetGCFlat(pResult, 0);
    4331     if (!cArgs)
    4332     {
    4333         /*
    4334          * Current cs:eip symbol.
    4335          */
    4336         DBGCVAR AddrVar;
    4337         int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(cs:eip)");
    4338         if (VBOX_FAILURE(rc))
    4339             return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");
    4340         return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);
    4341     }
    4342 
    4343     /*
    4344      * Iterate arguments.
    4345      */
    4346     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    4347     {
    4348         int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);
    4349         if (VBOX_FAILURE(rc))
    4350             return rc;
    4351     }
    4352 
    4353     NOREF(pCmd); NOREF(pResult);
    4354     return VINF_SUCCESS;
    4355 }
    4356 
    4357 
    4358 /**
    4359  * The 'loadsyms' command.
    4360  *
    4361  * @returns VBox status.
    4362  * @param   pCmd        Pointer to the command descriptor (as registered).
    4363  * @param   pCmdHlp     Pointer to command helper functions.
    4364  * @param   pVM         Pointer to the current VM (if any).
    4365  * @param   paArgs      Pointer to (readonly) array of arguments.
    4366  * @param   cArgs       Number of arguments in the array.
    4367  */
    4368 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4369 {
    4370     /*
    4371      * Validate the parsing and make sense of the input.
    4372      * This is a mess as usual because we don't trust the parser yet.
    4373      */
    4374     if (    cArgs < 1
    4375         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    4376     {
    4377         AssertMsgFailed(("Parse error, first argument required to be string!\n"));
    4378         return VERR_PARSE_INCORRECT_ARG_TYPE;
    4379     }
    4380     DBGCVAR     AddrVar;
    4381     RTGCUINTPTR Delta = 0;
    4382     const char *pszModule = NULL;
    4383     RTGCUINTPTR ModuleAddress = 0;
    4384     unsigned    cbModule = 0;
    4385     if (cArgs > 1)
    4386     {
    4387         unsigned iArg = 1;
    4388         if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    4389         {
    4390             Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
    4391             iArg++;
    4392         }
    4393         if (iArg < cArgs)
    4394         {
    4395             if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    4396             {
    4397                 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
    4398                 return VERR_PARSE_INCORRECT_ARG_TYPE;
    4399             }
    4400             pszModule = paArgs[iArg].u.pszString;
    4401             iArg++;
    4402             if (iArg < cArgs)
    4403             {
    4404                 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
    4405                 {
    4406                     AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
    4407                     return VERR_PARSE_INCORRECT_ARG_TYPE;
    4408                 }
    4409                 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
    4410                 if (VBOX_FAILURE(rc))
    4411                     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
    4412                 ModuleAddress = paArgs[iArg].u.GCFlat;
    4413                 iArg++;
    4414                 if (iArg < cArgs)
    4415                 {
    4416                     if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
    4417                     {
    4418                         AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
    4419                         return VERR_PARSE_INCORRECT_ARG_TYPE;
    4420                     }
    4421                     cbModule = (unsigned)paArgs[iArg].u.u64Number;
    4422                     iArg++;
    4423                     if (iArg < cArgs)
    4424                     {
    4425                         AssertMsgFailed(("Parse error, too many arguments!\n"));
    4426                         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    4427                     }
    4428                 }
    4429             }
    4430         }
    4431     }
    4432 
    4433     /*
    4434      * Call the debug info manager about this loading...
    4435      */
    4436     int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
    4437     if (VBOX_FAILURE(rc))
    4438         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",
    4439                                      paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
    4440 
    4441     NOREF(pCmd); NOREF(pResult);
    4442     return VINF_SUCCESS;
    4443 }
    4444 
    4445 
    4446 /**
    4447  * The 'set' command.
    4448  *
    4449  * @returns VBox status.
    4450  * @param   pCmd        Pointer to the command descriptor (as registered).
    4451  * @param   pCmdHlp     Pointer to command helper functions.
    4452  * @param   pVM         Pointer to the current VM (if any).
    4453  * @param   paArgs      Pointer to (readonly) array of arguments.
    4454  * @param   cArgs       Number of arguments in the array.
    4455  */
    4456 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4457 {
    4458     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    4459 
    4460     /* parse sanity check. */
    4461     AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
    4462     if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    4463         return VERR_PARSE_INCORRECT_ARG_TYPE;
    4464 
    4465 
    4466     /*
    4467      * A variable must start with an alpha chars and only contain alpha numerical chars.
    4468      */
    4469     const char *pszVar = paArgs[0].u.pszString;
    4470     if (!isalpha(*pszVar) || *pszVar == '_')
    4471         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4472             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
    4473 
    4474     while (isalnum(*pszVar) || *pszVar == '_')
    4475         *pszVar++;
    4476     if (*pszVar)
    4477         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    4478             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
    4479 
    4480 
    4481     /*
    4482      * Calc variable size.
    4483      */
    4484     size_t  cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
    4485     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    4486         cbVar += 1 + (size_t)paArgs[1].u64Range;
    4487 
    4488     /*
    4489      * Look for existing one.
    4490      */
    4491     pszVar = paArgs[0].u.pszString;
    4492     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    4493     {
    4494         if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    4495         {
    4496             /*
    4497              * Update existing variable.
    4498              */
    4499             void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
    4500             if (!pv)
    4501                 return VERR_PARSE_NO_MEMORY;
    4502             PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
    4503 
    4504             pVar->Var = paArgs[1];
    4505             memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
    4506             if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    4507                 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    4508             return 0;
    4509         }
    4510     }
    4511 
    4512     /*
    4513      * Allocate another.
    4514      */
    4515     PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
    4516 
    4517     pVar->Var = paArgs[1];
    4518     memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
    4519     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    4520         pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    4521 
    4522     /* need to reallocate the pointer array too? */
    4523     if (!(pDbgc->cVars % 0x20))
    4524     {
    4525         void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
    4526         if (!pv)
    4527         {
    4528             RTMemFree(pVar);
    4529             return VERR_PARSE_NO_MEMORY;
    4530         }
    4531         pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
    4532     }
    4533     pDbgc->papVars[pDbgc->cVars++] = pVar;
    4534 
    4535     NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
    4536     return 0;
    4537 }
    4538 
    4539 
    4540 /**
    4541  * The 'unset' command.
    4542  *
    4543  * @returns VBox status.
    4544  * @param   pCmd        Pointer to the command descriptor (as registered).
    4545  * @param   pCmdHlp     Pointer to command helper functions.
    4546  * @param   pVM         Pointer to the current VM (if any).
    4547  * @param   paArgs      Pointer to (readonly) array of arguments.
    4548  * @param   cArgs       Number of arguments in the array.
    4549  */
    4550 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4551 {
    4552     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    4553 
    4554     /*
    4555      * Don't trust the parser.
    4556      */
    4557     for (unsigned  i = 0; i < cArgs; i++)
    4558         if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
    4559         {
    4560             AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
    4561             return VERR_PARSE_INCORRECT_ARG_TYPE;
    4562         }
    4563 
    4564     /*
    4565      * Iterate the variables and unset them.
    4566      */
    4567     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    4568     {
    4569         const char *pszVar = paArgs[iArg].u.pszString;
    4570 
    4571         /*
    4572          * Look up the variable.
    4573          */
    4574         for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    4575         {
    4576             if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    4577             {
    4578                 /*
    4579                  * Shuffle the array removing this entry.
    4580                  */
    4581                 void *pvFree = pDbgc->papVars[iVar];
    4582                 if (iVar + 1 < pDbgc->cVars)
    4583                     memmove(&pDbgc->papVars[iVar],
    4584                             &pDbgc->papVars[iVar + 1],
    4585                             (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
    4586                 pDbgc->papVars[--pDbgc->cVars] = NULL;
    4587 
    4588                 RTMemFree(pvFree);
    4589             }
    4590         } /* lookup */
    4591     } /* arg loop */
    4592 
    4593     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    4594     return 0;
    4595 }
    4596 
    4597 
    4598 /**
    4599  * The 'loadvars' command.
    4600  *
    4601  * @returns VBox status.
    4602  * @param   pCmd        Pointer to the command descriptor (as registered).
    4603  * @param   pCmdHlp     Pointer to command helper functions.
    4604  * @param   pVM         Pointer to the current VM (if any).
    4605  * @param   paArgs      Pointer to (readonly) array of arguments.
    4606  * @param   cArgs       Number of arguments in the array.
    4607  */
    4608 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4609 {
    4610     /*
    4611      * Don't trust the parser.
    4612      */
    4613     if (    cArgs != 1
    4614         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    4615     {
    4616         AssertMsgFailed(("Expected one string exactly!\n"));
    4617         return VERR_PARSE_INCORRECT_ARG_TYPE;
    4618     }
    4619 
    4620     /*
    4621      * Iterate the variables and unset them.
    4622      */
    4623     FILE *pFile = fopen(paArgs[0].u.pszString, "r");
    4624     if (pFile)
    4625     {
    4626         char szLine[4096];
    4627         while (fgets(szLine, sizeof(szLine), pFile))
    4628         {
    4629             /* Strip it. */
    4630             char *psz = szLine;
    4631             while (isblank(*psz))
    4632                 psz++;
    4633             int i = (int)strlen(psz) - 1;
    4634             while (i >= 0 && isspace(psz[i]))
    4635                 psz[i--] ='\0';
    4636             /* Execute it if not comment or empty line. */
    4637             if (    *psz != '\0'
    4638                 &&  *psz != '#'
    4639                 &&  *psz != ';')
    4640             {
    4641                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
    4642                 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
    4643             }
    4644         }
    4645         fclose(pFile);
    4646     }
    4647     else
    4648         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
    4649 
    4650     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    4651     return 0;
    4652 }
    4653 
    4654 
    4655 /**
    4656  * The 'showvars' command.
    4657  *
    4658  * @returns VBox status.
    4659  * @param   pCmd        Pointer to the command descriptor (as registered).
    4660  * @param   pCmdHlp     Pointer to command helper functions.
    4661  * @param   pVM         Pointer to the current VM (if any).
    4662  * @param   paArgs      Pointer to (readonly) array of arguments.
    4663  * @param   cArgs       Number of arguments in the array.
    4664  */
    4665 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4666 {
    4667     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    4668 
    4669     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    4670     {
    4671         int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
    4672         if (!rc)
    4673             rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
    4674         if (rc)
    4675             return rc;
    4676     }
    4677 
    4678     NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    4679     return 0;
    4680 }
    4681 
    4682 
    4683 /**
    4684  * The 'harakiri' command.
    4685  *
    4686  * @returns VBox status.
    4687  * @param   pCmd        Pointer to the command descriptor (as registered).
    4688  * @param   pCmdHlp     Pointer to command helper functions.
    4689  * @param   pVM         Pointer to the current VM (if any).
    4690  * @param   paArgs      Pointer to (readonly) array of arguments.
    4691  * @param   cArgs       Number of arguments in the array.
    4692  */
    4693 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    4694 {
    4695     Log(("dbgcCmdHarakiri\n"));
    4696     for (;;)
    4697         exit(126);
    4698     NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    4699 }
    4700 
    4701 
    4702 
    4703 
    4704 
    4705 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4706 //
    4707 //
    4708 //      B u l t i n   S y m b o l s
    4709 //
    4710 //
    4711 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4712 
    4713 
    4714 
    4715 /**
    4716  * Get builtin register symbol.
    4717  *
    4718  * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
    4719  *
    4720  * @returns 0 on success.
    4721  * @returns VBox evaluation / parsing error code on failure.
    4722  *          The caller does the bitching.
    4723  * @param   pSymDesc    Pointer to the symbol descriptor.
    4724  * @param   pCmdHlp     Pointer to the command callback structure.
    4725  * @param   enmType     The result type.
    4726  * @param   pResult     Where to store the result.
    4727  */
    4728 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
    4729 {
    4730     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    4731 
    4732     /*
    4733      * pVM is required.
    4734      */
    4735     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    4736     Assert(pDbgc->pVM);
    4737 
    4738     /*
    4739      * Get the right CPU context.
    4740      */
    4741     PCPUMCTX    pCtx;
    4742     int         rc;
    4743     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    4744         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    4745     else
    4746         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    4747     if (VBOX_FAILURE(rc))
    4748         return rc;
    4749 
    4750     /*
    4751      * Get the value.
    4752      */
    4753     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    4754     uint64_t    u64;
    4755     switch (SYMREG_SIZE(pSymDesc->uUser))
    4756     {
    4757         case 1: u64 = *(uint8_t *)pvValue; break;
    4758         case 2: u64 = *(uint16_t *)pvValue; break;
    4759         case 4: u64 = *(uint32_t *)pvValue; break;
    4760         case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
    4761         case 8: u64 = *(uint64_t *)pvValue; break;
    4762         default:
    4763             return VERR_PARSE_NOT_IMPLEMENTED;
    4764     }
    4765 
    4766     /*
    4767      * Construct the desired result.
    4768      */
    4769     if (enmType == DBGCVAR_TYPE_ANY)
    4770         enmType = DBGCVAR_TYPE_NUMBER;
    4771     pResult->pDesc          = NULL;
    4772     pResult->pNext          = NULL;
    4773     pResult->enmType        = enmType;
    4774     pResult->enmRangeType   = DBGCVAR_RANGE_NONE;
    4775     pResult->u64Range       = 0;
    4776 
    4777     switch (enmType)
    4778     {
    4779         case DBGCVAR_TYPE_GC_FLAT:
    4780             pResult->u.GCFlat = (RTGCPTR)u64;
    4781             break;
    4782 
    4783         case DBGCVAR_TYPE_GC_FAR:
    4784             switch (SYMREG_SIZE(pSymDesc->uUser))
    4785             {
    4786                 case 4:
    4787                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    4788                     {
    4789                         pResult->u.GCFar.off = (uint16_t)u64;
    4790                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);
    4791                     }
    4792                     else
    4793                     {
    4794                         pResult->u.GCFar.sel = (uint16_t)u64;
    4795                         pResult->u.GCFar.off = (uint16_t)(u64 >> 16);
    4796                     }
    4797                     break;
    4798                 case 6:
    4799                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    4800                     {
    4801                         pResult->u.GCFar.off = (uint32_t)u64;
    4802                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);
    4803                     }
    4804                     else
    4805                     {
    4806                         pResult->u.GCFar.sel = (uint32_t)u64;
    4807                         pResult->u.GCFar.off = (uint16_t)(u64 >> 32);
    4808                     }
    4809                     break;
    4810 
    4811                 default:
    4812                     return VERR_PARSE_BAD_RESULT_TYPE;
    4813             }
    4814             break;
    4815 
    4816         case DBGCVAR_TYPE_GC_PHYS:
    4817             pResult->u.GCPhys = (RTGCPHYS)u64;
    4818             break;
    4819 
    4820         case DBGCVAR_TYPE_HC_FLAT:
    4821             pResult->u.pvHCFlat = (void *)(uintptr_t)u64;
    4822             break;
    4823 
    4824         case DBGCVAR_TYPE_HC_FAR:
    4825             switch (SYMREG_SIZE(pSymDesc->uUser))
    4826             {
    4827                 case 4:
    4828                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    4829                     {
    4830                         pResult->u.HCFar.off = (uint16_t)u64;
    4831                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);
    4832                     }
    4833                     else
    4834                     {
    4835                         pResult->u.HCFar.sel = (uint16_t)u64;
    4836                         pResult->u.HCFar.off = (uint16_t)(u64 >> 16);
    4837                     }
    4838                     break;
    4839                 case 6:
    4840                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    4841                     {
    4842                         pResult->u.HCFar.off = (uint32_t)u64;
    4843                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);
    4844                     }
    4845                     else
    4846                     {
    4847                         pResult->u.HCFar.sel = (uint32_t)u64;
    4848                         pResult->u.HCFar.off = (uint16_t)(u64 >> 32);
    4849                     }
    4850                     break;
    4851 
    4852                 default:
    4853                     return VERR_PARSE_BAD_RESULT_TYPE;
    4854             }
    4855             break;
    4856 
    4857         case DBGCVAR_TYPE_HC_PHYS:
    4858             pResult->u.GCPhys = (RTGCPHYS)u64;
    4859             break;
    4860 
    4861         case DBGCVAR_TYPE_NUMBER:
    4862             pResult->u.u64Number = u64;
    4863             break;
    4864 
    4865         case DBGCVAR_TYPE_STRING:
    4866         case DBGCVAR_TYPE_UNKNOWN:
    4867         default:
    4868             return VERR_PARSE_BAD_RESULT_TYPE;
    4869 
    4870     }
    4871 
    4872     return 0;
    4873 }
    4874 
    4875 
    4876 /**
    4877  * Set builtin register symbol.
    4878  *
    4879  * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
    4880  *
    4881  * @returns 0 on success.
    4882  * @returns VBox evaluation / parsing error code on failure.
    4883  *          The caller does the bitching.
    4884  * @param   pSymDesc    Pointer to the symbol descriptor.
    4885  * @param   pCmdHlp     Pointer to the command callback structure.
    4886  * @param   pValue      The value to assign the symbol.
    4887  */
    4888 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)
    4889 {
    4890     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    4891 
    4892     /*
    4893      * pVM is required.
    4894      */
    4895     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    4896     Assert(pDbgc->pVM);
    4897 
    4898     /*
    4899      * Get the right CPU context.
    4900      */
    4901     PCPUMCTX    pCtx;
    4902     int         rc;
    4903     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    4904         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    4905     else
    4906         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    4907     if (VBOX_FAILURE(rc))
    4908         return rc;
    4909 
    4910     /*
    4911      * Check the new value.
    4912      */
    4913     if (pValue->enmType != DBGCVAR_TYPE_NUMBER)
    4914         return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    4915 
    4916     /*
    4917      * Set the value.
    4918      */
    4919     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    4920     switch (SYMREG_SIZE(pSymDesc->uUser))
    4921     {
    4922         case 1:
    4923             *(uint8_t *)pvValue  = (uint8_t)pValue->u.u64Number;
    4924             break;
    4925         case 2:
    4926             *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;
    4927             break;
    4928         case 4:
    4929             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    4930             break;
    4931         case 6:
    4932             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    4933             ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);
    4934             break;
    4935         case 8:
    4936             *(uint64_t *)pvValue = pValue->u.u64Number;
    4937             break;
    4938         default:
    4939             return VERR_PARSE_NOT_IMPLEMENTED;
    4940     }
    4941 
    4942     return VINF_SUCCESS;
    4943 }
    4944 
    4945 
    4946 
    4947 
    4948 
    4949 
    4950 
    4951 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4952 //
    4953 //
    4954 //      O p e r a t o r s
    4955 //
    4956 //
    4957 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4958 
    4959 
    4960 /**
    4961  * Minus (unary).
    4962  *
    4963  * @returns 0 on success.
    4964  * @returns VBox evaluation / parsing error code on failure.
    4965  *          The caller does the bitching.
    4966  * @param   pDbgc       Debugger console instance data.
    4967  * @param   pArg        The argument.
    4968  * @param   pResult     Where to store the result.
    4969  */
    4970 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    4971 {
    4972 //    LogFlow(("dbgcOpMinus\n"));
    4973     *pResult = *pArg;
    4974     switch (pArg->enmType)
    4975     {
    4976         case DBGCVAR_TYPE_GC_FLAT:
    4977             pResult->u.GCFlat       = -(RTGCINTPTR)pResult->u.GCFlat;
    4978             break;
    4979         case DBGCVAR_TYPE_GC_FAR:
    4980             pResult->u.GCFar.off    = -(int32_t)pResult->u.GCFar.off;
    4981             break;
    4982         case DBGCVAR_TYPE_GC_PHYS:
    4983             pResult->u.GCPhys       = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;
    4984             break;
    4985         case DBGCVAR_TYPE_HC_FLAT:
    4986             pResult->u.pvHCFlat     = (void *) -(intptr_t)pResult->u.pvHCFlat;
    4987             break;
    4988         case DBGCVAR_TYPE_HC_FAR:
    4989             pResult->u.HCFar.off    = -(int32_t)pResult->u.HCFar.off;
    4990             break;
    4991         case DBGCVAR_TYPE_HC_PHYS:
    4992             pResult->u.HCPhys       = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;
    4993             break;
    4994         case DBGCVAR_TYPE_NUMBER:
    4995             pResult->u.u64Number    = -(int64_t)pResult->u.u64Number;
    4996             break;
    4997 
    4998         case DBGCVAR_TYPE_UNKNOWN:
    4999         case DBGCVAR_TYPE_STRING:
    5000         default:
    5001             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5002     }
    5003     NOREF(pDbgc);
    5004     return 0;
    5005 }
    5006 
    5007 
    5008 /**
    5009  * Pluss (unary).
    5010  *
    5011  * @returns 0 on success.
    5012  * @returns VBox evaluation / parsing error code on failure.
    5013  *          The caller does the bitching.
    5014  * @param   pDbgc       Debugger console instance data.
    5015  * @param   pArg        The argument.
    5016  * @param   pResult     Where to store the result.
    5017  */
    5018 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5019 {
    5020 //    LogFlow(("dbgcOpPluss\n"));
    5021     *pResult = *pArg;
    5022     switch (pArg->enmType)
    5023     {
    5024         case DBGCVAR_TYPE_GC_FLAT:
    5025         case DBGCVAR_TYPE_GC_FAR:
    5026         case DBGCVAR_TYPE_GC_PHYS:
    5027         case DBGCVAR_TYPE_HC_FLAT:
    5028         case DBGCVAR_TYPE_HC_FAR:
    5029         case DBGCVAR_TYPE_HC_PHYS:
    5030         case DBGCVAR_TYPE_NUMBER:
    5031             break;
    5032 
    5033         case DBGCVAR_TYPE_UNKNOWN:
    5034         case DBGCVAR_TYPE_STRING:
    5035         default:
    5036             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5037     }
    5038     NOREF(pDbgc);
    5039     return 0;
    5040 }
    5041 
    5042 
    5043 /**
    5044  * Boolean not (unary).
    5045  *
    5046  * @returns 0 on success.
    5047  * @returns VBox evaluation / parsing error code on failure.
    5048  *          The caller does the bitching.
    5049  * @param   pDbgc       Debugger console instance data.
    5050  * @param   pArg        The argument.
    5051  * @param   pResult     Where to store the result.
    5052  */
    5053 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5054 {
    5055 //    LogFlow(("dbgcOpBooleanNot\n"));
    5056     *pResult = *pArg;
    5057     switch (pArg->enmType)
    5058     {
    5059         case DBGCVAR_TYPE_GC_FLAT:
    5060             pResult->u.u64Number    = !pResult->u.GCFlat;
    5061             break;
    5062         case DBGCVAR_TYPE_GC_FAR:
    5063             pResult->u.u64Number    = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;
    5064             break;
    5065         case DBGCVAR_TYPE_GC_PHYS:
    5066             pResult->u.u64Number    = !pResult->u.GCPhys;
    5067             break;
    5068         case DBGCVAR_TYPE_HC_FLAT:
    5069             pResult->u.u64Number    = !pResult->u.pvHCFlat;
    5070             break;
    5071         case DBGCVAR_TYPE_HC_FAR:
    5072             pResult->u.u64Number    = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;
    5073             break;
    5074         case DBGCVAR_TYPE_HC_PHYS:
    5075             pResult->u.u64Number    = !pResult->u.HCPhys;
    5076             break;
    5077         case DBGCVAR_TYPE_NUMBER:
    5078             pResult->u.u64Number    = !pResult->u.u64Number;
    5079             break;
    5080         case DBGCVAR_TYPE_STRING:
    5081             pResult->u.u64Number    = !pResult->u64Range;
    5082             break;
    5083 
    5084         case DBGCVAR_TYPE_UNKNOWN:
    5085         default:
    5086             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5087     }
    5088     pResult->enmType = DBGCVAR_TYPE_NUMBER;
    5089     NOREF(pDbgc);
    5090     return 0;
    5091 }
    5092 
    5093 
    5094 /**
    5095  * Bitwise not (unary).
    5096  *
    5097  * @returns 0 on success.
    5098  * @returns VBox evaluation / parsing error code on failure.
    5099  *          The caller does the bitching.
    5100  * @param   pDbgc       Debugger console instance data.
    5101  * @param   pArg        The argument.
    5102  * @param   pResult     Where to store the result.
    5103  */
    5104 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5105 {
    5106 //    LogFlow(("dbgcOpBitwiseNot\n"));
    5107     *pResult = *pArg;
    5108     switch (pArg->enmType)
    5109     {
    5110         case DBGCVAR_TYPE_GC_FLAT:
    5111             pResult->u.GCFlat       = ~pResult->u.GCFlat;
    5112             break;
    5113         case DBGCVAR_TYPE_GC_FAR:
    5114             pResult->u.GCFar.off    = ~pResult->u.GCFar.off;
    5115             break;
    5116         case DBGCVAR_TYPE_GC_PHYS:
    5117             pResult->u.GCPhys       = ~pResult->u.GCPhys;
    5118             break;
    5119         case DBGCVAR_TYPE_HC_FLAT:
    5120             pResult->u.pvHCFlat     = (void *)~(uintptr_t)pResult->u.pvHCFlat;
    5121             break;
    5122         case DBGCVAR_TYPE_HC_FAR:
    5123             pResult->u.HCFar.off= ~pResult->u.HCFar.off;
    5124             break;
    5125         case DBGCVAR_TYPE_HC_PHYS:
    5126             pResult->u.HCPhys       = ~pResult->u.HCPhys;
    5127             break;
    5128         case DBGCVAR_TYPE_NUMBER:
    5129             pResult->u.u64Number    = ~pResult->u.u64Number;
    5130             break;
    5131 
    5132         case DBGCVAR_TYPE_UNKNOWN:
    5133         case DBGCVAR_TYPE_STRING:
    5134         default:
    5135             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5136     }
    5137     NOREF(pDbgc);
    5138     return 0;
    5139 }
    5140 
    5141 
    5142 /**
    5143  * Reference variable (unary).
    5144  *
    5145  * @returns 0 on success.
    5146  * @returns VBox evaluation / parsing error code on failure.
    5147  *          The caller does the bitching.
    5148  * @param   pDbgc       Debugger console instance data.
    5149  * @param   pArg        The argument.
    5150  * @param   pResult     Where to store the result.
    5151  */
    5152 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5153 {
    5154 //    LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));
    5155     /*
    5156      * Parse sanity.
    5157      */
    5158     if (pArg->enmType != DBGCVAR_TYPE_STRING)
    5159         return VERR_PARSE_INCORRECT_ARG_TYPE;
    5160 
    5161     /*
    5162      * Lookup the variable.
    5163      */
    5164     const char *pszVar = pArg->u.pszString;
    5165     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    5166     {
    5167         if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    5168         {
    5169             *pResult = pDbgc->papVars[iVar]->Var;
    5170             return 0;
    5171         }
    5172     }
    5173 
    5174     return VERR_PARSE_VARIABLE_NOT_FOUND;
    5175 }
    5176 
    5177 
    5178 /**
    5179  * Flat address (unary).
    5180  *
    5181  * @returns VINF_SUCCESS on success.
    5182  * @returns VBox evaluation / parsing error code on failure.
    5183  *          The caller does the bitching.
    5184  * @param   pDbgc       Debugger console instance data.
    5185  * @param   pArg        The argument.
    5186  * @param   pResult     Where to store the result.
    5187  */
    5188 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5189 {
    5190 //    LogFlow(("dbgcOpAddrFlat\n"));
    5191     int     rc;
    5192     *pResult = *pArg;
    5193 
    5194     switch (pArg->enmType)
    5195     {
    5196         case DBGCVAR_TYPE_GC_FLAT:
    5197             return VINF_SUCCESS;
    5198 
    5199         case DBGCVAR_TYPE_GC_FAR:
    5200         {
    5201             Assert(pDbgc->pVM);
    5202             DBGFADDRESS Address;
    5203             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    5204             if (VBOX_SUCCESS(rc))
    5205             {
    5206                 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
    5207                 pResult->u.GCFlat = Address.FlatPtr;
    5208                 return VINF_SUCCESS;
    5209             }
    5210             return VERR_PARSE_CONVERSION_FAILED;
    5211         }
    5212 
    5213         case DBGCVAR_TYPE_GC_PHYS:
    5214             //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
    5215             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5216 
    5217         case DBGCVAR_TYPE_HC_FLAT:
    5218             return VINF_SUCCESS;
    5219 
    5220         case DBGCVAR_TYPE_HC_FAR:
    5221             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5222 
    5223         case DBGCVAR_TYPE_HC_PHYS:
    5224             Assert(pDbgc->pVM);
    5225             pResult->enmType        = DBGCVAR_TYPE_HC_FLAT;
    5226             rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);
    5227             if (VBOX_SUCCESS(rc))
    5228                 return VINF_SUCCESS;
    5229             return VERR_PARSE_CONVERSION_FAILED;
    5230 
    5231         case DBGCVAR_TYPE_NUMBER:
    5232             pResult->enmType    = DBGCVAR_TYPE_GC_FLAT;
    5233             pResult->u.GCFlat   = (RTGCPTR)pResult->u.u64Number;
    5234             return VINF_SUCCESS;
    5235 
    5236         case DBGCVAR_TYPE_STRING:
    5237             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);
    5238 
    5239         case DBGCVAR_TYPE_UNKNOWN:
    5240         default:
    5241             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5242     }
    5243 }
    5244 
    5245 
    5246 /**
    5247  * Physical address (unary).
    5248  *
    5249  * @returns 0 on success.
    5250  * @returns VBox evaluation / parsing error code on failure.
    5251  *          The caller does the bitching.
    5252  * @param   pDbgc       Debugger console instance data.
    5253  * @param   pArg        The argument.
    5254  * @param   pResult     Where to store the result.
    5255  */
    5256 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5257 {
    5258 //    LogFlow(("dbgcOpAddrPhys\n"));
    5259     int     rc;
    5260 
    5261     *pResult = *pArg;
    5262     switch (pArg->enmType)
    5263     {
    5264         case DBGCVAR_TYPE_GC_FLAT:
    5265             Assert(pDbgc->pVM);
    5266             pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    5267             rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);
    5268             if (VBOX_SUCCESS(rc))
    5269                 return 0;
    5270             /** @todo more memory types! */
    5271             return VERR_PARSE_CONVERSION_FAILED;
    5272 
    5273         case DBGCVAR_TYPE_GC_FAR:
    5274         {
    5275             Assert(pDbgc->pVM);
    5276             DBGFADDRESS Address;
    5277             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    5278             if (VBOX_SUCCESS(rc))
    5279             {
    5280                 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    5281                 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);
    5282                 if (VBOX_SUCCESS(rc))
    5283                     return 0;
    5284                 /** @todo more memory types! */
    5285             }
    5286             return VERR_PARSE_CONVERSION_FAILED;
    5287         }
    5288 
    5289         case DBGCVAR_TYPE_GC_PHYS:
    5290             return 0;
    5291 
    5292         case DBGCVAR_TYPE_HC_FLAT:
    5293             Assert(pDbgc->pVM);
    5294             pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    5295             rc = PGMR3DbgHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);
    5296             if (VBOX_SUCCESS(rc))
    5297                 return 0;
    5298             /** @todo more memory types! */
    5299             return VERR_PARSE_CONVERSION_FAILED;
    5300 
    5301         case DBGCVAR_TYPE_HC_FAR:
    5302             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5303 
    5304         case DBGCVAR_TYPE_HC_PHYS:
    5305             return 0;
    5306 
    5307         case DBGCVAR_TYPE_NUMBER:
    5308             pResult->enmType    = DBGCVAR_TYPE_GC_PHYS;
    5309             pResult->u.GCPhys   = (RTGCPHYS)pResult->u.u64Number;
    5310             return 0;
    5311 
    5312         case DBGCVAR_TYPE_STRING:
    5313             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);
    5314 
    5315         case DBGCVAR_TYPE_UNKNOWN:
    5316         default:
    5317             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5318     }
    5319     return 0;
    5320 }
    5321 
    5322 
    5323 /**
    5324  * Physical host address (unary).
    5325  *
    5326  * @returns 0 on success.
    5327  * @returns VBox evaluation / parsing error code on failure.
    5328  *          The caller does the bitching.
    5329  * @param   pDbgc       Debugger console instance data.
    5330  * @param   pArg        The argument.
    5331  * @param   pResult     Where to store the result.
    5332  */
    5333 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5334 {
    5335 //    LogFlow(("dbgcOpAddrPhys\n"));
    5336     int     rc;
    5337 
    5338     *pResult = *pArg;
    5339     switch (pArg->enmType)
    5340     {
    5341         case DBGCVAR_TYPE_GC_FLAT:
    5342             Assert(pDbgc->pVM);
    5343             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    5344             rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
    5345             if (VBOX_SUCCESS(rc))
    5346                 return 0;
    5347             /** @todo more memory types. */
    5348             return VERR_PARSE_CONVERSION_FAILED;
    5349 
    5350         case DBGCVAR_TYPE_GC_FAR:
    5351         {
    5352             Assert(pDbgc->pVM);
    5353             DBGFADDRESS Address;
    5354             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    5355             if (VBOX_SUCCESS(rc))
    5356             {
    5357                 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    5358                 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);
    5359                 if (VBOX_SUCCESS(rc))
    5360                     return 0;
    5361                 /** @todo more memory types. */
    5362             }
    5363             return VERR_PARSE_CONVERSION_FAILED;
    5364         }
    5365 
    5366         case DBGCVAR_TYPE_GC_PHYS:
    5367             Assert(pDbgc->pVM);
    5368             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    5369             rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
    5370             if (VBOX_SUCCESS(rc))
    5371                 return 0;
    5372             return VERR_PARSE_CONVERSION_FAILED;
    5373 
    5374         case DBGCVAR_TYPE_HC_FLAT:
    5375             Assert(pDbgc->pVM);
    5376             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    5377             rc = PGMR3DbgHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);
    5378             if (VBOX_SUCCESS(rc))
    5379                 return 0;
    5380             /** @todo more memory types! */
    5381             return VERR_PARSE_CONVERSION_FAILED;
    5382 
    5383         case DBGCVAR_TYPE_HC_FAR:
    5384             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5385 
    5386         case DBGCVAR_TYPE_HC_PHYS:
    5387             return 0;
    5388 
    5389         case DBGCVAR_TYPE_NUMBER:
    5390             pResult->enmType    = DBGCVAR_TYPE_HC_PHYS;
    5391             pResult->u.HCPhys   = (RTGCPHYS)pResult->u.u64Number;
    5392             return 0;
    5393 
    5394         case DBGCVAR_TYPE_STRING:
    5395             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);
    5396 
    5397         case DBGCVAR_TYPE_UNKNOWN:
    5398         default:
    5399             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5400     }
    5401     return 0;
    5402 }
    5403 
    5404 
    5405 /**
    5406  * Host address (unary).
    5407  *
    5408  * @returns 0 on success.
    5409  * @returns VBox evaluation / parsing error code on failure.
    5410  *          The caller does the bitching.
    5411  * @param   pDbgc       Debugger console instance data.
    5412  * @param   pArg        The argument.
    5413  * @param   pResult     Where to store the result.
    5414  */
    5415 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    5416 {
    5417 //    LogFlow(("dbgcOpAddrHost\n"));
    5418     int     rc;
    5419 
    5420     *pResult = *pArg;
    5421     switch (pArg->enmType)
    5422     {
    5423         case DBGCVAR_TYPE_GC_FLAT:
    5424             Assert(pDbgc->pVM);
    5425             pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    5426             rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);
    5427             if (VBOX_SUCCESS(rc))
    5428                 return 0;
    5429             /** @todo more memory types. */
    5430             return VERR_PARSE_CONVERSION_FAILED;
    5431 
    5432         case DBGCVAR_TYPE_GC_FAR:
    5433         {
    5434             Assert(pDbgc->pVM);
    5435             DBGFADDRESS Address;
    5436             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    5437             if (VBOX_SUCCESS(rc))
    5438             {
    5439                 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    5440                 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);
    5441                 if (VBOX_SUCCESS(rc))
    5442                     return 0;
    5443                 /** @todo more memory types. */
    5444             }
    5445             return VERR_PARSE_CONVERSION_FAILED;
    5446         }
    5447 
    5448         case DBGCVAR_TYPE_GC_PHYS:
    5449             Assert(pDbgc->pVM);
    5450             pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    5451             rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);
    5452             if (VBOX_SUCCESS(rc))
    5453                 return 0;
    5454             return VERR_PARSE_CONVERSION_FAILED;
    5455 
    5456         case DBGCVAR_TYPE_HC_FLAT:
    5457             return 0;
    5458 
    5459         case DBGCVAR_TYPE_HC_FAR:
    5460         case DBGCVAR_TYPE_HC_PHYS:
    5461             /** @todo !*/
    5462             return VERR_PARSE_CONVERSION_FAILED;
    5463 
    5464         case DBGCVAR_TYPE_NUMBER:
    5465             pResult->enmType    = DBGCVAR_TYPE_HC_FLAT;
    5466             pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;
    5467             return 0;
    5468 
    5469         case DBGCVAR_TYPE_STRING:
    5470             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);
    5471 
    5472         case DBGCVAR_TYPE_UNKNOWN:
    5473         default:
    5474             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5475     }
    5476 }
    5477 
    5478 /**
    5479  * Bitwise not (unary).
    5480  *
    5481  * @returns 0 on success.
    5482  * @returns VBox evaluation / parsing error code on failure.
    5483  *          The caller does the bitching.
    5484  * @param   pDbgc       Debugger console instance data.
    5485  * @param   pArg        The argument.
    5486  * @param   pResult     Where to store the result.
    5487  */
    5488 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5489 {
    5490 //    LogFlow(("dbgcOpAddrFar\n"));
    5491     int     rc;
    5492 
    5493     switch (pArg1->enmType)
    5494     {
    5495         case DBGCVAR_TYPE_STRING:
    5496             rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
    5497             if (VBOX_FAILURE(rc))
    5498                 return rc;
    5499             break;
    5500         case DBGCVAR_TYPE_NUMBER:
    5501             *pResult = *pArg1;
    5502             break;
    5503 
    5504         case DBGCVAR_TYPE_GC_FLAT:
    5505         case DBGCVAR_TYPE_GC_FAR:
    5506         case DBGCVAR_TYPE_GC_PHYS:
    5507         case DBGCVAR_TYPE_HC_FLAT:
    5508         case DBGCVAR_TYPE_HC_FAR:
    5509         case DBGCVAR_TYPE_HC_PHYS:
    5510         case DBGCVAR_TYPE_UNKNOWN:
    5511         default:
    5512             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5513     }
    5514     pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;
    5515 
    5516     /* common code for the two types we support. */
    5517     switch (pArg2->enmType)
    5518     {
    5519         case DBGCVAR_TYPE_GC_FLAT:
    5520             pResult->u.GCFar.off = pArg2->u.GCFlat;
    5521             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    5522             break;
    5523 
    5524         case DBGCVAR_TYPE_HC_FLAT:
    5525             pResult->u.HCFar.off = pArg2->u.GCFlat;
    5526             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    5527             break;
    5528 
    5529         case DBGCVAR_TYPE_NUMBER:
    5530             pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;
    5531             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    5532             break;
    5533 
    5534         case DBGCVAR_TYPE_STRING:
    5535         {
    5536             DBGCVAR Var;
    5537             rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    5538             if (VBOX_FAILURE(rc))
    5539                 return rc;
    5540             pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;
    5541             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    5542             break;
    5543         }
    5544 
    5545         case DBGCVAR_TYPE_GC_FAR:
    5546         case DBGCVAR_TYPE_GC_PHYS:
    5547         case DBGCVAR_TYPE_HC_FAR:
    5548         case DBGCVAR_TYPE_HC_PHYS:
    5549         case DBGCVAR_TYPE_UNKNOWN:
    5550         default:
    5551             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5552     }
    5553     return 0;
    5554 
    5555 }
    5556 
    5557 
    5558 /**
    5559  * Multiplication operator (binary).
    5560  *
    5561  * @returns 0 on success.
    5562  * @returns VBox evaluation / parsing error code on failure.
    5563  *          The caller does the bitching.
    5564  * @param   pDbgc       Debugger console instance data.
    5565  * @param   pArg1       The first argument.
    5566  * @param   pArg2       The 2nd argument.
    5567  * @param   pResult     Where to store the result.
    5568  */
    5569 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5570 {
    5571 //    LogFlow(("dbgcOpMult\n"));
    5572     int     rc;
    5573 
    5574     /*
    5575      * Switch the factors so we preserve pointers, far pointers are considered more
    5576      * important that physical and flat pointers.
    5577      */
    5578     if (    DBGCVAR_ISPOINTER(pArg2->enmType)
    5579         &&  (   !DBGCVAR_ISPOINTER(pArg1->enmType)
    5580              || (   DBGCVAR_IS_FAR_PTR(pArg2->enmType)
    5581                  && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))
    5582     {
    5583         PCDBGCVAR pTmp = pArg1;
    5584         pArg2 = pArg1;
    5585         pArg1 = pTmp;
    5586     }
    5587 
    5588     /*
    5589      * Convert the 2nd number into a number we use multiply the first with.
    5590      */
    5591     DBGCVAR Factor2 = *pArg2;
    5592     if (    Factor2.enmType == DBGCVAR_TYPE_STRING
    5593         ||  Factor2.enmType == DBGCVAR_TYPE_SYMBOL)
    5594     {
    5595         rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);
    5596         if (VBOX_FAILURE(rc))
    5597             return rc;
    5598     }
    5599     uint64_t u64Factor;
    5600     switch (Factor2.enmType)
    5601     {
    5602         case DBGCVAR_TYPE_GC_FLAT:  u64Factor = Factor2.u.GCFlat; break;
    5603         case DBGCVAR_TYPE_GC_FAR:   u64Factor = Factor2.u.GCFar.off; break;
    5604         case DBGCVAR_TYPE_GC_PHYS:  u64Factor = Factor2.u.GCPhys; break;
    5605         case DBGCVAR_TYPE_HC_FLAT:  u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;
    5606         case DBGCVAR_TYPE_HC_FAR:   u64Factor = Factor2.u.HCFar.off; break;
    5607         case DBGCVAR_TYPE_HC_PHYS:  u64Factor = Factor2.u.HCPhys; break;
    5608         case DBGCVAR_TYPE_NUMBER:   u64Factor = Factor2.u.u64Number; break;
    5609         default:
    5610             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5611     }
    5612 
    5613     /*
    5614      * Fix symbols in the 1st factor.
    5615      */
    5616     *pResult = *pArg1;
    5617     if (    pResult->enmType == DBGCVAR_TYPE_STRING
    5618         ||  pResult->enmType == DBGCVAR_TYPE_SYMBOL)
    5619     {
    5620         rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
    5621         if (VBOX_FAILURE(rc))
    5622             return rc;
    5623     }
    5624 
    5625     /*
    5626      * Do the multiplication.
    5627      */
    5628     switch (pArg1->enmType)
    5629     {
    5630         case DBGCVAR_TYPE_GC_FLAT:  pResult->u.GCFlat *= u64Factor; break;
    5631         case DBGCVAR_TYPE_GC_FAR:   pResult->u.GCFar.off *= u64Factor; break;
    5632         case DBGCVAR_TYPE_GC_PHYS:  pResult->u.GCPhys *= u64Factor; break;
    5633         case DBGCVAR_TYPE_HC_FLAT:
    5634             pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);
    5635             break;
    5636         case DBGCVAR_TYPE_HC_FAR:   pResult->u.HCFar.off *= u64Factor; break;
    5637         case DBGCVAR_TYPE_HC_PHYS:  pResult->u.HCPhys *= u64Factor; break;
    5638         case DBGCVAR_TYPE_NUMBER:   pResult->u.u64Number *= u64Factor; break;
    5639         default:
    5640             return VERR_PARSE_INCORRECT_ARG_TYPE;
    5641     }
    5642     return 0;
    5643 }
    5644 
    5645 
    5646 /**
    5647  * Division operator (binary).
    5648  *
    5649  * @returns 0 on success.
    5650  * @returns VBox evaluation / parsing error code on failure.
    5651  *          The caller does the bitching.
    5652  * @param   pDbgc       Debugger console instance data.
    5653  * @param   pArg1       The first argument.
    5654  * @param   pArg2       The 2nd argument.
    5655  * @param   pResult     Where to store the result.
    5656  */
    5657 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5658 {
    5659     LogFlow(("dbgcOpDiv\n"));
    5660     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    5661     return -1;
    5662 }
    5663 
    5664 
    5665 /**
    5666  * Modulus operator (binary).
    5667  *
    5668  * @returns 0 on success.
    5669  * @returns VBox evaluation / parsing error code on failure.
    5670  *          The caller does the bitching.
    5671  * @param   pDbgc       Debugger console instance data.
    5672  * @param   pArg1       The first argument.
    5673  * @param   pArg2       The 2nd argument.
    5674  * @param   pResult     Where to store the result.
    5675  */
    5676 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5677 {
    5678     LogFlow(("dbgcOpMod\n"));
    5679     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    5680     return -1;
    5681 }
    5682 
    5683 
    5684 /**
    5685  * Addition operator (binary).
    5686  *
    5687  * @returns 0 on success.
    5688  * @returns VBox evaluation / parsing error code on failure.
    5689  *          The caller does the bitching.
    5690  * @param   pDbgc       Debugger console instance data.
    5691  * @param   pArg1       The first argument.
    5692  * @param   pArg2       The 2nd argument.
    5693  * @param   pResult     Where to store the result.
    5694  */
    5695 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5696 {
    5697 //    LogFlow(("dbgcOpAdd\n"));
    5698 
    5699     /*
    5700      * An addition operation will return (when possible) the left side type in the
    5701      * expression. We make an omission for numbers, where we'll take the right side
    5702      * type instead. An expression where only the left hand side is a string we'll
    5703      * use the right hand type assuming that the string is a symbol.
    5704      */
    5705     if (    (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)
    5706         ||  (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))
    5707     {
    5708         PCDBGCVAR pTmp = pArg2;
    5709         pArg2 = pArg1;
    5710         pArg1 = pTmp;
    5711     }
    5712     DBGCVAR     Sym1, Sym2;
    5713     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    5714     {
    5715         int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
    5716         if (VBOX_FAILURE(rc))
    5717             return rc;
    5718         pArg1 = &Sym1;
    5719 
    5720         rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
    5721         if (VBOX_FAILURE(rc))
    5722             return rc;
    5723         pArg2 = &Sym2;
    5724     }
    5725 
    5726     int         rc;
    5727     DBGCVAR     Var;
    5728     DBGCVAR     Var2;
    5729     switch (pArg1->enmType)
    5730     {
    5731         /*
    5732          * GC Flat
    5733          */
    5734         case DBGCVAR_TYPE_GC_FLAT:
    5735             switch (pArg2->enmType)
    5736             {
    5737                 case DBGCVAR_TYPE_HC_FLAT:
    5738                 case DBGCVAR_TYPE_HC_FAR:
    5739                 case DBGCVAR_TYPE_HC_PHYS:
    5740                     return VERR_PARSE_INVALID_OPERATION;
    5741                 default:
    5742                     *pResult = *pArg1;
    5743                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    5744                     if (VBOX_FAILURE(rc))
    5745                         return rc;
    5746                     pResult->u.GCFlat += pArg2->u.GCFlat;
    5747                     break;
    5748             }
    5749             break;
    5750 
    5751         /*
    5752          * GC Far
    5753          */
    5754         case DBGCVAR_TYPE_GC_FAR:
    5755             switch (pArg2->enmType)
    5756             {
    5757                 case DBGCVAR_TYPE_HC_FLAT:
    5758                 case DBGCVAR_TYPE_HC_FAR:
    5759                 case DBGCVAR_TYPE_HC_PHYS:
    5760                     return VERR_PARSE_INVALID_OPERATION;
    5761                 case DBGCVAR_TYPE_NUMBER:
    5762                     *pResult = *pArg1;
    5763                     pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;
    5764                     break;
    5765                 default:
    5766                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    5767                     if (VBOX_FAILURE(rc))
    5768                         return rc;
    5769                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    5770                     if (VBOX_FAILURE(rc))
    5771                         return rc;
    5772                     pResult->u.GCFlat += pArg2->u.GCFlat;
    5773                     break;
    5774             }
    5775             break;
    5776 
    5777         /*
    5778          * GC Phys
    5779          */
    5780         case DBGCVAR_TYPE_GC_PHYS:
    5781             switch (pArg2->enmType)
    5782             {
    5783                 case DBGCVAR_TYPE_HC_FLAT:
    5784                 case DBGCVAR_TYPE_HC_FAR:
    5785                 case DBGCVAR_TYPE_HC_PHYS:
    5786                     return VERR_PARSE_INVALID_OPERATION;
    5787                 default:
    5788                     *pResult = *pArg1;
    5789                     rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
    5790                     if (VBOX_FAILURE(rc))
    5791                         return rc;
    5792                     if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
    5793                         return VERR_PARSE_INVALID_OPERATION;
    5794                     pResult->u.GCPhys += Var.u.GCPhys;
    5795                     break;
    5796             }
    5797             break;
    5798 
    5799         /*
    5800          * HC Flat
    5801          */
    5802         case DBGCVAR_TYPE_HC_FLAT:
    5803             *pResult = *pArg1;
    5804             rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    5805             if (VBOX_FAILURE(rc))
    5806                 return rc;
    5807             rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    5808             if (VBOX_FAILURE(rc))
    5809                 return rc;
    5810             pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
    5811             break;
    5812 
    5813         /*
    5814          * HC Far
    5815          */
    5816         case DBGCVAR_TYPE_HC_FAR:
    5817             switch (pArg2->enmType)
    5818             {
    5819                 case DBGCVAR_TYPE_NUMBER:
    5820                     *pResult = *pArg1;
    5821                     pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;
    5822                     break;
    5823 
    5824                 default:
    5825                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    5826                     if (VBOX_FAILURE(rc))
    5827                         return rc;
    5828                     rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    5829                     if (VBOX_FAILURE(rc))
    5830                         return rc;
    5831                     rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    5832                     if (VBOX_FAILURE(rc))
    5833                         return rc;
    5834                     pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
    5835                     break;
    5836             }
    5837             break;
    5838 
    5839         /*
    5840          * HC Phys
    5841          */
    5842         case DBGCVAR_TYPE_HC_PHYS:
    5843             *pResult = *pArg1;
    5844             rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
    5845             if (VBOX_FAILURE(rc))
    5846                 return rc;
    5847             pResult->u.HCPhys += Var.u.HCPhys;
    5848             break;
    5849 
    5850         /*
    5851          * Numbers (see start of function)
    5852          */
    5853         case DBGCVAR_TYPE_NUMBER:
    5854             *pResult = *pArg1;
    5855             switch (pArg2->enmType)
    5856             {
    5857                 case DBGCVAR_TYPE_SYMBOL:
    5858                 case DBGCVAR_TYPE_STRING:
    5859                     rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    5860                     if (VBOX_FAILURE(rc))
    5861                         return rc;
    5862                 case DBGCVAR_TYPE_NUMBER:
    5863                     pResult->u.u64Number += pArg2->u.u64Number;
    5864                     break;
    5865                 default:
    5866                     return VERR_PARSE_INVALID_OPERATION;
    5867             }
    5868             break;
    5869 
    5870         default:
    5871             return VERR_PARSE_INVALID_OPERATION;
    5872 
    5873     }
    5874     return 0;
    5875 }
    5876 
    5877 
    5878 /**
    5879  * Subtration operator (binary).
    5880  *
    5881  * @returns 0 on success.
    5882  * @returns VBox evaluation / parsing error code on failure.
    5883  *          The caller does the bitching.
    5884  * @param   pDbgc       Debugger console instance data.
    5885  * @param   pArg1       The first argument.
    5886  * @param   pArg2       The 2nd argument.
    5887  * @param   pResult     Where to store the result.
    5888  */
    5889 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    5890 {
    5891 //    LogFlow(("dbgcOpSub\n"));
    5892 
    5893     /*
    5894      * An subtraction operation will return the left side type in the expression.
    5895      * However, if the left hand side is a number and the right hand a pointer of
    5896      * some kind we'll convert the left hand side to the same type as the right hand.
    5897      * Any strings will be attempted resolved as symbols.
    5898      */
    5899     DBGCVAR     Sym1, Sym2;
    5900     if (    pArg2->enmType == DBGCVAR_TYPE_STRING
    5901         &&  (   pArg1->enmType == DBGCVAR_TYPE_NUMBER
    5902              || pArg1->enmType == DBGCVAR_TYPE_STRING))
    5903     {
    5904         int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
    5905         if (VBOX_FAILURE(rc))
    5906             return rc;
    5907         pArg2 = &Sym2;
    5908     }
    5909 
    5910     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    5911     {
    5912         DBGCVARTYPE enmType;
    5913         switch (pArg2->enmType)
    5914         {
    5915             case DBGCVAR_TYPE_NUMBER:
    5916                 enmType = DBGCVAR_TYPE_ANY;
    5917                 break;
    5918             case DBGCVAR_TYPE_GC_FLAT:
    5919             case DBGCVAR_TYPE_GC_PHYS:
    5920             case DBGCVAR_TYPE_HC_FLAT:
    5921             case DBGCVAR_TYPE_HC_PHYS:
    5922                 enmType = pArg2->enmType;
    5923                 break;
    5924             case DBGCVAR_TYPE_GC_FAR:
    5925                 enmType = DBGCVAR_TYPE_GC_FLAT;
    5926                 break;
    5927             case DBGCVAR_TYPE_HC_FAR:
    5928                 enmType = DBGCVAR_TYPE_HC_FLAT;
    5929                 break;
    5930 
    5931             default:
    5932             case DBGCVAR_TYPE_STRING:
    5933                 AssertMsgFailed(("Can't happen\n"));
    5934                 enmType = DBGCVAR_TYPE_STRING;
    5935                 break;
    5936         }
    5937         if (enmType != DBGCVAR_TYPE_STRING)
    5938         {
    5939             int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
    5940             if (VBOX_FAILURE(rc))
    5941                 return rc;
    5942             pArg1 = &Sym1;
    5943         }
    5944     }
    5945     else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)
    5946     {
    5947         PFNDBGCOPUNARY pOp = NULL;
    5948         switch (pArg2->enmType)
    5949         {
    5950             case DBGCVAR_TYPE_GC_FAR:
    5951             case DBGCVAR_TYPE_GC_FLAT:
    5952                 pOp = dbgcOpAddrFlat;
    5953                 break;
    5954             case DBGCVAR_TYPE_GC_PHYS:
    5955                 pOp = dbgcOpAddrPhys;
    5956                 break;
    5957             case DBGCVAR_TYPE_HC_FAR:
    5958             case DBGCVAR_TYPE_HC_FLAT:
    5959                 pOp = dbgcOpAddrHost;
    5960                 break;
    5961             case DBGCVAR_TYPE_HC_PHYS:
    5962                 pOp = dbgcOpAddrHostPhys;
    5963                 break;
    5964             case DBGCVAR_TYPE_NUMBER:
    5965                 break;
    5966             default:
    5967             case DBGCVAR_TYPE_STRING:
    5968                 AssertMsgFailed(("Can't happen\n"));
    5969                 break;
    5970         }
    5971         if (pOp)
    5972         {
    5973             int rc = pOp(pDbgc, pArg1, &Sym1);
    5974             if (VBOX_FAILURE(rc))
    5975                 return rc;
    5976             pArg1 = &Sym1;
    5977         }
    5978     }
    5979 
    5980 
    5981     /*
    5982      * Normal processing.
    5983      */
    5984     int         rc;
    5985     DBGCVAR     Var;
    5986     DBGCVAR     Var2;
    5987     switch (pArg1->enmType)
    5988     {
    5989         /*
    5990          * GC Flat
    5991          */
    5992         case DBGCVAR_TYPE_GC_FLAT:
    5993             switch (pArg2->enmType)
    5994             {
    5995                 case DBGCVAR_TYPE_HC_FLAT:
    5996                 case DBGCVAR_TYPE_HC_FAR:
    5997                 case DBGCVAR_TYPE_HC_PHYS:
    5998                     return VERR_PARSE_INVALID_OPERATION;
    5999                 default:
    6000                     *pResult = *pArg1;
    6001                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    6002                     if (VBOX_FAILURE(rc))
    6003                         return rc;
    6004                     pResult->u.GCFlat -= pArg2->u.GCFlat;
    6005                     break;
    6006             }
    6007             break;
    6008 
    6009         /*
    6010          * GC Far
    6011          */
    6012         case DBGCVAR_TYPE_GC_FAR:
    6013             switch (pArg2->enmType)
    6014             {
    6015                 case DBGCVAR_TYPE_HC_FLAT:
    6016                 case DBGCVAR_TYPE_HC_FAR:
    6017                 case DBGCVAR_TYPE_HC_PHYS:
    6018                     return VERR_PARSE_INVALID_OPERATION;
    6019                 case DBGCVAR_TYPE_NUMBER:
    6020                     *pResult = *pArg1;
    6021                     pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;
    6022                     break;
    6023                 default:
    6024                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    6025                     if (VBOX_FAILURE(rc))
    6026                         return rc;
    6027                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    6028                     if (VBOX_FAILURE(rc))
    6029                         return rc;
    6030                     pResult->u.GCFlat -= pArg2->u.GCFlat;
    6031                     break;
    6032             }
    6033             break;
    6034 
    6035         /*
    6036          * GC Phys
    6037          */
    6038         case DBGCVAR_TYPE_GC_PHYS:
    6039             switch (pArg2->enmType)
    6040             {
    6041                 case DBGCVAR_TYPE_HC_FLAT:
    6042                 case DBGCVAR_TYPE_HC_FAR:
    6043                 case DBGCVAR_TYPE_HC_PHYS:
    6044                     return VERR_PARSE_INVALID_OPERATION;
    6045                 default:
    6046                     *pResult = *pArg1;
    6047                     rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
    6048                     if (VBOX_FAILURE(rc))
    6049                         return rc;
    6050                     if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
    6051                         return VERR_PARSE_INVALID_OPERATION;
    6052                     pResult->u.GCPhys -= Var.u.GCPhys;
    6053                     break;
    6054             }
    6055             break;
    6056 
    6057         /*
    6058          * HC Flat
    6059          */
    6060         case DBGCVAR_TYPE_HC_FLAT:
    6061             *pResult = *pArg1;
    6062             rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    6063             if (VBOX_FAILURE(rc))
    6064                 return rc;
    6065             rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    6066             if (VBOX_FAILURE(rc))
    6067                 return rc;
    6068             pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
    6069             break;
    6070 
    6071         /*
    6072          * HC Far
    6073          */
    6074         case DBGCVAR_TYPE_HC_FAR:
    6075             switch (pArg2->enmType)
    6076             {
    6077                 case DBGCVAR_TYPE_NUMBER:
    6078                     *pResult = *pArg1;
    6079                     pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;
    6080                     break;
    6081 
    6082                 default:
    6083                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    6084                     if (VBOX_FAILURE(rc))
    6085                         return rc;
    6086                     rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    6087                     if (VBOX_FAILURE(rc))
    6088                         return rc;
    6089                     rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    6090                     if (VBOX_FAILURE(rc))
    6091                         return rc;
    6092                     pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
    6093                     break;
    6094             }
    6095             break;
    6096 
    6097         /*
    6098          * HC Phys
    6099          */
    6100         case DBGCVAR_TYPE_HC_PHYS:
    6101             *pResult = *pArg1;
    6102             rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
    6103             if (VBOX_FAILURE(rc))
    6104                 return rc;
    6105             pResult->u.HCPhys -= Var.u.HCPhys;
    6106             break;
    6107 
    6108         /*
    6109          * Numbers (see start of function)
    6110          */
    6111         case DBGCVAR_TYPE_NUMBER:
    6112             *pResult = *pArg1;
    6113             switch (pArg2->enmType)
    6114             {
    6115                 case DBGCVAR_TYPE_SYMBOL:
    6116                 case DBGCVAR_TYPE_STRING:
    6117                     rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    6118                     if (VBOX_FAILURE(rc))
    6119                         return rc;
    6120                 case DBGCVAR_TYPE_NUMBER:
    6121                     pResult->u.u64Number -= pArg2->u.u64Number;
    6122                     break;
    6123                 default:
    6124                     return VERR_PARSE_INVALID_OPERATION;
    6125             }
    6126             break;
    6127 
    6128         default:
    6129             return VERR_PARSE_INVALID_OPERATION;
    6130 
    6131     }
    6132     return 0;
    6133 }
    6134 
    6135 
    6136 /**
    6137  * Bitwise shift left operator (binary).
    6138  *
    6139  * @returns 0 on success.
    6140  * @returns VBox evaluation / parsing error code on failure.
    6141  *          The caller does the bitching.
    6142  * @param   pDbgc       Debugger console instance data.
    6143  * @param   pArg1       The first argument.
    6144  * @param   pArg2       The 2nd argument.
    6145  * @param   pResult     Where to store the result.
    6146  */
    6147 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6148 {
    6149     LogFlow(("dbgcOpBitwiseShiftLeft\n"));
    6150     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6151     return -1;
    6152 }
    6153 
    6154 
    6155 /**
    6156  * Bitwise shift right operator (binary).
    6157  *
    6158  * @returns 0 on success.
    6159  * @returns VBox evaluation / parsing error code on failure.
    6160  *          The caller does the bitching.
    6161  * @param   pDbgc       Debugger console instance data.
    6162  * @param   pArg1       The first argument.
    6163  * @param   pArg2       The 2nd argument.
    6164  * @param   pResult     Where to store the result.
    6165  */
    6166 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6167 {
    6168     LogFlow(("dbgcOpBitwiseShiftRight\n"));
    6169     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6170     return -1;
    6171 }
    6172 
    6173 
    6174 /**
    6175  * Bitwise and operator (binary).
    6176  *
    6177  * @returns 0 on success.
    6178  * @returns VBox evaluation / parsing error code on failure.
    6179  *          The caller does the bitching.
    6180  * @param   pDbgc       Debugger console instance data.
    6181  * @param   pArg1       The first argument.
    6182  * @param   pArg2       The 2nd argument.
    6183  * @param   pResult     Where to store the result.
    6184  */
    6185 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6186 {
    6187     LogFlow(("dbgcOpBitwiseAnd\n"));
    6188     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6189     return -1;
    6190 }
    6191 
    6192 
    6193 /**
    6194  * Bitwise exclusive or operator (binary).
    6195  *
    6196  * @returns 0 on success.
    6197  * @returns VBox evaluation / parsing error code on failure.
    6198  *          The caller does the bitching.
    6199  * @param   pDbgc       Debugger console instance data.
    6200  * @param   pArg1       The first argument.
    6201  * @param   pArg2       The 2nd argument.
    6202  * @param   pResult     Where to store the result.
    6203  */
    6204 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6205 {
    6206     LogFlow(("dbgcOpBitwiseXor\n"));
    6207     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6208     return -1;
    6209 }
    6210 
    6211 
    6212 /**
    6213  * Bitwise inclusive or operator (binary).
    6214  *
    6215  * @returns 0 on success.
    6216  * @returns VBox evaluation / parsing error code on failure.
    6217  *          The caller does the bitching.
    6218  * @param   pDbgc       Debugger console instance data.
    6219  * @param   pArg1       The first argument.
    6220  * @param   pArg2       The 2nd argument.
    6221  * @param   pResult     Where to store the result.
    6222  */
    6223 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6224 {
    6225     LogFlow(("dbgcOpBitwiseOr\n"));
    6226     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6227     return -1;
    6228 }
    6229 
    6230 
    6231 /**
    6232  * Boolean and operator (binary).
    6233  *
    6234  * @returns 0 on success.
    6235  * @returns VBox evaluation / parsing error code on failure.
    6236  *          The caller does the bitching.
    6237  * @param   pDbgc       Debugger console instance data.
    6238  * @param   pArg1       The first argument.
    6239  * @param   pArg2       The 2nd argument.
    6240  * @param   pResult     Where to store the result.
    6241  */
    6242 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6243 {
    6244     LogFlow(("dbgcOpBooleanAnd\n"));
    6245     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6246     return -1;
    6247 }
    6248 
    6249 
    6250 /**
    6251  * Boolean or operator (binary).
    6252  *
    6253  * @returns 0 on success.
    6254  * @returns VBox evaluation / parsing error code on failure.
    6255  *          The caller does the bitching.
    6256  * @param   pDbgc       Debugger console instance data.
    6257  * @param   pArg1       The first argument.
    6258  * @param   pArg2       The 2nd argument.
    6259  * @param   pResult     Where to store the result.
    6260  */
    6261 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6262 {
    6263     LogFlow(("dbgcOpBooleanOr\n"));
    6264     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    6265     return -1;
    6266 }
    6267 
    6268 
    6269 /**
    6270  * Range to operator (binary).
    6271  *
    6272  * @returns 0 on success.
    6273  * @returns VBox evaluation / parsing error code on failure.
    6274  *          The caller does the bitching.
    6275  * @param   pDbgc       Debugger console instance data.
    6276  * @param   pArg1       The first argument.
    6277  * @param   pArg2       The 2nd argument.
    6278  * @param   pResult     Where to store the result.
    6279  */
    6280 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6281 {
    6282 //    LogFlow(("dbgcOpRangeLength\n"));
    6283     /*
    6284      * Make result. Strings needs to be resolved into symbols.
    6285      */
    6286     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    6287     {
    6288         int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
    6289         if (VBOX_FAILURE(rc))
    6290             return rc;
    6291     }
    6292     else
    6293         *pResult = *pArg1;
    6294 
    6295     /*
    6296      * Convert 2nd argument to element count.
    6297      */
    6298     pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    6299     switch (pArg2->enmType)
    6300     {
    6301         case DBGCVAR_TYPE_NUMBER:
    6302             pResult->u64Range = pArg2->u.u64Number;
    6303             break;
    6304 
    6305         case DBGCVAR_TYPE_STRING:
    6306         {
    6307             int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
    6308             if (VBOX_FAILURE(rc))
    6309                 return rc;
    6310             pResult->u64Range = pArg2->u.u64Number;
    6311             break;
    6312         }
    6313 
    6314         default:
    6315             return VERR_PARSE_INVALID_OPERATION;
    6316     }
    6317 
    6318     return VINF_SUCCESS;
    6319 }
    6320 
    6321 
    6322 /**
    6323  * Range to operator (binary).
    6324  *
    6325  * @returns 0 on success.
    6326  * @returns VBox evaluation / parsing error code on failure.
    6327  *          The caller does the bitching.
    6328  * @param   pDbgc       Debugger console instance data.
    6329  * @param   pArg1       The first argument.
    6330  * @param   pArg2       The 2nd argument.
    6331  * @param   pResult     Where to store the result.
    6332  */
    6333 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6334 {
    6335 //    LogFlow(("dbgcOpRangeLengthBytes\n"));
    6336     int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);
    6337     if (VBOX_SUCCESS(rc))
    6338         pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
    6339     return rc;
    6340 }
    6341 
    6342 
    6343 /**
    6344  * Range to operator (binary).
    6345  *
    6346  * @returns 0 on success.
    6347  * @returns VBox evaluation / parsing error code on failure.
    6348  *          The caller does the bitching.
    6349  * @param   pDbgc       Debugger console instance data.
    6350  * @param   pArg1       The first argument.
    6351  * @param   pArg2       The 2nd argument.
    6352  * @param   pResult     Where to store the result.
    6353  */
    6354 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    6355 {
    6356 //    LogFlow(("dbgcOpRangeTo\n"));
    6357     /*
    6358      * Calc number of bytes between the two args.
    6359      */
    6360     DBGCVAR Diff;
    6361     int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);
    6362     if (VBOX_FAILURE(rc))
    6363         return rc;
    6364 
    6365     /*
    6366      * Use the diff as the range of Arg1.
    6367      */
    6368     *pResult = *pArg1;
    6369     pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
    6370     switch (Diff.enmType)
    6371     {
    6372         case DBGCVAR_TYPE_GC_FLAT:
    6373             pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;
    6374             break;
    6375         case DBGCVAR_TYPE_GC_PHYS:
    6376             pResult->u64Range = Diff.u.GCPhys;
    6377             break;
    6378         case DBGCVAR_TYPE_HC_FLAT:
    6379             pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;
    6380             break;
    6381         case DBGCVAR_TYPE_HC_PHYS:
    6382             pResult->u64Range = Diff.u.HCPhys;
    6383             break;
    6384         case DBGCVAR_TYPE_NUMBER:
    6385             pResult->u64Range = Diff.u.u64Number;
    6386             break;
    6387 
    6388         case DBGCVAR_TYPE_GC_FAR:
    6389         case DBGCVAR_TYPE_STRING:
    6390         case DBGCVAR_TYPE_HC_FAR:
    6391         default:
    6392             AssertMsgFailed(("Impossible!\n"));
    6393             return VERR_PARSE_INVALID_OPERATION;
    6394     }
    6395 
    6396     return 0;
    6397 }
    6398 
    6399 
    6400 
    6401 
    6402 
    6403 /**
    6404  * Output callback.
    6405  *
    6406  * @returns number of bytes written.
    6407  * @param   pvArg       User argument.
    6408  * @param   pachChars   Pointer to an array of utf-8 characters.
    6409  * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    6410  */
    6411 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
    6412 {
    6413     PDBGC   pDbgc = (PDBGC)pvArg;
    6414     if (cbChars)
    6415     {
    6416         int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
    6417         if (VBOX_FAILURE(rc))
    6418         {
    6419             pDbgc->rcOutput = rc;
    6420             cbChars = 0;
    6421         }
    6422     }
    6423 
    6424     return cbChars;
    6425 }
    6426 
    6427 
    6428 
    6429 
    6430 
    6431 
    6432 
    6433 
    6434 
    6435 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    6436 //
    6437 //
    6438 //      C a l l b a c k   H e l p e r s
    6439 //
    6440 //
    6441 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    6442 
    6443 
    6444 
    6445 /**
    6446  * Command helper for writing text to the debug console.
    6447  *
    6448  * @returns VBox status.
    6449  * @param   pCmdHlp     Pointer to the command callback structure.
    6450  * @param   pvBuf       What to write.
    6451  * @param   cbBuf       Number of bytes to write.
    6452  * @param   pcbWritten  Where to store the number of bytes actually written.
    6453  *                      If NULL the entire buffer must be successfully written.
    6454  */
    6455 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    6456 {
    6457     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6458     return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
    6459 }
    6460 
    6461 
    6462 /**
    6463  * Command helper for writing formatted text to the debug console.
    6464  *
    6465  * @returns VBox status.
    6466  * @param   pCmdHlp     Pointer to the command callback structure.
    6467  * @param   pcb         Where to store the number of bytes written.
    6468  * @param   pszFormat   The format string.
    6469  *                      This is using the log formatter, so it's format extensions can be used.
    6470  * @param   ...         Arguments specified in the format string.
    6471  */
    6472 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
    6473 {
    6474     /*
    6475      * Do the formatting and output.
    6476      */
    6477     va_list args;
    6478     va_start(args, pszFormat);
    6479     int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
    6480     va_end(args);
    6481 
    6482     return rc;
    6483 }
    6484 
    6485 /**
    6486  * Callback to format non-standard format specifiers.
    6487  *
    6488  * @returns The number of bytes formatted.
    6489  * @param   pvArg           Formatter argument.
    6490  * @param   pfnOutput       Pointer to output function.
    6491  * @param   pvArgOutput     Argument for the output function.
    6492  * @param   ppszFormat      Pointer to the format string pointer. Advance this till the char
    6493  *                          after the format specifier.
    6494  * @param   pArgs           Pointer to the argument list. Use this to fetch the arguments.
    6495  * @param   cchWidth        Format Width. -1 if not specified.
    6496  * @param   cchPrecision    Format Precision. -1 if not specified.
    6497  * @param   fFlags          Flags (RTSTR_NTFS_*).
    6498  * @param   chArgSize       The argument size specifier, 'l' or 'L'.
    6499  */
    6500 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
    6501                                                 const char **ppszFormat, va_list *pArgs, int cchWidth,
    6502                                                 int cchPrecision, unsigned fFlags, char chArgSize)
    6503 {
    6504     NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
    6505     if (**ppszFormat != 'D')
    6506     {
    6507         (*ppszFormat)++;
    6508         return 0;
    6509     }
    6510 
    6511     (*ppszFormat)++;
    6512     switch (**ppszFormat)
    6513     {
    6514         /*
    6515          * Print variable without range.
    6516          * The argument is a const pointer to the variable.
    6517          */
    6518         case 'V':
    6519         {
    6520             (*ppszFormat)++;
    6521             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    6522             switch (pVar->enmType)
    6523             {
    6524                 case DBGCVAR_TYPE_GC_FLAT:
    6525                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
    6526                 case DBGCVAR_TYPE_GC_FAR:
    6527                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
    6528                 case DBGCVAR_TYPE_GC_PHYS:
    6529                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
    6530                 case DBGCVAR_TYPE_HC_FLAT:
    6531                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
    6532                 case DBGCVAR_TYPE_HC_FAR:
    6533                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
    6534                 case DBGCVAR_TYPE_HC_PHYS:
    6535                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
    6536                 case DBGCVAR_TYPE_STRING:
    6537                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    6538                 case DBGCVAR_TYPE_NUMBER:
    6539                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
    6540 
    6541                 case DBGCVAR_TYPE_UNKNOWN:
    6542                 default:
    6543                     return pfnOutput(pvArgOutput, "??", 2);
    6544             }
    6545         }
    6546 
    6547         /*
    6548          * Print variable with range.
    6549          * The argument is a const pointer to the variable.
    6550          */
    6551         case 'v':
    6552         {
    6553             (*ppszFormat)++;
    6554             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    6555 
    6556             char szRange[32];
    6557             switch (pVar->enmRangeType)
    6558             {
    6559                 case DBGCVAR_RANGE_NONE:
    6560                     szRange[0] = '\0';
    6561                     break;
    6562                 case DBGCVAR_RANGE_ELEMENTS:
    6563                     RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
    6564                     break;
    6565                 case DBGCVAR_RANGE_BYTES:
    6566                     RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
    6567                     break;
    6568             }
    6569 
    6570             switch (pVar->enmType)
    6571             {
    6572                 case DBGCVAR_TYPE_GC_FLAT:
    6573                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
    6574                 case DBGCVAR_TYPE_GC_FAR:
    6575                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
    6576                 case DBGCVAR_TYPE_GC_PHYS:
    6577                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
    6578                 case DBGCVAR_TYPE_HC_FLAT:
    6579                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
    6580                 case DBGCVAR_TYPE_HC_FAR:
    6581                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
    6582                 case DBGCVAR_TYPE_HC_PHYS:
    6583                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
    6584                 case DBGCVAR_TYPE_STRING:
    6585                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    6586                 case DBGCVAR_TYPE_NUMBER:
    6587                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
    6588 
    6589                 case DBGCVAR_TYPE_UNKNOWN:
    6590                 default:
    6591                     return pfnOutput(pvArgOutput, "??", 2);
    6592             }
    6593         }
    6594 
    6595         default:
    6596             AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
    6597             return 0;
    6598     }
    6599 }
    6600 
    6601 
    6602 /**
    6603  * Command helper for writing formatted text to the debug console.
    6604  *
    6605  * @returns VBox status.
    6606  * @param   pCmdHlp     Pointer to the command callback structure.
    6607  * @param   pcb         Where to store the number of bytes written.
    6608  * @param   pszFormat   The format string.
    6609  *                      This is using the log formatter, so it's format extensions can be used.
    6610  * @param   args        Arguments specified in the format string.
    6611  */
    6612 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
    6613 {
    6614     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6615 
    6616     /*
    6617      * Do the formatting and output.
    6618      */
    6619     pDbgc->rcOutput = 0;
    6620     size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
    6621 
    6622     if (pcbWritten)
    6623         *pcbWritten = cb;
    6624 
    6625     return pDbgc->rcOutput;
    6626 }
    6627 
    6628 
    6629 /**
    6630  * Reports an error from a DBGF call.
    6631  *
    6632  * @returns VBox status code appropriate to return from a command.
    6633  * @param   pCmdHlp     Pointer to command helpers.
    6634  * @param   rc          The VBox status code returned by a DBGF call.
    6635  * @param   pszFormat   Format string for additional messages. Can be NULL.
    6636  * @param   ...         Format arguments, optional.
    6637  */
    6638 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
    6639 {
    6640     switch (rc)
    6641     {
    6642         case VINF_SUCCESS:
    6643             break;
    6644 
    6645         default:
    6646             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
    6647             if (VBOX_SUCCESS(rc) && pszFormat)
    6648                 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    6649             break;
    6650     }
    6651     return rc;
    6652 }
    6653 
    6654 
    6655 /**
    6656  * Reports an error from a DBGF call.
    6657  *
    6658  * @returns VBox status code appropriate to return from a command.
    6659  * @param   pCmdHlp     Pointer to command helpers.
    6660  * @param   rc          The VBox status code returned by a DBGF call.
    6661  * @param   pszFormat   Format string for additional messages. Can be NULL.
    6662  * @param   ...         Format arguments, optional.
    6663  */
    6664 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
    6665 {
    6666     va_list args;
    6667     va_start(args, pszFormat);
    6668     int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
    6669     va_end(args);
    6670     return rcRet;
    6671 }
    6672 
    6673 
    6674 /**
    6675  * Command helper for reading memory specified by a DBGC variable.
    6676  *
    6677  * @returns VBox status code appropriate to return from a command.
    6678  * @param   pCmdHlp     Pointer to the command callback structure.
    6679  * @param   pVM         VM handle if GC or physical HC address.
    6680  * @param   pvBuffer    Where to store the read data.
    6681  * @param   cbRead      Number of bytes to read.
    6682  * @param   pVarPointer DBGC variable specifying where to start reading.
    6683  * @param   pcbRead     Where to store the number of bytes actually read.
    6684  *                      This optional, but it's useful when read GC virtual memory where a
    6685  *                      page in the requested range might not be present.
    6686  *                      If not specified not-present failure or end of a HC physical page
    6687  *                      will cause failure.
    6688  */
    6689 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
    6690 {
    6691     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6692 
    6693     /*
    6694      * Dummy check.
    6695      */
    6696     if (cbRead == 0)
    6697     {
    6698         if (*pcbRead)
    6699             *pcbRead = 0;
    6700         return VINF_SUCCESS;
    6701     }
    6702 
    6703     /*
    6704      * Convert Far addresses getting size and the correct base address.
    6705      * Getting and checking the size is what makes this messy and slow.
    6706      */
    6707     DBGCVAR Var = *pVarPointer;
    6708     switch (pVarPointer->enmType)
    6709     {
    6710         case DBGCVAR_TYPE_GC_FAR:
    6711         {
    6712             /* Use DBGFR3AddrFromSelOff for the conversion. */
    6713             Assert(pDbgc->pVM);
    6714             DBGFADDRESS Address;
    6715             int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
    6716             if (VBOX_FAILURE(rc))
    6717                 return rc;
    6718 
    6719             /* don't bother with flat selectors (for now). */
    6720             if (!DBGFADDRESS_IS_FLAT(&Address))
    6721             {
    6722                 SELMSELINFO SelInfo;
    6723                 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
    6724                 if (VBOX_SUCCESS(rc))
    6725                 {
    6726                     RTGCUINTPTR cb; /* -1 byte */
    6727                     if (SELMSelInfoIsExpandDown(&SelInfo))
    6728                     {
    6729                         if (    !SelInfo.Raw.Gen.u1Granularity
    6730                             &&  Address.off > UINT16_C(0xffff))
    6731                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    6732                         if (Address.off <= SelInfo.cbLimit)
    6733                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    6734                         cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
    6735                     }
    6736                     else
    6737                     {
    6738                         if (Address.off > SelInfo.cbLimit)
    6739                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    6740                         cb = SelInfo.cbLimit - Address.off;
    6741                     }
    6742                     if (cbRead - 1 > cb)
    6743                     {
    6744                         if (!pcbRead)
    6745                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    6746                         cbRead = cb + 1;
    6747                     }
    6748                 }
    6749 
    6750                 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
    6751                 Var.u.GCFlat = Address.FlatPtr;
    6752             }
    6753             break;
    6754         }
    6755 
    6756         case DBGCVAR_TYPE_GC_FLAT:
    6757         case DBGCVAR_TYPE_GC_PHYS:
    6758         case DBGCVAR_TYPE_HC_FLAT:
    6759         case DBGCVAR_TYPE_HC_PHYS:
    6760             break;
    6761 
    6762         case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
    6763         default:
    6764             return VERR_NOT_IMPLEMENTED;
    6765     }
    6766 
    6767 
    6768 
    6769     /*
    6770      * Copy page by page.
    6771      */
    6772     size_t cbLeft = cbRead;
    6773     for (;;)
    6774     {
    6775         /*
    6776          * Calc read size.
    6777          */
    6778         size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
    6779         switch (pVarPointer->enmType)
    6780         {
    6781             case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
    6782             case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
    6783             case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
    6784             case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */
    6785             default: break;
    6786         }
    6787 
    6788         /*
    6789          * Perform read.
    6790          */
    6791         int rc;
    6792         switch (Var.enmType)
    6793         {
    6794             case DBGCVAR_TYPE_GC_FLAT:
    6795                 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
    6796                 break;
    6797             case DBGCVAR_TYPE_GC_PHYS:
    6798                 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
    6799                 break;
    6800 
    6801             case DBGCVAR_TYPE_HC_PHYS:
    6802             case DBGCVAR_TYPE_HC_FLAT:
    6803             case DBGCVAR_TYPE_HC_FAR:
    6804             {
    6805                 DBGCVAR Var2;
    6806                 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
    6807                 if (VBOX_SUCCESS(rc))
    6808                 {
    6809                     /** @todo protect this!!! */
    6810                     memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
    6811                     rc = 0;
    6812                 }
    6813                 else
    6814                     rc = VERR_INVALID_POINTER;
    6815                 break;
    6816             }
    6817 
    6818             default:
    6819                 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
    6820         }
    6821 
    6822         /*
    6823          * Check for failure.
    6824          */
    6825         if (VBOX_FAILURE(rc))
    6826         {
    6827             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    6828                 return VINF_SUCCESS;
    6829             return rc;
    6830         }
    6831 
    6832         /*
    6833          * Next.
    6834          */
    6835         cbLeft -= cb;
    6836         if (!cbLeft)
    6837             break;
    6838         pvBuffer = (char *)pvBuffer + cb;
    6839         rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
    6840         if (VBOX_FAILURE(rc))
    6841         {
    6842             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    6843                 return VINF_SUCCESS;
    6844             return rc;
    6845         }
    6846     }
    6847 
    6848     /*
    6849      * Done
    6850      */
    6851     if (pcbRead)
    6852         *pcbRead = cbRead;
    6853     return 0;
    6854 }
    6855 
    6856 /**
    6857  * Command helper for writing memory specified by a DBGC variable.
    6858  *
    6859  * @returns VBox status code appropriate to return from a command.
    6860  * @param   pCmdHlp     Pointer to the command callback structure.
    6861  * @param   pVM         VM handle if GC or physical HC address.
    6862  * @param   pvBuffer    What to write.
    6863  * @param   cbWrite     Number of bytes to write.
    6864  * @param   pVarPointer DBGC variable specifying where to start reading.
    6865  * @param   pcbWritten  Where to store the number of bytes written.
    6866  *                      This is optional. If NULL be aware that some of the buffer
    6867  *                      might have been written to the specified address.
    6868  */
    6869 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
    6870 {
    6871     NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
    6872     return VERR_NOT_IMPLEMENTED;
    6873 }
    6874 
    6875 
    6876 /**
    6877  * Evaluates an expression.
    6878  * (Hopefully the parser and functions are fully reentrant.)
    6879  *
    6880  * @returns VBox status code appropriate to return from a command.
    6881  * @param   pCmdHlp     Pointer to the command callback structure.
    6882  * @param   pResult     Where to store the result.
    6883  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    6884  * @param   ...         Format arguments.
    6885  */
    6886 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
    6887 {
    6888     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6889 
    6890     /*
    6891      * Format the expression.
    6892      */
    6893     char szExprFormatted[2048];
    6894     va_list args;
    6895     va_start(args, pszExpr);
    6896     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
    6897     va_end(args);
    6898     /* ignore overflows. */
    6899 
    6900     return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
    6901 }
    6902 
    6903 
    6904 /**
    6905  * Executes one command expression.
    6906  * (Hopefully the parser and functions are fully reentrant.)
    6907  *
    6908  * @returns VBox status code appropriate to return from a command.
    6909  * @param   pCmdHlp     Pointer to the command callback structure.
    6910  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    6911  * @param   ...         Format arguments.
    6912  */
    6913 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
    6914 {
    6915     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6916     /* Save the scratch state. */
    6917     char       *pszScratch  = pDbgc->pszScratch;
    6918     unsigned    iArg        = pDbgc->iArg;
    6919 
    6920     /*
    6921      * Format the expression.
    6922      */
    6923     va_list args;
    6924     va_start(args, pszExpr);
    6925     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    6926     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
    6927     va_end(args);
    6928     if (cb >= cbScratch)
    6929         return VERR_BUFFER_OVERFLOW;
    6930 
    6931     /*
    6932      * Execute the command.
    6933      * We save and restore the arg index and scratch buffer pointer.
    6934      */
    6935     pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
    6936     int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
    6937 
    6938     /* Restore the scratch state. */
    6939     pDbgc->iArg         = iArg;
    6940     pDbgc->pszScratch   = pszScratch;
    6941 
    6942     return rc;
    6943 }
    6944 
    6945 
    6946 /**
    6947  * Converts a DBGC variable to a DBGF address structure.
    6948  *
    6949  * @returns VBox status code.
    6950  * @param   pCmdHlp     Pointer to the command callback structure.
    6951  * @param   pVar        The variable to convert.
    6952  * @param   pAddress    The target address.
    6953  */
    6954 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    6955 {
    6956     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6957     return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
    6958 }
    6959 
    6960 
    6961 /**
    6962  * Converts a DBGC variable to a boolean.
    6963  *
    6964  * @returns VBox status code.
    6965  * @param   pCmdHlp     Pointer to the command callback structure.
    6966  * @param   pVar        The variable to convert.
    6967  * @param   pf          Where to store the boolean.
    6968  */
    6969 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
    6970 {
    6971     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    6972     NOREF(pDbgc);
    6973 
    6974     switch (pVar->enmType)
    6975     {
    6976         case DBGCVAR_TYPE_STRING:
    6977             /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
    6978             if (    !strcmp(pVar->u.pszString, "true")
    6979                 ||  !strcmp(pVar->u.pszString, "True")
    6980                 ||  !strcmp(pVar->u.pszString, "TRUE")
    6981                 ||  !strcmp(pVar->u.pszString, "on")
    6982                 ||  !strcmp(pVar->u.pszString, "On")
    6983                 ||  !strcmp(pVar->u.pszString, "oN")
    6984                 ||  !strcmp(pVar->u.pszString, "ON")
    6985                 ||  !strcmp(pVar->u.pszString, "enabled")
    6986                 ||  !strcmp(pVar->u.pszString, "Enabled")
    6987                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    6988             {
    6989                 *pf = true;
    6990                 return VINF_SUCCESS;
    6991             }
    6992             if (    !strcmp(pVar->u.pszString, "false")
    6993                 ||  !strcmp(pVar->u.pszString, "False")
    6994                 ||  !strcmp(pVar->u.pszString, "FALSE")
    6995                 ||  !strcmp(pVar->u.pszString, "off")
    6996                 ||  !strcmp(pVar->u.pszString, "Off")
    6997                 ||  !strcmp(pVar->u.pszString, "OFF")
    6998                 ||  !strcmp(pVar->u.pszString, "disabled")
    6999                 ||  !strcmp(pVar->u.pszString, "Disabled")
    7000                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    7001             {
    7002                 *pf = false;
    7003                 return VINF_SUCCESS;
    7004             }
    7005             return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
    7006 
    7007         case DBGCVAR_TYPE_GC_FLAT:
    7008         case DBGCVAR_TYPE_GC_PHYS:
    7009         case DBGCVAR_TYPE_HC_FLAT:
    7010         case DBGCVAR_TYPE_HC_PHYS:
    7011         case DBGCVAR_TYPE_NUMBER:
    7012             *pf = pVar->u.u64Number != 0;
    7013             return VINF_SUCCESS;
    7014 
    7015         case DBGCVAR_TYPE_HC_FAR:
    7016         case DBGCVAR_TYPE_GC_FAR:
    7017         case DBGCVAR_TYPE_SYMBOL:
    7018         default:
    7019             return VERR_PARSE_INCORRECT_ARG_TYPE;
    7020     }
    7021 }
    7022 
    7023 
    7024 
    7025 
    7026 
    7027 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7028 //
    7029 //
    7030 //      V a r i a b l e   M a n i p u l a t i o n
    7031 //
    7032 //
    7033 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7034 
    7035 
    7036 
    7037 /** @todo move me!*/
    7038 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
    7039 {
    7040     if (pVar)
    7041     {
    7042         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    7043         pVar->u.GCFlat = GCFlat;
    7044         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    7045         pVar->u64Range  = 0;
    7046     }
    7047 }
    7048 
    7049 
    7050 /** @todo move me!*/
    7051 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
    7052 {
    7053     if (pVar)
    7054     {
    7055         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    7056         pVar->u.GCFlat = GCFlat;
    7057         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    7058         pVar->u64Range  = cb;
    7059     }
    7060 }
    7061 
    7062 
    7063 /** @todo move me!*/
    7064 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    7065 {
    7066     if (pVar)
    7067     {
    7068         if (pVar2)
    7069             *pVar = *pVar2;
    7070         else
    7071         {
    7072             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    7073             memset(&pVar->u, 0, sizeof(pVar->u));
    7074             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    7075             pVar->u64Range  = 0;
    7076         }
    7077     }
    7078 }
    7079 
    7080 
    7081 /** @todo move me!*/
    7082 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    7083 {
    7084     if (pVar)
    7085     {
    7086         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    7087         pVar->u64Range  = cb;
    7088     }
    7089 }
    7090 
    7091 
    7092 /** @todo move me!*/
    7093 static void dbgcVarSetNoRange(PDBGCVAR pVar)
    7094 {
    7095     if (pVar)
    7096     {
    7097         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    7098         pVar->u64Range  = 0;
    7099     }
    7100 }
    7101 
    7102 
    7103 /**
    7104  * Converts a DBGC variable to a DBGF address.
    7105  *
    7106  * @returns VBox status code.
    7107  * @param   pDbgc       The DBGC instance.
    7108  * @param   pVar        The variable.
    7109  * @param   pAddress    Where to store the address.
    7110  */
    7111 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    7112 {
    7113     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    7114     switch (pVar->enmType)
    7115     {
    7116         case DBGCVAR_TYPE_GC_FLAT:
    7117             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    7118             return VINF_SUCCESS;
    7119 
    7120         case DBGCVAR_TYPE_NUMBER:
    7121             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    7122             return VINF_SUCCESS;
    7123 
    7124         case DBGCVAR_TYPE_GC_FAR:
    7125             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    7126 
    7127         case DBGCVAR_TYPE_STRING:
    7128         case DBGCVAR_TYPE_SYMBOL:
    7129         {
    7130             DBGCVAR Var;
    7131             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    7132             if (VBOX_FAILURE(rc))
    7133                 return rc;
    7134             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    7135         }
    7136 
    7137         case DBGCVAR_TYPE_GC_PHYS:
    7138         case DBGCVAR_TYPE_HC_FLAT:
    7139         case DBGCVAR_TYPE_HC_FAR:
    7140         case DBGCVAR_TYPE_HC_PHYS:
    7141         default:
    7142             return VERR_PARSE_CONVERSION_FAILED;
    7143     }
    7144 }
    7145 
    7146 
    7147 
    7148 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7149 //
    7150 //
    7151 //      B r e a k p o i n t   M a n a g e m e n t
    7152 //
    7153 //
    7154 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7155 
    7156 
    7157 /**
    7158  * Adds a breakpoint to the DBGC breakpoint list.
    7159  */
    7160 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    7161 {
    7162     /*
    7163      * Check if it already exists.
    7164      */
    7165     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    7166     if (pBp)
    7167         return VERR_DBGC_BP_EXISTS;
    7168 
    7169     /*
    7170      * Add the breakpoint.
    7171      */
    7172     if (pszCmd)
    7173         pszCmd = RTStrStripL(pszCmd);
    7174     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    7175     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    7176     if (!pBp)
    7177         return VERR_NO_MEMORY;
    7178     if (cchCmd)
    7179         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    7180     else
    7181         pBp->szCmd[0] = '\0';
    7182     pBp->cchCmd = cchCmd;
    7183     pBp->iBp    = iBp;
    7184     pBp->pNext  = pDbgc->pFirstBp;
    7185     pDbgc->pFirstBp = pBp;
    7186 
    7187     return VINF_SUCCESS;
    7188 }
    7189 
    7190 /**
    7191  * Updates the a breakpoint.
    7192  *
    7193  * @returns VBox status code.
    7194  * @param   pDbgc       The DBGC instance.
    7195  * @param   iBp         The breakpoint to update.
    7196  * @param   pszCmd      The new command.
    7197  */
    7198 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    7199 {
    7200     /*
    7201      * Find the breakpoint.
    7202      */
    7203     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    7204     if (!pBp)
    7205         return VERR_DBGC_BP_NOT_FOUND;
    7206 
    7207     /*
    7208      * Do we need to reallocate?
    7209      */
    7210     if (pszCmd)
    7211         pszCmd = RTStrStripL(pszCmd);
    7212     if (!pszCmd || !*pszCmd)
    7213         pBp->szCmd[0] = '\0';
    7214     else
    7215     {
    7216         size_t cchCmd = strlen(pszCmd);
    7217         if (strlen(pBp->szCmd) >= cchCmd)
    7218         {
    7219             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    7220             pBp->cchCmd = cchCmd;
    7221         }
    7222         else
    7223         {
    7224             /*
    7225              * Yes, let's do it the simple way...
    7226              */
    7227             int rc = dbgcBpDelete(pDbgc, iBp);
    7228             AssertRC(rc);
    7229             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    7230         }
    7231     }
    7232     return VINF_SUCCESS;
    7233 }
    7234 
    7235 
    7236 /**
    7237  * Deletes a breakpoint.
    7238  *
    7239  * @returns VBox status code.
    7240  * @param   pDbgc       The DBGC instance.
    7241  * @param   iBp         The breakpoint to delete.
    7242  */
    7243 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    7244 {
    7245     /*
    7246      * Search thru the list, when found unlink and free it.
    7247      */
    7248     PDBGCBP pBpPrev = NULL;
    7249     PDBGCBP pBp = pDbgc->pFirstBp;
    7250     for (; pBp; pBp = pBp->pNext)
    7251     {
    7252         if (pBp->iBp == iBp)
    7253         {
    7254             if (pBpPrev)
    7255                 pBpPrev->pNext = pBp->pNext;
    7256             else
    7257                 pDbgc->pFirstBp = pBp->pNext;
    7258             RTMemFree(pBp);
    7259             return VINF_SUCCESS;
    7260         }
    7261         pBpPrev = pBp;
    7262     }
    7263 
    7264     return VERR_DBGC_BP_NOT_FOUND;
    7265 }
    7266 
    7267 
    7268 /**
    7269  * Get a breakpoint.
    7270  *
    7271  * @returns Pointer to the breakpoint.
    7272  * @returns NULL if the breakpoint wasn't found.
    7273  * @param   pDbgc       The DBGC instance.
    7274  * @param   iBp         The breakpoint to get.
    7275  */
    7276 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    7277 {
    7278     /*
    7279      * Enumerate the list.
    7280      */
    7281     PDBGCBP pBp = pDbgc->pFirstBp;
    7282     for (; pBp; pBp = pBp->pNext)
    7283         if (pBp->iBp == iBp)
    7284             return pBp;
    7285     return NULL;
    7286 }
    7287 
    7288 
    7289 /**
    7290  * Executes the command of a breakpoint.
    7291  *
    7292  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    7293  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    7294  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    7295  * @returns VBox status code from dbgcProcessCommand() other wise.
    7296  * @param   pDbgc       The DBGC instance.
    7297  * @param   iBp         The breakpoint to execute.
    7298  */
    7299 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    7300 {
    7301     /*
    7302      * Find the breakpoint.
    7303      */
    7304     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    7305     if (!pBp)
    7306         return VERR_DBGC_BP_NOT_FOUND;
    7307 
    7308     /*
    7309      * Anything to do?
    7310      */
    7311     if (!pBp->cchCmd)
    7312         return VINF_DBGC_BP_NO_COMMAND;
    7313 
    7314     /*
    7315      * Execute the command.
    7316      * This means copying it to the scratch buffer and process it as if it
    7317      * were user input. We must save and restore the state of the scratch buffer.
    7318      */
    7319     /* Save the scratch state. */
    7320     char       *pszScratch  = pDbgc->pszScratch;
    7321     unsigned    iArg        = pDbgc->iArg;
    7322 
    7323     /* Copy the command to the scratch buffer. */
    7324     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    7325     if (pBp->cchCmd >= cbScratch)
    7326         return VERR_BUFFER_OVERFLOW;
    7327     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    7328 
    7329     /* Execute the command. */
    7330     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    7331     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    7332 
    7333     /* Restore the scratch state. */
    7334     pDbgc->iArg         = iArg;
    7335     pDbgc->pszScratch   = pszScratch;
    7336 
    7337     return rc;
    7338 }
    7339 
    7340 
    7341 
    7342 
    7343 
    7344 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7345 //
    7346 //
    7347 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    7348 //
    7349 //
    7350 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    7351 
    7352 
    7353 
    7354 /**
    7355  * Prints any log lines from the log buffer.
    7356  *
    7357  * The caller must not call function this unless pDbgc->fLog is set.
    7358  *
    7359  * @returns VBox status. (output related)
    7360  * @param   pDbgc   Debugger console instance data.
    7361  */
    7362 static int dbgcProcessLog(PDBGC pDbgc)
    7363 {
    7364     /** @todo */
    7365     NOREF(pDbgc);
    7366     return 0;
    7367 }
    7368 
    7369 
    7370 
    7371 /**
    7372  * Handle input buffer overflow.
    7373  *
    7374  * Will read any available input looking for a '\n' to reset the buffer on.
    7375  *
    7376  * @returns VBox status.
    7377  * @param   pDbgc   Debugger console instance data.
    7378  */
    7379 static int dbgcInputOverflow(PDBGC pDbgc)
    7380 {
    7381     /*
    7382      * Assert overflow status and reset the input buffer.
    7383      */
    7384     if (!pDbgc->fInputOverflow)
    7385     {
    7386         pDbgc->fInputOverflow = true;
    7387         pDbgc->iRead = pDbgc->iWrite = 0;
    7388         pDbgc->cInputLines = 0;
    7389         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    7390     }
    7391 
    7392     /*
    7393      * Eat input till no more or there is a '\n'.
    7394      * When finding a '\n' we'll continue normal processing.
    7395      */
    7396     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    7397     {
    7398         size_t cbRead;
    7399         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    7400         if (VBOX_FAILURE(rc))
    7401             return rc;
    7402         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    7403         if (psz)
    7404         {
    7405             pDbgc->fInputOverflow = false;
    7406             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    7407             pDbgc->iWrite = (unsigned)cbRead;
    7408             pDbgc->cInputLines = 0;
    7409             break;
    7410         }
    7411     }
    7412 
    7413     return 0;
    7414 }
    7415 
    7416 
    7417 
    7418 /**
    7419  * Read input and do some preprocessing.
    7420  *
    7421  * @returns VBox status.
    7422  *          In addition to the iWrite and achInput, cInputLines is maintained.
    7423  *          In case of an input overflow the fInputOverflow flag will be set.
    7424  * @param   pDbgc   Debugger console instance data.
    7425  */
    7426 static int dbgcInputRead(PDBGC pDbgc)
    7427 {
    7428     /*
    7429      * We have ready input.
    7430      * Read it till we don't have any or we have a full input buffer.
    7431      */
    7432     int     rc = 0;
    7433     do
    7434     {
    7435         /*
    7436          * More available buffer space?
    7437          */
    7438         size_t cbLeft;
    7439         if (pDbgc->iWrite > pDbgc->iRead)
    7440             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    7441         else
    7442             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    7443         if (!cbLeft)
    7444         {
    7445             /* overflow? */
    7446             if (!pDbgc->cInputLines)
    7447                 rc = dbgcInputOverflow(pDbgc);
    7448             break;
    7449         }
    7450 
    7451         /*
    7452          * Read one char and interpret it.
    7453          */
    7454         char    achRead[128];
    7455         size_t  cbRead;
    7456         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    7457         if (VBOX_FAILURE(rc))
    7458             return rc;
    7459         char *psz = &achRead[0];
    7460         while (cbRead-- > 0)
    7461         {
    7462             char ch = *psz++;
    7463             switch (ch)
    7464             {
    7465                 /*
    7466                  * Ignore.
    7467                  */
    7468                 case '\0':
    7469                 case '\r':
    7470                 case '\a':
    7471                     break;
    7472 
    7473                 /*
    7474                  * Backspace.
    7475                  */
    7476                 case '\b':
    7477                     Log2(("DBGC: backspace\n"));
    7478                     if (pDbgc->iRead != pDbgc->iWrite)
    7479                     {
    7480                         unsigned iWriteUndo = pDbgc->iWrite;
    7481                         if (pDbgc->iWrite)
    7482                             pDbgc->iWrite--;
    7483                         else
    7484                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    7485 
    7486                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    7487                             pDbgc->iWrite = iWriteUndo;
    7488                     }
    7489                     break;
    7490 
    7491                 /*
    7492                  * Add char to buffer.
    7493                  */
    7494                 case '\t':
    7495                 case '\n':
    7496                 case ';':
    7497                     switch (ch)
    7498                     {
    7499                         case '\t': ch = ' '; break;
    7500                         case '\n': pDbgc->cInputLines++; break;
    7501                     }
    7502                 default:
    7503                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    7504                     pDbgc->achInput[pDbgc->iWrite] = ch;
    7505                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    7506                         pDbgc->iWrite = 0;
    7507                     break;
    7508             }
    7509         }
    7510 
    7511         /* Terminate it to make it easier to read in the debugger. */
    7512         pDbgc->achInput[pDbgc->iWrite] = '\0';
    7513     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    7514 
    7515     return rc;
    7516 }
    7517 
    7518 
    7519 /**
    7520  * Finds a builtin symbol.
    7521  * @returns Pointer to symbol descriptor on success.
    7522  * @returns NULL on failure.
    7523  * @param   pDbgc       The debug console instance.
    7524  * @param   pszSymbol   The symbol name.
    7525  */
    7526 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
    7527 {
    7528     for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)
    7529         if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
    7530             return &g_aSyms[iSym];
    7531 
    7532     /** @todo externally registered symbols. */
    7533     NOREF(pDbgc);
    7534     return NULL;
    7535 }
    7536 
    7537 
    7538 /**
    7539  * Resolves a symbol (or tries to do so at least).
    7540  *
    7541  * @returns 0 on success.
    7542  * @returns VBox status on failure.
    7543  * @param   pDbgc       The debug console instance.
    7544  * @param   pszSymbol   The symbol name.
    7545  * @param   enmType     The result type.
    7546  * @param   pResult     Where to store the result.
    7547  */
    7548 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    7549 {
    7550     /*
    7551      * Builtin?
    7552      */
    7553     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    7554     if (pSymDesc)
    7555     {
    7556         if (!pSymDesc->pfnGet)
    7557             return VERR_PARSE_WRITEONLY_SYMBOL;
    7558         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    7559     }
    7560 
    7561 
    7562     /*
    7563      * Ask PDM.
    7564      */
    7565     /** @todo resolve symbols using PDM. */
    7566 
    7567 
    7568     /*
    7569      * Ask the debug info manager.
    7570      */
    7571     DBGFSYMBOL Symbol;
    7572     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    7573     if (VBOX_SUCCESS(rc))
    7574     {
    7575         /*
    7576          * Default return is a flat gc address.
    7577          */
    7578         memset(pResult, 0,  sizeof(*pResult));
    7579         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    7580         pResult->u64Range     = Symbol.cb;
    7581         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    7582         pResult->u.GCFlat     = Symbol.Value;
    7583         DBGCVAR VarTmp;
    7584         switch (enmType)
    7585         {
    7586             /* nothing to do. */
    7587             case DBGCVAR_TYPE_GC_FLAT:
    7588             case DBGCVAR_TYPE_GC_FAR:
    7589             case DBGCVAR_TYPE_ANY:
    7590                 return VINF_SUCCESS;
    7591 
    7592             /* simply make it numeric. */
    7593             case DBGCVAR_TYPE_NUMBER:
    7594                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    7595                 pResult->u.u64Number = Symbol.Value;
    7596                 return VINF_SUCCESS;
    7597 
    7598             /* cast it. */
    7599 
    7600             case DBGCVAR_TYPE_GC_PHYS:
    7601                 VarTmp = *pResult;
    7602                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    7603 
    7604             case DBGCVAR_TYPE_HC_FAR:
    7605             case DBGCVAR_TYPE_HC_FLAT:
    7606                 VarTmp = *pResult;
    7607                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    7608 
    7609             case DBGCVAR_TYPE_HC_PHYS:
    7610                 VarTmp = *pResult;
    7611                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    7612 
    7613             default:
    7614                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    7615                 return VERR_INVALID_PARAMETER;
    7616         }
    7617     }
    7618 
    7619     return VERR_PARSE_NOT_IMPLEMENTED;
    7620 }
    7621 
    7622 
    7623 
    7624 /**
    7625  * Finds a routine.
    7626  *
    7627  * @returns Pointer to the command descriptor.
    7628  *          If the request was for an external command, the caller is responsible for
    7629  *          unlocking the external command list.
    7630  * @returns NULL if not found.
    7631  * @param   pDbgc       The debug console instance.
    7632  * @param   pachName    Pointer to the routine string (not terminated).
    7633  * @param   cchName     Length of the routine name.
    7634  * @param   fExternal   Whether or not the routine is external.
    7635  */
    7636 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
    7637 {
    7638     if (!fExternal)
    7639     {
    7640         /* emulation first, so commands can be overloaded (info ++). */
    7641         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    7642         unsigned cLeft = pDbgc->cEmulationCmds;
    7643         while (cLeft-- > 0)
    7644         {
    7645             if (    !strncmp(pachName, pCmd->pszCmd, cchName)
    7646                 &&  !pCmd->pszCmd[cchName])
    7647                 return pCmd;
    7648             pCmd++;
    7649         }
    7650 
    7651         for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
    7652         {
    7653             if (    !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
    7654                 &&  !g_aCmds[iCmd].pszCmd[cchName])
    7655                 return &g_aCmds[iCmd];
    7656         }
    7657     }
    7658     else
    7659     {
    7660         DBGCEXTCMDS_LOCK_RD();
    7661         for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
    7662         {
    7663             for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
    7664             {
    7665                 if (    !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
    7666                     &&  !pExtCmds->paCmds[iCmd].pszCmd[cchName])
    7667                     return &pExtCmds->paCmds[iCmd];
    7668             }
    7669         }
    7670         DBGCEXTCMDS_UNLOCK_RD();
    7671     }
    7672 
    7673     NOREF(pDbgc);
    7674     return NULL;
    7675 }
    7676 
    7677 
    7678 /**
    7679  * Searches for an operator descriptor which matches the start of
    7680  * the expression given us.
    7681  *
    7682  * @returns Pointer to the operator on success.
    7683  * @param   pDbgc           The debug console instance.
    7684  * @param   pszExpr         Pointer to the expression string which might start with an operator.
    7685  * @param   fPreferBinary   Whether to favour binary or unary operators.
    7686  *                          Caller must assert that it's the disired type! Both types will still
    7687  *                          be returned, this is only for resolving duplicates.
    7688  * @param   chPrev          The previous char. Some operators requires a blank in front of it.
    7689  */
    7690 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
    7691 {
    7692     PCDBGCOP    pOp = NULL;
    7693     for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)
    7694     {
    7695         if (     g_aOps[iOp].szName[0] == pszExpr[0]
    7696             &&  (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])
    7697             &&  (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))
    7698         {
    7699             /*
    7700              * Check that we don't mistake it for some other operator which have more chars.
    7701              */
    7702             unsigned j;
    7703             for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)
    7704                 if (    g_aOps[j].cchName > g_aOps[iOp].cchName
    7705                     &&  g_aOps[j].szName[0] == pszExpr[0]
    7706                     &&  (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])
    7707                     &&  (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )
    7708                     break;
    7709             if (j < ELEMENTS(g_aOps))
    7710                 continue;       /* we'll catch it later. (for theoretical +,++,+++ cases.) */
    7711             pOp = &g_aOps[iOp];
    7712 
    7713             /*
    7714              * Prefered type?
    7715              */
    7716             if (g_aOps[iOp].fBinary == fPreferBinary)
    7717                 break;
    7718         }
    7719     }
    7720 
    7721     if (pOp)
    7722         Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));
    7723     NOREF(pDbgc); NOREF(chPrev);
    7724     return pOp;
    7725 }
    7726 
    7727 
    7728 /**
    7729  * Initalizes g_bmOperatorChars.
    7730  */
    7731 static void dbgcInitOpCharBitMap(void)
    7732 {
    7733     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    7734     for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)
    7735         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    7736 }
    7737 
    7738 
    7739 /**
    7740  * Checks whether the character may be the start of an operator.
    7741  *
    7742  * @returns true/false.
    7743  * @param   ch      The character.
    7744  */
    7745 DECLINLINE(bool) dbgcIsOpChar(char ch)
    7746 {
    7747     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    7748 }
    7749 
    7750 
    7751 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    7752 {
    7753     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    7754 
    7755     /*
    7756      * Removing any quoting and escapings.
    7757      */
    7758     char ch = *pszExpr;
    7759     if (ch == '"' || ch == '\'' || ch == '`')
    7760     {
    7761         if (pszExpr[--cchExpr] != ch)
    7762             return VERR_PARSE_UNBALANCED_QUOTE;
    7763         cchExpr--;
    7764         pszExpr++;
    7765 
    7766         /** @todo string unescaping. */
    7767     }
    7768     pszExpr[cchExpr] = '\0';
    7769 
    7770     /*
    7771      * Make the argument.
    7772      */
    7773     pArg->pDesc         = NULL;
    7774     pArg->pNext         = NULL;
    7775     pArg->enmType       = DBGCVAR_TYPE_STRING;
    7776     pArg->u.pszString   = pszExpr;
    7777     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    7778     pArg->u64Range      = cchExpr;
    7779 
    7780     NOREF(pDbgc);
    7781     return 0;
    7782 }
    7783 
    7784 
    7785 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    7786 {
    7787     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    7788     /*
    7789      * Convert to number.
    7790      */
    7791     uint64_t    u64 = 0;
    7792     char        ch;
    7793     while ((ch = *pszExpr) != '\0')
    7794     {
    7795         uint64_t    u64Prev = u64;
    7796         unsigned    u = ch - '0';
    7797         if (u < 10 && u < uBase)
    7798             u64 = u64 * uBase + u;
    7799         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    7800             u64 = u64 * uBase + u;
    7801         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    7802             u64 = u64 * uBase + u;
    7803         else
    7804             return VERR_PARSE_INVALID_NUMBER;
    7805 
    7806         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    7807         if (u64Prev != u64 / uBase)
    7808             return VERR_PARSE_NUMBER_TOO_BIG;
    7809 
    7810         /* next */
    7811         pszExpr++;
    7812     }
    7813 
    7814     /*
    7815      * Initialize the argument.
    7816      */
    7817     pArg->pDesc         = NULL;
    7818     pArg->pNext         = NULL;
    7819     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    7820     pArg->u.u64Number   = u64;
    7821     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    7822     pArg->u64Range      = 0;
    7823 
    7824     return 0;
    7825 }
    7826 
    7827 
    7828 /**
    7829  * Match variable and variable descriptor, promoting the variable if necessary.
    7830  *
    7831  * @returns VBox status code.
    7832  * @param   pDbgc       Debug console instanace.
    7833  * @param   pVar        Variable.
    7834  * @param   pVarDesc    Variable descriptor.
    7835  */
    7836 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    7837 {
    7838     /*
    7839      * (If match or promoted to match, return, else break.)
    7840      */
    7841     switch (pVarDesc->enmCategory)
    7842     {
    7843         /*
    7844          * Anything goes
    7845          */
    7846         case DBGCVAR_CAT_ANY:
    7847             return VINF_SUCCESS;
    7848 
    7849         /*
    7850          * Pointer with and without range.
    7851          * We can try resolve strings and symbols as symbols and
    7852          * promote numbers to flat GC pointers.
    7853          */
    7854         case DBGCVAR_CAT_POINTER_NO_RANGE:
    7855             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    7856                 return VERR_PARSE_NO_RANGE_ALLOWED;
    7857             /* fallthru */
    7858         case DBGCVAR_CAT_POINTER:
    7859             switch (pVar->enmType)
    7860             {
    7861                 case DBGCVAR_TYPE_GC_FLAT:
    7862                 case DBGCVAR_TYPE_GC_FAR:
    7863                 case DBGCVAR_TYPE_GC_PHYS:
    7864                 case DBGCVAR_TYPE_HC_FLAT:
    7865                 case DBGCVAR_TYPE_HC_FAR:
    7866                 case DBGCVAR_TYPE_HC_PHYS:
    7867                     return VINF_SUCCESS;
    7868 
    7869                 case DBGCVAR_TYPE_SYMBOL:
    7870                 case DBGCVAR_TYPE_STRING:
    7871                 {
    7872                     DBGCVAR Var;
    7873                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    7874                     if (VBOX_SUCCESS(rc))
    7875                     {
    7876                         /* deal with range */
    7877                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    7878                         {
    7879                             Var.enmRangeType = pVar->enmRangeType;
    7880                             Var.u64Range = pVar->u64Range;
    7881                         }
    7882                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    7883                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    7884                         *pVar = Var;
    7885                         return rc;
    7886                     }
    7887                     break;
    7888                 }
    7889 
    7890                 case DBGCVAR_TYPE_NUMBER:
    7891                 {
    7892                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    7893                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    7894                     pVar->u.GCFlat = GCPtr;
    7895                     return VINF_SUCCESS;
    7896                 }
    7897 
    7898                 default:
    7899                     break;
    7900             }
    7901             break;
    7902 
    7903         /*
    7904          * GC pointer with and without range.
    7905          * We can try resolve strings and symbols as symbols and
    7906          * promote numbers to flat GC pointers.
    7907          */
    7908         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    7909             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    7910                 return VERR_PARSE_NO_RANGE_ALLOWED;
    7911             /* fallthru */
    7912         case DBGCVAR_CAT_GC_POINTER:
    7913             switch (pVar->enmType)
    7914             {
    7915                 case DBGCVAR_TYPE_GC_FLAT:
    7916                 case DBGCVAR_TYPE_GC_FAR:
    7917                 case DBGCVAR_TYPE_GC_PHYS:
    7918                     return VINF_SUCCESS;
    7919 
    7920                 case DBGCVAR_TYPE_HC_FLAT:
    7921                 case DBGCVAR_TYPE_HC_FAR:
    7922                 case DBGCVAR_TYPE_HC_PHYS:
    7923                     return VERR_PARSE_CONVERSION_FAILED;
    7924 
    7925                 case DBGCVAR_TYPE_SYMBOL:
    7926                 case DBGCVAR_TYPE_STRING:
    7927                 {
    7928                     DBGCVAR Var;
    7929                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    7930                     if (VBOX_SUCCESS(rc))
    7931                     {
    7932                         /* deal with range */
    7933                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    7934                         {
    7935                             Var.enmRangeType = pVar->enmRangeType;
    7936                             Var.u64Range = pVar->u64Range;
    7937                         }
    7938                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    7939                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    7940                         *pVar = Var;
    7941                         return rc;
    7942                     }
    7943                     break;
    7944                 }
    7945 
    7946                 case DBGCVAR_TYPE_NUMBER:
    7947                 {
    7948                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    7949                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    7950                     pVar->u.GCFlat = GCPtr;
    7951                     return VINF_SUCCESS;
    7952                 }
    7953 
    7954                 default:
    7955                     break;
    7956             }
    7957             break;
    7958 
    7959         /*
    7960          * Number with or without a range.
    7961          * Numbers can be resolved from symbols, but we cannot demote a pointer
    7962          * to a number.
    7963          */
    7964         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    7965             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    7966                 return VERR_PARSE_NO_RANGE_ALLOWED;
    7967             /* fallthru */
    7968         case DBGCVAR_CAT_NUMBER:
    7969             switch (pVar->enmType)
    7970             {
    7971                 case DBGCVAR_TYPE_NUMBER:
    7972                     return VINF_SUCCESS;
    7973 
    7974                 case DBGCVAR_TYPE_SYMBOL:
    7975                 case DBGCVAR_TYPE_STRING:
    7976                 {
    7977                     DBGCVAR Var;
    7978                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    7979                     if (VBOX_SUCCESS(rc))
    7980                     {
    7981                         *pVar = Var;
    7982                         return rc;
    7983                     }
    7984                     break;
    7985                 }
    7986                 default:
    7987                     break;
    7988             }
    7989             break;
    7990 
    7991         /*
    7992          * Strings can easily be made from symbols (and of course strings).
    7993          * We could consider reformatting the addresses and numbers into strings later...
    7994          */
    7995         case DBGCVAR_CAT_STRING:
    7996             switch (pVar->enmType)
    7997             {
    7998                 case DBGCVAR_TYPE_SYMBOL:
    7999                     pVar->enmType = DBGCVAR_TYPE_STRING;
    8000                     /* fallthru */
    8001                 case DBGCVAR_TYPE_STRING:
    8002                     return VINF_SUCCESS;
    8003                 default:
    8004                     break;
    8005             }
    8006             break;
    8007 
    8008         /*
    8009          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    8010          */
    8011         case DBGCVAR_CAT_SYMBOL:
    8012             switch (pVar->enmType)
    8013             {
    8014                 case DBGCVAR_TYPE_STRING:
    8015                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    8016                     /* fallthru */
    8017                 case DBGCVAR_TYPE_SYMBOL:
    8018                     return VINF_SUCCESS;
    8019                 default:
    8020                     break;
    8021             }
    8022             break;
    8023 
    8024         /*
    8025          * Anything else is illegal.
    8026          */
    8027         default:
    8028             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    8029             break;
    8030     }
    8031 
    8032     return VERR_PARSE_NO_ARGUMENT_MATCH;
    8033 }
    8034 
    8035 
    8036 /**
    8037  * Matches a set of variables with a description set.
    8038  *
    8039  * This is typically used for routine arguments before a call. The effects in
    8040  * addition to the validation, is that some variables might be propagated to
    8041  * other types in order to match the description. The following transformations
    8042  * are supported:
    8043  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    8044  *      - Number to a pointer.
    8045  *      - Pointer to a number.
    8046  * @returns 0 on success with paVars.
    8047  * @returns VBox error code for match errors.
    8048  */
    8049 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    8050                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    8051                                 PDBGCVAR paVars, unsigned cVars)
    8052 {
    8053     /*
    8054      * Just do basic min / max checks first.
    8055      */
    8056     if (cVars < cVarsMin)
    8057         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    8058     if (cVars > cVarsMax)
    8059         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    8060 
    8061     /*
    8062      * Match the descriptors and actual variables.
    8063      */
    8064     PCDBGCVARDESC   pPrevDesc = NULL;
    8065     unsigned        cCurDesc = 0;
    8066     unsigned        iVar = 0;
    8067     unsigned        iVarDesc = 0;
    8068     while (iVar < cVars)
    8069     {
    8070         /* walk the descriptors */
    8071         if (iVarDesc >= cVarDescs)
    8072             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    8073         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    8074                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    8075             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    8076         {
    8077             iVarDesc++;
    8078             if (iVarDesc >= cVarDescs)
    8079                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    8080             cCurDesc = 0;
    8081         }
    8082 
    8083         /*
    8084          * Skip thru optional arguments until we find something which matches
    8085          * or can easily be promoted to what the descriptor want.
    8086          */
    8087         for (;;)
    8088         {
    8089             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    8090             if (VBOX_SUCCESS(rc))
    8091             {
    8092                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    8093                 cCurDesc++;
    8094                 break;
    8095             }
    8096 
    8097             /* can we advance? */
    8098             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    8099                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    8100             if (++iVarDesc >= cVarDescs)
    8101                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    8102             cCurDesc = 0;
    8103         }
    8104 
    8105         /* next var */
    8106         iVar++;
    8107     }
    8108 
    8109     /*
    8110      * Check that the rest of the descriptors are optional.
    8111      */
    8112     while (iVarDesc < cVarDescs)
    8113     {
    8114         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    8115             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    8116         cCurDesc = 0;
    8117 
    8118         /* next */
    8119         iVarDesc++;
    8120     }
    8121 
    8122     return 0;
    8123 }
    8124 
    8125 
    8126 /**
    8127  * Evaluates one argument with respect to unary operators.
    8128  *
    8129  * @returns 0 on success. pResult contains the result.
    8130  * @returns VBox error code on parse or other evaluation error.
    8131  *
    8132  * @param   pDbgc       Debugger console instance data.
    8133  * @param   pszExpr     The expression string.
    8134  * @param   pResult     Where to store the result of the expression evaluation.
    8135  */
    8136 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    8137 {
    8138     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    8139 
    8140     /*
    8141      * The state of the expression is now such that it will start by zero or more
    8142      * unary operators and being followed by an expression of some kind.
    8143      * The expression is either plain or in parenthesis.
    8144      *
    8145      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    8146      * ASSUME: unary operators are all of equal precedence.
    8147      */
    8148     int         rc = 0;
    8149     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    8150     if (pOp)
    8151     {
    8152         /* binary operators means syntax error. */
    8153         if (pOp->fBinary)
    8154             return VERR_PARSE_UNEXPECTED_OPERATOR;
    8155 
    8156         /*
    8157          * If the next expression (the one following the unary operator) is in a
    8158          * parenthesis a full eval is needed. If not the unary eval will suffice.
    8159          */
    8160         /* calc and strip next expr. */
    8161         char *pszExpr2 = pszExpr + pOp->cchName;
    8162         while (isblank(*pszExpr2))
    8163             pszExpr2++;
    8164 
    8165         if (!*pszExpr2)
    8166             rc = VERR_PARSE_EMPTY_ARGUMENT;
    8167         else
    8168         {
    8169             DBGCVAR Arg;
    8170             if (*pszExpr2 == '(')
    8171                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    8172             else
    8173                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    8174             if (VBOX_SUCCESS(rc))
    8175                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    8176         }
    8177     }
    8178     else
    8179     {
    8180         /*
    8181          * Didn't find any operators, so it we have to check if this can be an
    8182          * function call before assuming numeric or string expression.
    8183          *
    8184          * (ASSUMPTIONS:)
    8185          * A function name only contains alphanumerical chars and it can not start
    8186          * with a numerical character.
    8187          * Immediately following the name is a parenthesis which must over
    8188          * the remaining part of the expression.
    8189          */
    8190         bool    fExternal = *pszExpr == '.';
    8191         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    8192         char   *pszFunEnd = NULL;
    8193         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    8194         {
    8195             pszFunEnd = pszExpr + 1;
    8196             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    8197                 pszFunEnd++;
    8198             if (*pszFunEnd != '(')
    8199                 pszFunEnd = NULL;
    8200         }
    8201 
    8202         if (pszFunEnd)
    8203         {
    8204             /*
    8205              * Ok, it's a function call.
    8206              */
    8207             if (fExternal)
    8208                 pszExpr++, cchExpr--;
    8209             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    8210             if (!pFun)
    8211                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    8212             if (!pFun->pResultDesc)
    8213                 return VERR_PARSE_NOT_A_FUNCTION;
    8214 
    8215             /*
    8216              * Parse the expression in parenthesis.
    8217              */
    8218             cchExpr -= pszFunEnd - pszExpr;
    8219             pszExpr = pszFunEnd;
    8220             /** @todo implement multiple arguments. */
    8221             DBGCVAR     Arg;
    8222             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    8223             if (!rc)
    8224             {
    8225                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    8226                 if (!rc)
    8227                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    8228             }
    8229             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    8230                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    8231         }
    8232         else
    8233         {
    8234             /*
    8235              * Didn't find any operators, so it must be a plain expression.
    8236              * This might be numeric or a string expression.
    8237              */
    8238             char ch  = pszExpr[0];
    8239             char ch2 = pszExpr[1];
    8240             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    8241                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    8242             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    8243                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    8244             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    8245                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    8246             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    8247             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    8248             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    8249             else
    8250             {
    8251                 /*
    8252                  * Hexadecimal number or a string?
    8253                  */
    8254                 char *psz = pszExpr;
    8255                 while (isxdigit(*psz))
    8256                     psz++;
    8257                 if (!*psz)
    8258                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    8259                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    8260                 {
    8261                     *psz = '\0';
    8262                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    8263                 }
    8264                 else
    8265                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    8266             }
    8267         }
    8268     }
    8269 
    8270     return rc;
    8271 }
    8272 
    8273 
    8274 /**
    8275  * Evaluates one argument.
    8276  *
    8277  * @returns 0 on success. pResult contains the result.
    8278  * @returns VBox error code on parse or other evaluation error.
    8279  *
    8280  * @param   pDbgc       Debugger console instance data.
    8281  * @param   pszExpr     The expression string.
    8282  * @param   pResult     Where to store the result of the expression evaluation.
    8283  */
    8284 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    8285 {
    8286     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    8287     /*
    8288      * First we need to remove blanks in both ends.
    8289      * ASSUMES: There is no quoting unless the entire expression is a string.
    8290      */
    8291 
    8292     /* stripping. */
    8293     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    8294         pszExpr[--cchExpr] = '\0';
    8295     while (isblank(*pszExpr))
    8296         pszExpr++, cchExpr--;
    8297     if (!*pszExpr)
    8298         return VERR_PARSE_EMPTY_ARGUMENT;
    8299 
    8300     /* it there is any kind of quoting in the expression, it's string meat. */
    8301     if (strpbrk(pszExpr, "\"'`"))
    8302         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    8303 
    8304     /*
    8305      * Check if there are any parenthesis which needs removing.
    8306      */
    8307     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    8308     {
    8309         do
    8310         {
    8311             unsigned cPar = 1;
    8312             char    *psz = pszExpr + 1;
    8313             char     ch;
    8314             while ((ch = *psz) != '\0')
    8315             {
    8316                 if (ch == '(')
    8317                     cPar++;
    8318                 else if (ch == ')')
    8319                 {
    8320                     if (cPar <= 0)
    8321                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    8322                     cPar--;
    8323                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    8324                         break;
    8325                 }
    8326                 /* next */
    8327                 psz++;
    8328             }
    8329             if (ch)
    8330                 break;
    8331 
    8332             /* remove the parenthesis. */
    8333             pszExpr++;
    8334             cchExpr -= 2;
    8335             pszExpr[cchExpr] = '\0';
    8336 
    8337             /* strip blanks. */
    8338             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    8339                 pszExpr[--cchExpr] = '\0';
    8340             while (isblank(*pszExpr))
    8341                 pszExpr++, cchExpr--;
    8342             if (!*pszExpr)
    8343                 return VERR_PARSE_EMPTY_ARGUMENT;
    8344         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    8345     }
    8346 
    8347     /* tabs to spaces. */
    8348     char *psz = pszExpr;
    8349     while ((psz = strchr(psz, '\t')) != NULL)
    8350         *psz = ' ';
    8351 
    8352     /*
    8353      * Now, we need to look for the binary operator with the lowest precedence.
    8354      *
    8355      * If there are no operators we're left with a simple expression which we
    8356      * evaluate with respect to unary operators
    8357      */
    8358     char       *pszOpSplit = NULL;
    8359     PCDBGCOP    pOpSplit = NULL;
    8360     unsigned    cBinaryOps = 0;
    8361     unsigned    cPar = 0;
    8362     char        ch;
    8363     char        chPrev = ' ';
    8364     bool        fBinary = false;
    8365     psz = pszExpr;
    8366 
    8367     while ((ch = *psz) != '\0')
    8368     {
    8369         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    8370         /*
    8371          * Parenthesis.
    8372          */
    8373         if (ch == '(')
    8374         {
    8375             cPar++;
    8376             fBinary = false;
    8377         }
    8378         else if (ch == ')')
    8379         {
    8380             if (cPar <= 0)
    8381                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    8382             cPar--;
    8383             fBinary = true;
    8384         }
    8385         /*
    8386          * Potential operator.
    8387          */
    8388         else if (cPar == 0 && !isblank(ch))
    8389         {
    8390             PCDBGCOP pOp = dbgcIsOpChar(ch)
    8391                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    8392                          : NULL;
    8393             if (pOp)
    8394             {
    8395                 /* If not the right kind of operator we've got a syntax error. */
    8396                 if (pOp->fBinary != fBinary)
    8397                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    8398 
    8399                 /*
    8400                  * Update the parse state and skip the operator.
    8401                  */
    8402                 if (!pOpSplit)
    8403                 {
    8404                     pOpSplit = pOp;
    8405                     pszOpSplit = psz;
    8406                     cBinaryOps = fBinary;
    8407                 }
    8408                 else if (fBinary)
    8409                 {
    8410                     cBinaryOps++;
    8411                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    8412                     {
    8413                         pOpSplit = pOp;
    8414                         pszOpSplit = psz;
    8415                     }
    8416                 }
    8417 
    8418                 psz += pOp->cchName - 1;
    8419                 fBinary = false;
    8420             }
    8421             else
    8422                 fBinary = true;
    8423         }
    8424 
    8425         /* next */
    8426         psz++;
    8427         chPrev = ch;
    8428     } /* parse loop. */
    8429 
    8430 
    8431     /*
    8432      * Either we found an operator to divide the expression by
    8433      * or we didn't find any. In the first case it's divide and
    8434      * conquer. In the latter it's a single expression which
    8435      * needs dealing with its unary operators if any.
    8436      */
    8437     int rc;
    8438     if (    cBinaryOps
    8439         &&  pOpSplit->fBinary)
    8440     {
    8441         /* process 1st sub expression. */
    8442         *pszOpSplit = '\0';
    8443         DBGCVAR     Arg1;
    8444         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    8445         if (VBOX_SUCCESS(rc))
    8446         {
    8447             /* process 2nd sub expression. */
    8448             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    8449             DBGCVAR     Arg2;
    8450             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    8451             if (VBOX_SUCCESS(rc))
    8452                 /* apply the operator. */
    8453                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    8454         }
    8455     }
    8456     else if (cBinaryOps)
    8457     {
    8458         /* process sub expression. */
    8459         pszOpSplit += pOpSplit->cchName;
    8460         DBGCVAR     Arg;
    8461         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    8462         if (VBOX_SUCCESS(rc))
    8463             /* apply the operator. */
    8464             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    8465     }
    8466     else
    8467         /* plain expression or using unary operators perhaps with paratheses. */
    8468         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    8469 
    8470     return rc;
    8471 }
    8472 
    8473 
    8474 /**
    8475  * Parses the arguments of one command.
    8476  *
    8477  * @returns 0 on success.
    8478  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    8479  * @param   pDbgc       Debugger console instance data.
    8480  * @param   pCmd        Pointer to the command descriptor.
    8481  * @param   pszArg      Pointer to the arguments to parse.
    8482  * @param   paArgs      Where to store the parsed arguments.
    8483  * @param   cArgs       Size of the paArgs array.
    8484  * @param   pcArgs      Where to store the number of arguments.
    8485  *                      In the event of an error this is used to store the index of the offending argument.
    8486  */
    8487 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    8488 {
    8489     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    8490     /*
    8491      * Check if we have any argument and if the command takes any.
    8492      */
    8493     *pcArgs = 0;
    8494     /* strip leading blanks. */
    8495     while (*pszArgs && isblank(*pszArgs))
    8496         pszArgs++;
    8497     if (!*pszArgs)
    8498     {
    8499         if (!pCmd->cArgsMin)
    8500             return 0;
    8501         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    8502     }
    8503     /** @todo fixme - foo() doesn't work. */
    8504     if (!pCmd->cArgsMax)
    8505         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    8506 
    8507     /*
    8508      * This is a hack, it's "temporary" and should go away "when" the parser is
    8509      * modified to match arguments while parsing.
    8510      */
    8511     if (    pCmd->cArgsMax == 1
    8512         &&  pCmd->cArgsMin == 1
    8513         &&  pCmd->cArgDescs == 1
    8514         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    8515         &&  cArgs >= 1)
    8516     {
    8517         *pcArgs = 1;
    8518         RTStrStripR(pszArgs);
    8519         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    8520     }
    8521 
    8522 
    8523     /*
    8524      * The parse loop.
    8525      */
    8526     PDBGCVAR        pArg0 = &paArgs[0];
    8527     PDBGCVAR        pArg = pArg0;
    8528     *pcArgs = 0;
    8529     do
    8530     {
    8531         /*
    8532          * Can we have another argument?
    8533          */
    8534         if (*pcArgs >= pCmd->cArgsMax)
    8535             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    8536         if (pArg >= &paArgs[cArgs])
    8537             return VERR_PARSE_ARGUMENT_OVERFLOW;
    8538 
    8539         /*
    8540          * Find the end of the argument.
    8541          */
    8542         int     cPar    = 0;
    8543         char    chQuote = '\0';
    8544         char   *pszEnd  = NULL;
    8545         char   *psz     = pszArgs;
    8546         char    ch;
    8547         bool    fBinary = false;
    8548         for (;;)
    8549         {
    8550             /*
    8551              * Check for the end.
    8552              */
    8553             if ((ch = *psz) == '\0')
    8554             {
    8555                 if (chQuote)
    8556                     return VERR_PARSE_UNBALANCED_QUOTE;
    8557                 if (cPar)
    8558                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    8559                 pszEnd = psz;
    8560                 break;
    8561             }
    8562             /*
    8563              * When quoted we ignore everything but the quotation char.
    8564              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    8565              */
    8566             else if (ch == '\'' || ch == '"' || ch == '`')
    8567             {
    8568                 if (chQuote)
    8569                 {
    8570                     /* end quote? */
    8571                     if (ch == chQuote)
    8572                     {
    8573                         if (psz[1] == ch)
    8574                             psz++;          /* skip the escaped quote char */
    8575                         else
    8576                             chQuote = '\0'; /* end of quoted string. */
    8577                     }
    8578                 }
    8579                 else
    8580                     chQuote = ch;           /* open new quote */
    8581             }
    8582             /*
    8583              * Parenthesis can of course be nested.
    8584              */
    8585             else if (ch == '(')
    8586             {
    8587                 cPar++;
    8588                 fBinary = false;
    8589             }
    8590             else if (ch == ')')
    8591             {
    8592                 if (!cPar)
    8593                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    8594                 cPar--;
    8595                 fBinary = true;
    8596             }
    8597             else if (!chQuote && !cPar)
    8598             {
    8599                 /*
    8600                  * Encountering blanks may mean the end of it all. A binary operator
    8601                  * will force continued parsing.
    8602                  */
    8603                 if (isblank(*psz))
    8604                 {
    8605                     pszEnd = psz++;         /* just in case. */
    8606                     while (isblank(*psz))
    8607                         psz++;
    8608                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    8609                     if (!pOp || pOp->fBinary != fBinary)
    8610                         break;              /* the end. */
    8611                     psz += pOp->cchName;
    8612                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    8613                         psz++;
    8614                     fBinary = false;
    8615                     continue;
    8616                 }
    8617 
    8618                 /*
    8619                  * Look for operators without a space up front.
    8620                  */
    8621                 if (dbgcIsOpChar(*psz))
    8622                 {
    8623                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    8624                     if (pOp)
    8625                     {
    8626                         if (pOp->fBinary != fBinary)
    8627                         {
    8628                             pszEnd = psz;
    8629                             /** @todo this is a parsing error really. */
    8630                             break;              /* the end. */
    8631                         }
    8632                         psz += pOp->cchName;
    8633                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    8634                             psz++;
    8635                         fBinary = false;
    8636                         continue;
    8637                     }
    8638                 }
    8639                 fBinary = true;
    8640             }
    8641 
    8642             /* next char */
    8643             psz++;
    8644         }
    8645         *pszEnd = '\0';
    8646         /* (psz = next char to process) */
    8647 
    8648         /*
    8649          * Parse and evaluate the argument.
    8650          */
    8651         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    8652         if (VBOX_FAILURE(rc))
    8653             return rc;
    8654 
    8655         /*
    8656          * Next.
    8657          */
    8658         pArg++;
    8659         (*pcArgs)++;
    8660         pszArgs = psz;
    8661         while (*pszArgs && isblank(*pszArgs))
    8662             pszArgs++;
    8663     } while (*pszArgs);
    8664 
    8665     /*
    8666      * Match the arguments.
    8667      */
    8668     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    8669 }
    8670 
    8671 
    8672 /**
    8673  * Process one command.
    8674  *
    8675  * @returns VBox status code. Any error indicates the termination of the console session.
    8676  * @param   pDbgc   Debugger console instance data.
    8677  * @param   pszCmd  Pointer to the command.
    8678  * @param   cchCmd  Length of the command.
    8679  */
    8680 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    8681 {
    8682     char *pszCmdInput = pszCmd;
    8683 
    8684     /*
    8685      * Skip blanks.
    8686      */
    8687     while (isblank(*pszCmd))
    8688         pszCmd++, cchCmd--;
    8689 
    8690     /* external command? */
    8691     bool fExternal = *pszCmd == '.';
    8692     if (fExternal)
    8693         pszCmd++, cchCmd--;
    8694 
    8695     /*
    8696      * Find arguments.
    8697      */
    8698     char *pszArgs = pszCmd;
    8699     while (isalnum(*pszArgs))
    8700         pszArgs++;
    8701     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    8702     {
    8703         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    8704         return 0;
    8705     }
    8706 
    8707     /*
    8708      * Find the command.
    8709      */
    8710     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    8711     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    8712         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    8713 
    8714     /*
    8715      * Parse arguments (if any).
    8716      */
    8717     unsigned    cArgs;
    8718     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    8719 
    8720     /*
    8721      * Execute the command.
    8722      */
    8723     if (!rc)
    8724     {
    8725         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    8726     }
    8727     else
    8728     {
    8729         /* report parse / eval error. */
    8730         switch (rc)
    8731         {
    8732             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    8733                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8734                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    8735                 break;
    8736             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    8737                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8738                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    8739                 break;
    8740             case VERR_PARSE_ARGUMENT_OVERFLOW:
    8741                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8742                     "Syntax error: Too many arguments.\n");
    8743                 break;
    8744             case VERR_PARSE_UNBALANCED_QUOTE:
    8745                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8746                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    8747                 break;
    8748             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    8749                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8750                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    8751                 break;
    8752             case VERR_PARSE_EMPTY_ARGUMENT:
    8753                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8754                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    8755                 break;
    8756             case VERR_PARSE_UNEXPECTED_OPERATOR:
    8757                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8758                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    8759                 break;
    8760             case VERR_PARSE_INVALID_NUMBER:
    8761                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8762                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    8763                 break;
    8764             case VERR_PARSE_NUMBER_TOO_BIG:
    8765                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8766                     "Error: Numeric overflow (argument %d).\n", cArgs);
    8767                 break;
    8768             case VERR_PARSE_INVALID_OPERATION:
    8769                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8770                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    8771                 break;
    8772             case VERR_PARSE_FUNCTION_NOT_FOUND:
    8773                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8774                     "Error: Function not found (argument %d).\n", cArgs);
    8775                 break;
    8776             case VERR_PARSE_NOT_A_FUNCTION:
    8777                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8778                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    8779                 break;
    8780             case VERR_PARSE_NO_MEMORY:
    8781                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8782                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    8783                 break;
    8784             case VERR_PARSE_INCORRECT_ARG_TYPE:
    8785                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8786                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    8787                 break;
    8788             case VERR_PARSE_VARIABLE_NOT_FOUND:
    8789                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8790                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    8791                 break;
    8792             case VERR_PARSE_CONVERSION_FAILED:
    8793                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8794                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    8795                 break;
    8796             case VERR_PARSE_NOT_IMPLEMENTED:
    8797                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8798                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    8799                 break;
    8800             case VERR_PARSE_BAD_RESULT_TYPE:
    8801                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8802                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    8803                 break;
    8804             case VERR_PARSE_WRITEONLY_SYMBOL:
    8805                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8806                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    8807                 break;
    8808 
    8809             default:
    8810                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    8811                     "Error: Unknown error %d!\n", rc);
    8812                 return rc;
    8813         }
    8814 
    8815         /*
    8816          * Parse errors are non fatal.
    8817          */
    8818         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    8819             rc = 0;
    8820     }
    8821 
    8822     return rc;
    8823 }
    8824 
    8825 
    8826 /**
    8827  * Process all commands current in the buffer.
    8828  *
    8829  * @returns VBox status code. Any error indicates the termination of the console session.
    8830  * @param   pDbgc   Debugger console instance data.
    8831  */
    8832 static int dbgcProcessCommands(PDBGC pDbgc)
    8833 {
    8834     int rc = 0;
    8835     while (pDbgc->cInputLines)
    8836     {
    8837         /*
    8838          * Empty the log buffer if we're hooking the log.
    8839          */
    8840         if (pDbgc->fLog)
    8841         {
    8842             rc = dbgcProcessLog(pDbgc);
    8843             if (VBOX_FAILURE(rc))
    8844                 break;
    8845         }
    8846 
    8847         if (pDbgc->iRead == pDbgc->iWrite)
    8848         {
    8849             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    8850             pDbgc->cInputLines = 0;
    8851             return 0;
    8852         }
    8853 
    8854         /*
    8855          * Copy the command to the parse buffer.
    8856          */
    8857         char    ch;
    8858         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    8859         char   *pszTrg = &pDbgc->achScratch[0];
    8860         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    8861         {
    8862             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    8863                 psz = &pDbgc->achInput[0];
    8864 
    8865             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    8866             {
    8867                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    8868                 pDbgc->cInputLines = 0;
    8869                 return 0;
    8870             }
    8871 
    8872             pszTrg++;
    8873         }
    8874         *pszTrg = '\0';
    8875 
    8876         /*
    8877          * Advance the buffer.
    8878          */
    8879         pDbgc->iRead = psz - &pDbgc->achInput[0];
    8880         if (ch == '\n')
    8881             pDbgc->cInputLines--;
    8882 
    8883         /*
    8884          * Parse and execute this command.
    8885          */
    8886         pDbgc->pszScratch = psz;
    8887         pDbgc->iArg       = 0;
    8888         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    8889         if (rc)
    8890             break;
    8891     }
    8892 
    8893     return rc;
    8894 }
    8895 
    8896 
    8897 /**
    8898  * Reads input, parses it and executes commands on '\n'.
    8899  *
    8900  * @returns VBox status.
    8901  * @param   pDbgc   Debugger console instance data.
    8902  */
    8903 static int dbgcProcessInput(PDBGC pDbgc)
    8904 {
    8905     /*
    8906      * We know there's input ready, so let's read it first.
    8907      */
    8908     int rc = dbgcInputRead(pDbgc);
    8909     if (VBOX_FAILURE(rc))
    8910         return rc;
    8911 
    8912     /*
    8913      * Now execute any ready commands.
    8914      */
    8915     if (pDbgc->cInputLines)
    8916     {
    8917         /** @todo this fReady stuff is broken. */
    8918         pDbgc->fReady = false;
    8919         rc = dbgcProcessCommands(pDbgc);
    8920         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    8921             pDbgc->fReady = true;
    8922         if (    VBOX_SUCCESS(rc)
    8923             &&  pDbgc->iRead == pDbgc->iWrite
    8924             &&  pDbgc->fReady)
    8925             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    8926     }
    8927 
    8928     return rc;
    8929 }
    8930 
    8931 
    8932 /**
    8933  * Gets the event context identifier string.
    8934  * @returns Read only string.
    8935  * @param   enmCtx          The context.
    8936  */
    8937 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    8938 {
    8939     switch (enmCtx)
    8940     {
    8941         case DBGFEVENTCTX_RAW:      return "raw";
    8942         case DBGFEVENTCTX_REM:      return "rem";
    8943         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    8944         case DBGFEVENTCTX_HYPER:    return "hyper";
    8945         case DBGFEVENTCTX_OTHER:    return "other";
    8946 
    8947         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    8948         default:
    8949             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    8950             return "!Unknown Event Ctx!";
    8951     }
    8952 }
    8953 
    8954 
    8955 /**
    8956  * Processes debugger events.
    8957  *
    8958  * @returns VBox status.
    8959  * @param   pDbgc   DBGC Instance data.
    8960  * @param   pEvent  Pointer to event data.
    8961  */
    8962 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    8963 {
    8964     /*
    8965      * Flush log first.
    8966      */
    8967     if (pDbgc->fLog)
    8968     {
    8969         int rc = dbgcProcessLog(pDbgc);
    8970         if (VBOX_FAILURE(rc))
    8971             return rc;
    8972     }
    8973 
    8974     /*
    8975      * Process the event.
    8976      */
    8977     pDbgc->pszScratch = &pDbgc->achInput[0];
    8978     pDbgc->iArg       = 0;
    8979     bool fPrintPrompt = true;
    8980     int rc = VINF_SUCCESS;
    8981     switch (pEvent->enmType)
    8982     {
    8983         /*
    8984          * The first part is events we have initiated with commands.
    8985          */
    8986         case DBGFEVENT_HALT_DONE:
    8987         {
    8988             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    8989                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    8990             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    8991             if (VBOX_SUCCESS(rc))
    8992                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    8993             break;
    8994         }
    8995 
    8996 
    8997         /*
    8998          * The second part is events which can occur at any time.
    8999          */
    9000         case DBGFEVENT_FATAL_ERROR:
    9001         {
    9002             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    9003                                          dbgcGetEventCtx(pEvent->enmCtx));
    9004             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    9005             if (VBOX_SUCCESS(rc))
    9006                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    9007             break;
    9008         }
    9009 
    9010         case DBGFEVENT_BREAKPOINT:
    9011         case DBGFEVENT_BREAKPOINT_HYPER:
    9012         {
    9013             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    9014             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    9015 
    9016             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    9017             switch (rc)
    9018             {
    9019                 case VERR_DBGC_BP_NOT_FOUND:
    9020                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    9021                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    9022                     break;
    9023 
    9024                 case VINF_DBGC_BP_NO_COMMAND:
    9025                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    9026                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    9027                     break;
    9028 
    9029                 case VINF_BUFFER_OVERFLOW:
    9030                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    9031                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    9032                     break;
    9033 
    9034                 default:
    9035                     break;
    9036             }
    9037             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    9038                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    9039             else
    9040                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    9041             break;
    9042         }
    9043 
    9044         case DBGFEVENT_STEPPED:
    9045         case DBGFEVENT_STEPPED_HYPER:
    9046         {
    9047             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    9048 
    9049             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    9050             if (VBOX_SUCCESS(rc))
    9051                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    9052             break;
    9053         }
    9054 
    9055         case DBGFEVENT_ASSERTION_HYPER:
    9056         {
    9057             pDbgc->fRegCtxGuest = false;
    9058 
    9059             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    9060                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    9061                                          "%s"
    9062                                          "%s"
    9063                                          "\n",
    9064                                          dbgcGetEventCtx(pEvent->enmCtx),
    9065                                          pEvent->u.Assert.pszMsg1,
    9066                                          pEvent->u.Assert.pszMsg2);
    9067             if (VBOX_SUCCESS(rc))
    9068                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    9069             break;
    9070         }
    9071 
    9072         case DBGFEVENT_DEV_STOP:
    9073         {
    9074             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    9075                                          "\n"
    9076                                          "dbgf event: DBGFSTOP (%s)\n"
    9077                                          "File:     %s\n"
    9078                                          "Line:     %d\n"
    9079                                          "Function: %s\n",
    9080                                          dbgcGetEventCtx(pEvent->enmCtx),
    9081                                          pEvent->u.Src.pszFile,
    9082                                          pEvent->u.Src.uLine,
    9083                                          pEvent->u.Src.pszFunction);
    9084             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    9085                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    9086                                          "Message:  %s\n",
    9087                                              pEvent->u.Src.pszMessage);
    9088             if (VBOX_SUCCESS(rc))
    9089                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    9090             break;
    9091         }
    9092 
    9093 
    9094         case DBGFEVENT_INVALID_COMMAND:
    9095         {
    9096             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    9097             fPrintPrompt = !pDbgc->fReady;
    9098             break;
    9099         }
    9100 
    9101         case DBGFEVENT_TERMINATING:
    9102         {
    9103             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    9104             rc = VERR_GENERAL_FAILURE;
    9105             break;
    9106         }
    9107 
    9108 
    9109         default:
    9110         {
    9111             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    9112             fPrintPrompt = !pDbgc->fReady;
    9113             break;
    9114         }
    9115     }
    9116 
    9117     /*
    9118      * Prompt, anyone?
    9119      */
    9120     if (fPrintPrompt && VBOX_SUCCESS(rc))
    9121     {
    9122         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    9123     }
    9124 
    9125     return rc;
    9126 }
    9127 
    9128 
    9129 
    9130 
    9131 
    9132 /**
    9133  * Make a console instance.
    9134  *
    9135  * This will not return until either an 'exit' command is issued or a error code
    9136  * indicating connection loss is encountered.
    9137  *
    9138  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    9139  * @returns The VBox status code causing the console termination.
    9140  *
    9141  * @param   pVM         VM Handle.
    9142  * @param   pBack       Pointer to the backend structure. This must contain
    9143  *                      a full set of function pointers to service the console.
    9144  * @param   fFlags      Reserved, must be zero.
    9145  * @remark  A forced termination of the console is easiest done by forcing the
    9146  *          callbacks to return fatal failures.
    9147  */
    9148 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    9149 {
    9150     /*
    9151      * Validate input.
    9152      */
    9153     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    9154     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    9155     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    9156 
    9157     /*
    9158      * Allocate and initialize instance data
    9159      */
    9160     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    9161     if (!pDbgc)
    9162         return VERR_NO_MEMORY;
    9163 
    9164     pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    9165     pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
    9166     pDbgc->CmdHlp.pfnPrintf     = dbgcHlpPrintf;
    9167     pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
    9168     pDbgc->CmdHlp.pfnVBoxError  = dbgcHlpVBoxError;
    9169     pDbgc->CmdHlp.pfnMemRead    = dbgcHlpMemRead;
    9170     pDbgc->CmdHlp.pfnMemWrite   = dbgcHlpMemWrite;
    9171     pDbgc->CmdHlp.pfnEval       = dbgcHlpEval;
    9172     pDbgc->CmdHlp.pfnExec       = dbgcHlpExec;
    9173     pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    9174     pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
    9175     pDbgc->pBack            = pBack;
    9176     pDbgc->pVM              = NULL;
    9177     pDbgc->pszEmulation     = "CodeView/WinDbg";
    9178     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    9179     pDbgc->cEmulationCmds   = RT_ELEMENTS(g_aCmdsCodeView);
    9180     //pDbgc->fLog             = false;
    9181     pDbgc->fRegCtxGuest     = true;
    9182     pDbgc->fRegTerse        = true;
    9183     //pDbgc->DisasmPos        = {0};
    9184     //pDbgc->SourcePos        = {0};
    9185     //pDbgc->DumpPos          = {0};
    9186     //pDbgc->cbDumpElement    = 0;
    9187     //pDbgc->cVars            = 0;
    9188     //pDbgc->paVars           = NULL;
    9189     //pDbgc->pFirstBp         = NULL;
    9190     //pDbgc->uInputZero       = 0;
    9191     //pDbgc->iRead            = 0;
    9192     //pDbgc->iWrite           = 0;
    9193     //pDbgc->cInputLines      = 0;
    9194     //pDbgc->fInputOverflow   = false;
    9195     pDbgc->fReady           = true;
    9196     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    9197     //pDbgc->iArg             = 0;
    9198     //pDbgc->rcOutput         = 0;
    9199 
    9200     dbgcInitOpCharBitMap();
    9201 
    9202     /*
    9203      * Print welcome message.
    9204      */
    9205     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    9206         "Welcome to the VirtualBox Debugger!\n");
    9207     if (VBOX_FAILURE(rc))
    9208         goto l_failure;
    9209 
    9210     /*
    9211      * Attach to the VM.
    9212      */
    9213     rc = DBGFR3Attach(pVM);
    9214     if (VBOX_FAILURE(rc))
    9215     {
    9216         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    9217         goto l_failure;
    9218     }
    9219     pDbgc->pVM = pVM;
    9220 
    9221     /*
    9222      * Print commandline and auto select result.
    9223      */
    9224     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    9225         "Current VM is %08x\n" /** @todo get and print the VM name! */
    9226         "VBoxDbg> ",
    9227         pDbgc->pVM);
    9228     if (VBOX_FAILURE(rc))
    9229         goto l_failure;
    9230 
    9231     /*
    9232      * Main Debugger Loop.
    9233      *
    9234      * This loop will either block on waiting for input or on waiting on
    9235      * debug events. If we're forwarding the log we cannot wait for long
    9236      * before we must flush the log.
    9237      */
    9238     for (rc = 0;;)
    9239     {
    9240         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    9241         {
    9242             /*
    9243              * Wait for a debug event.
    9244              */
    9245             PCDBGFEVENT pEvent;
    9246             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    9247             if (VBOX_SUCCESS(rc))
    9248             {
    9249                 rc = dbgcProcessEvent(pDbgc, pEvent);
    9250                 if (VBOX_FAILURE(rc))
    9251                     break;
    9252             }
    9253             else if (rc != VERR_TIMEOUT)
    9254                 break;
    9255 
    9256             /*
    9257              * Check for input.
    9258              */
    9259             if (pBack->pfnInput(pDbgc->pBack, 0))
    9260             {
    9261                 rc = dbgcProcessInput(pDbgc);
    9262                 if (VBOX_FAILURE(rc))
    9263                     break;
    9264             }
    9265         }
    9266         else
    9267         {
    9268             /*
    9269              * Wait for input. If Logging is enabled we'll only wait very briefly.
    9270              */
    9271             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    9272             {
    9273                 rc = dbgcProcessInput(pDbgc);
    9274                 if (VBOX_FAILURE(rc))
    9275                     break;
    9276             }
    9277         }
    9278 
    9279         /*
    9280          * Forward log output.
    9281          */
    9282         if (pDbgc->fLog)
    9283         {
    9284             rc = dbgcProcessLog(pDbgc);
    9285             if (VBOX_FAILURE(rc))
    9286                 break;
    9287         }
    9288     }
    9289 
    9290 
    9291 l_failure:
    9292     /*
    9293      * Cleanup console debugger session.
    9294      */
    9295     /* Disable log hook. */
    9296     if (pDbgc->fLog)
    9297     {
    9298 
    9299     }
    9300 
    9301     /* Detach from the VM. */
    9302     if (pDbgc->pVM)
    9303         DBGFR3Detach(pDbgc->pVM);
    9304 
    9305     /* finally, free the instance memory. */
    9306     RTMemFree(pDbgc);
    9307 
    9308     return rc;
    9309 }
    9310 
    9311 
    9312 
    9313 /**
    9314  * Register one or more external commands.
    9315  *
    9316  * @returns VBox status.
    9317  * @param   paCommands      Pointer to an array of command descriptors.
    9318  *                          The commands must be unique. It's not possible
    9319  *                          to register the same commands more than once.
    9320  * @param   cCommands       Number of commands.
    9321  */
    9322 DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    9323 {
    9324     /*
    9325      * Lock the list.
    9326      */
    9327     DBGCEXTCMDS_LOCK_WR();
    9328     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    9329     while (pCur)
    9330     {
    9331         if (paCommands == pCur->paCmds)
    9332         {
    9333             DBGCEXTCMDS_UNLOCK_WR();
    9334             AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
    9335             return VWRN_DBGC_ALREADY_REGISTERED;
    9336         }
    9337         pCur = pCur->pNext;
    9338     }
    9339 
    9340     /*
    9341      * Allocate new chunk.
    9342      */
    9343     int rc = 0;
    9344     pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
    9345     if (pCur)
    9346     {
    9347         pCur->cCmds  = cCommands;
    9348         pCur->paCmds = paCommands;
    9349         pCur->pNext = g_pExtCmdsHead;
    9350         g_pExtCmdsHead = pCur;
    9351     }
    9352     else
    9353         rc = VERR_NO_MEMORY;
    9354     DBGCEXTCMDS_UNLOCK_WR();
    9355 
    9356     return rc;
    9357 }
    9358 
    9359 
    9360 /**
    9361  * Deregister one or more external commands previously registered by
    9362  * DBGCRegisterCommands().
    9363  *
    9364  * @returns VBox status.
    9365  * @param   paCommands      Pointer to an array of command descriptors
    9366  *                          as given to DBGCRegisterCommands().
    9367  * @param   cCommands       Number of commands.
    9368  */
    9369 DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    9370 {
    9371     /*
    9372      * Lock the list.
    9373      */
    9374     DBGCEXTCMDS_LOCK_WR();
    9375     PDBGCEXTCMDS pPrev = NULL;
    9376     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    9377     while (pCur)
    9378     {
    9379         if (paCommands == pCur->paCmds)
    9380         {
    9381             if (pPrev)
    9382                 pPrev->pNext = pCur->pNext;
    9383             else
    9384                 g_pExtCmdsHead = pCur->pNext;
    9385             DBGCEXTCMDS_UNLOCK_WR();
    9386 
    9387             RTMemFree(pCur);
    9388             return VINF_SUCCESS;
    9389         }
    9390         pPrev = pCur;
    9391         pCur = pCur->pNext;
    9392     }
    9393     DBGCEXTCMDS_UNLOCK_WR();
    9394 
    9395     NOREF(cCommands);
    9396     return VERR_DBGC_COMMANDS_NOT_REGISTERED;
    9397 }
    9398 
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r5666 r5668  
    125125#include <stdio.h>
    126126
    127 /* to err.h! */
    128 #define VERR_DBGC_QUIT                          (-11999)
    129 #define VERR_PARSE_FIRST                        (-11000)
    130 #define VERR_PARSE_TOO_FEW_ARGUMENTS            (VERR_PARSE_FIRST - 0)
    131 #define VERR_PARSE_TOO_MANY_ARGUMENTS           (VERR_PARSE_FIRST - 1)
    132 #define VERR_PARSE_ARGUMENT_OVERFLOW            (VERR_PARSE_FIRST - 2)
    133 #define VERR_PARSE_ARGUMENT_TYPE_MISMATCH       (VERR_PARSE_FIRST - 3)
    134 #define VERR_PARSE_NO_RANGE_ALLOWED             (VERR_PARSE_FIRST - 4)
    135 #define VERR_PARSE_UNBALANCED_QUOTE             (VERR_PARSE_FIRST - 5)
    136 #define VERR_PARSE_UNBALANCED_PARENTHESIS       (VERR_PARSE_FIRST - 6)
    137 #define VERR_PARSE_EMPTY_ARGUMENT               (VERR_PARSE_FIRST - 7)
    138 #define VERR_PARSE_UNEXPECTED_OPERATOR          (VERR_PARSE_FIRST - 8)
    139 #define VERR_PARSE_INVALID_NUMBER               (VERR_PARSE_FIRST - 9)
    140 #define VERR_PARSE_NUMBER_TOO_BIG               (VERR_PARSE_FIRST - 10)
    141 #define VERR_PARSE_INVALID_OPERATION            (VERR_PARSE_FIRST - 11)
    142 #define VERR_PARSE_FUNCTION_NOT_FOUND           (VERR_PARSE_FIRST - 12)
    143 #define VERR_PARSE_NOT_A_FUNCTION               (VERR_PARSE_FIRST - 13)
    144 #define VERR_PARSE_NO_MEMORY                    (VERR_PARSE_FIRST - 14)
    145 #define VERR_PARSE_INCORRECT_ARG_TYPE           (VERR_PARSE_FIRST - 15)
    146 #define VERR_PARSE_VARIABLE_NOT_FOUND           (VERR_PARSE_FIRST - 16)
    147 #define VERR_PARSE_CONVERSION_FAILED            (VERR_PARSE_FIRST - 17)
    148 #define VERR_PARSE_NOT_IMPLEMENTED              (VERR_PARSE_FIRST - 18)
    149 #define VERR_PARSE_BAD_RESULT_TYPE              (VERR_PARSE_FIRST - 19)
    150 #define VERR_PARSE_WRITEONLY_SYMBOL             (VERR_PARSE_FIRST - 20)
    151 #define VERR_PARSE_NO_ARGUMENT_MATCH            (VERR_PARSE_FIRST - 21)
    152 #define VERR_PARSE_LAST                         (VERR_PARSE_FIRST - 30)
    153 
    154 #define VWRN_DBGC_CMD_PENDING                   12000
    155 #define VWRN_DBGC_ALREADY_REGISTERED            12001
    156 #define VERR_DBGC_COMMANDS_NOT_REGISTERED       (-12002)
    157 #define VERR_DBGC_BP_NOT_FOUND                  (-12003)
    158 #define VERR_DBGC_BP_EXISTS                     (-12004)
    159 #define VINF_DBGC_BP_NO_COMMAND                 12005
    160 
    161 
    162 
    163 /*******************************************************************************
    164 *   Defined Constants And Macros                                               *
    165 *******************************************************************************/
    166 /** Makes a DBGC variable type pair.
    167  * Typically used by binary operators. */
    168 #define BINARY_TYPE_PAIR(type1, type2)   (type1 | (type2 << 16))
    169 
    170 
    171 /*******************************************************************************
    172 *   Structures and Typedefs                                                    *
    173 *******************************************************************************/
    174 
    175 /**
    176  * Debugger console per breakpoint data.
    177  */
    178 typedef struct DBGCBP
    179 {
    180     /** Pointer to the next breakpoint in the list. */
    181     struct DBGCBP  *pNext;
    182     /** The breakpoint identifier. */
    183     RTUINT          iBp;
    184     /** The size of the command. */
    185     size_t          cchCmd;
    186     /** The command to execute when the breakpoint is hit. */
    187     char            szCmd[1];
    188 } DBGCBP;
    189 /** Pointer to a breakpoint. */
    190 typedef DBGCBP *PDBGCBP;
    191 
    192 
    193 /**
    194  * Named variable.
    195  *
    196  * Always allocated from heap in one signle block.
    197  */
    198 typedef struct DBGCNAMEDVAR
    199 {
    200     /** The variable. */
    201     DBGCVAR     Var;
    202     /** It's name. */
    203     char        szName[1];
    204 } DBGCNAMEDVAR;
    205 /** Pointer to named variable. */
    206 typedef DBGCNAMEDVAR *PDBGCNAMEDVAR;
    207 
    208 
    209 /**
    210  * Debugger console status
    211  */
    212 typedef enum DBGCSTATUS
    213 {
    214     /** Normal status, .*/
    215     DBGC_HALTED
    216 
    217 } DBGCSTATUS;
    218 
    219 
    220 /**
    221  * Debugger console instance data.
    222  */
    223 typedef struct DBGC
    224 {
    225     /** Command helpers. */
    226     DBGCCMDHLP          CmdHlp;
    227     /** Pointer to backend callback structure. */
    228     PDBGCBACK           pBack;
    229 
    230     /** Pointer to the current VM. */
    231     PVM                 pVM;
    232     /** The current debugger emulation. */
    233     const char         *pszEmulation;
    234     /** Pointer to the command and functions for the current debugger emulation. */
    235     PCDBGCCMD           paEmulationCmds;
    236     /** The number of commands paEmulationCmds points to. */
    237     unsigned            cEmulationCmds;
    238     /** Log indicator. (If set we're writing the log to the console.) */
    239     bool                fLog;
    240 
    241     /** Indicates whether we're in guest (true) or hypervisor (false) register context. */
    242     bool                fRegCtxGuest;
    243     /** Indicates whether the register are terse or sparse. */
    244     bool                fRegTerse;
    245 
    246     /** Current dissassembler position. */
    247     DBGCVAR             DisasmPos;
    248     /** Current source position. (flat GC) */
    249     DBGCVAR             SourcePos;
    250     /** Current memory dump position. */
    251     DBGCVAR             DumpPos;
    252     /** Size of the previous dump element. */
    253     unsigned            cbDumpElement;
    254 
    255     /** Number of variables in papVars. */
    256     unsigned            cVars;
    257     /** Array of global variables.
    258      * Global variables can be referenced using the $ operator and set
    259      * and unset using command with those names. */
    260     PDBGCNAMEDVAR      *papVars;
    261 
    262     /** The list of breakpoints. (singly linked) */
    263     PDBGCBP             pFirstBp;
    264 
    265     /** @name Parsing and Execution
    266      * @{ */
    267 
    268     /** Input buffer. */
    269     char                achInput[2048];
    270     /** To ease debugging. */
    271     unsigned            uInputZero;
    272     /** Write index in the input buffer. */
    273     unsigned            iWrite;
    274     /** Read index in the input buffer. */
    275     unsigned            iRead;
    276     /** The number of lines in the buffer. */
    277     unsigned            cInputLines;
    278     /** Indicates that we have a buffer overflow condition.
    279      * This means that input is ignored up to the next newline. */
    280     bool                fInputOverflow;
    281     /** Indicates whether or we're ready for input. */
    282     bool                fReady;
    283 
    284     /** Scratch buffer position. */
    285     char               *pszScratch;
    286     /** Scratch buffer. */
    287     char                achScratch[16384];
    288     /** Argument array position. */
    289     unsigned            iArg;
    290     /** Array of argument variables. */
    291     DBGCVAR             aArgs[100];
    292 
    293     /** rc from last dbgcHlpPrintfV(). */
    294     int                 rcOutput;
    295 
    296     /** @} */
    297 } DBGC;
    298 /** Pointer to debugger console instance data. */
    299 typedef DBGC *PDBGC;
    300 
    301 /** Converts a Command Helper pointer to a pointer to DBGC instance data. */
    302 #define DBGC_CMDHLP2DBGC(pCmdHlp)   ( (PDBGC)((uintptr_t)(pCmdHlp) - RT_OFFSETOF(DBGC, CmdHlp)) )
    303 
    304 
    305 /**
    306  * Chunk of external commands.
    307  */
    308 typedef struct DBGCEXTCMDS
    309 {
    310     /** Number of commands descriptors. */
    311     unsigned            cCmds;
    312     /** Pointer to array of command descriptors. */
    313     PCDBGCCMD           paCmds;
    314     /** Pointer to the next chunk. */
    315     struct DBGCEXTCMDS *pNext;
    316 } DBGCEXTCMDS;
    317 /** Pointer to chunk of external commands. */
    318 typedef DBGCEXTCMDS *PDBGCEXTCMDS;
    319 
    320 
    321 
    322 /**
    323  * Unary operator handler function.
    324  *
    325  * @returns 0 on success.
    326  * @returns VBox evaluation / parsing error code on failure.
    327  *          The caller does the bitching.
    328  * @param   pDbgc       Debugger console instance data.
    329  * @param   pArg        The argument.
    330  * @param   pResult     Where to store the result.
    331  */
    332 typedef DECLCALLBACK(int) FNDBGCOPUNARY(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    333 /** Pointer to a unary operator handler function. */
    334 typedef FNDBGCOPUNARY *PFNDBGCOPUNARY;
    335 
    336 
    337 /**
    338  * Binary operator handler function.
    339  *
    340  * @returns 0 on success.
    341  * @returns VBox evaluation / parsing error code on failure.
    342  *          The caller does the bitching.
    343  * @param   pDbgc       Debugger console instance data.
    344  * @param   pArg1       The first argument.
    345  * @param   pArg2       The 2nd argument.
    346  * @param   pResult     Where to store the result.
    347  */
    348 typedef DECLCALLBACK(int) FNDBGCOPBINARY(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    349 /** Pointer to a binary operator handler function. */
    350 typedef FNDBGCOPBINARY *PFNDBGCOPBINARY;
    351 
    352 
    353 /**
    354  * Operator descriptor.
    355  */
    356 typedef struct DBGCOP
    357 {
    358     /** Operator mnemonic. */
    359     char            szName[4];
    360     /** Length of name. */
    361     const unsigned  cchName;
    362     /** Whether or not this is a binary operator.
    363      * Unary operators are evaluated right-to-left while binary are left-to-right. */
    364     bool            fBinary;
    365     /** Precedence level. */
    366     unsigned        iPrecedence;
    367     /** Unary operator handler. */
    368     PFNDBGCOPUNARY  pfnHandlerUnary;
    369     /** Binary operator handler. */
    370     PFNDBGCOPBINARY pfnHandlerBinary;
    371     /** Operator description. */
    372     const char     *pszDescription;
    373 } DBGCOP;
    374 /** Pointer to an operator descriptor. */
    375 typedef DBGCOP *PDBGCOP;
    376 /** Pointer to a const operator descriptor. */
    377 typedef const DBGCOP *PCDBGCOP;
    378 
    379 
    380 
    381 /** Pointer to symbol descriptor. */
    382 typedef struct DBGCSYM *PDBGCSYM;
    383 /** Pointer to const symbol descriptor. */
    384 typedef const struct DBGCSYM *PCDBGCSYM;
    385 
    386 /**
    387  * Get builtin symbol.
    388  *
    389  * @returns 0 on success.
    390  * @returns VBox evaluation / parsing error code on failure.
    391  *          The caller does the bitching.
    392  * @param   pSymDesc    Pointer to the symbol descriptor.
    393  * @param   pCmdHlp     Pointer to the command callback structure.
    394  * @param   enmType     The result type.
    395  * @param   pResult     Where to store the result.
    396  */
    397 typedef DECLCALLBACK(int) FNDBGCSYMGET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    398 /** Pointer to get function for a builtin symbol. */
    399 typedef FNDBGCSYMGET *PFNDBGCSYMGET;
    400 
    401 /**
    402  * Set builtin symbol.
    403  *
    404  * @returns 0 on success.
    405  * @returns VBox evaluation / parsing error code on failure.
    406  *          The caller does the bitching.
    407  * @param   pSymDesc    Pointer to the symbol descriptor.
    408  * @param   pCmdHlp     Pointer to the command callback structure.
    409  * @param   pValue      The value to assign the symbol.
    410  */
    411 typedef DECLCALLBACK(int) FNDBGCSYMSET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    412 /** Pointer to set function for a builtin symbol. */
    413 typedef FNDBGCSYMSET *PFNDBGCSYMSET;
    414 
    415 
    416 /**
    417  * Symbol description (for builtin symbols).
    418  */
    419 typedef struct DBGCSYM
    420 {
    421     /** Symbol name. */
    422     const char     *pszName;
    423     /** Get function. */
    424     PFNDBGCSYMGET   pfnGet;
    425     /** Set function. (NULL if readonly) */
    426     PFNDBGCSYMSET   pfnSet;
    427     /** User data. */
    428     unsigned        uUser;
    429 } DBGCSYM;
     127#include "DBGCInternal.h"
    430128
    431129
Note: See TracChangeset for help on using the changeset viewer.

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