VirtualBox

Changeset 5673 in vbox for trunk


Ignore:
Timestamp:
Nov 11, 2007 5:28:37 AM (17 years ago)
Author:
vboxsync
Message:

Split out the operators.

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

Legend:

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

    r5671 r5673  
    341341int     dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress);
    342342
    343 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol);
     343int     dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
     344PCDBGCSYM   dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol);
     345PCDBGCOP    dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev);
     346
     347DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
     348DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
     349DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
     350DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    344351
    345352
     
    349356extern const DBGCCMD    g_aCmdsCodeView[];
    350357extern const unsigned   g_cCmdsCodeView;
     358extern const DBGCOP     g_aOps[];
     359extern const unsigned   g_cOps;
     360
    351361
    352362#endif
  • trunk/src/VBox/Debugger/DBGCOps.cpp

    r5672 r5673  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Operators.
    44 */
    55
     
    1515 * be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
    17 
    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 
    100 
    10117
    10218/*******************************************************************************
     
    13147*   Internal Functions                                                         *
    13248*******************************************************************************/
    133 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    134 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    135 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    136 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    137 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    138 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    139 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    140 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    141 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    142 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    143 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    144 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    145 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    146 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    147 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    148 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    149 
    15049static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    15150static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    15251static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    15352static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    154 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    155 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    156 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    157 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    15853static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    15954
     
    17570static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    17671
    177 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    178 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    179 
    180 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
    181 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    182 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
    183 
    18472
    18573/*******************************************************************************
    18674*   Global Variables                                                           *
    18775*******************************************************************************/
    188 /**
    189  * Pointer to head of the list of external commands.
    190  */
    191 static PDBGCEXTCMDS     g_pExtCmdsHead;     /** @todo rw protect g_pExtCmdsHead! */
    192 /** Locks the g_pExtCmdsHead list for reading. */
    193 #define DBGCEXTCMDS_LOCK_RD()       do { } while (0)
    194 /** Locks the g_pExtCmdsHead list for writing. */
    195 #define DBGCEXTCMDS_LOCK_WR()       do { } while (0)
    196 /** UnLocks the g_pExtCmdsHead list after reading. */
    197 #define DBGCEXTCMDS_UNLOCK_RD()     do { } while (0)
    198 /** UnLocks the g_pExtCmdsHead list after writing. */
    199 #define DBGCEXTCMDS_UNLOCK_WR()     do { } while (0)
    200 
    201 
    202 /** One argument of any kind. */
    203 static const DBGCVARDESC    g_aArgAny[] =
    204 {
    205     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    206     {  0,           1,          DBGCVAR_CAT_ANY,        0,                              "var",          "Any type of argument." },
    207 };
    208 
    209 /** Multiple string arguments (min 1). */
    210 static const DBGCVARDESC    g_aArgMultiStr[] =
    211 {
    212     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    213     {  1,           ~0,         DBGCVAR_CAT_STRING,     0,                              "strings",      "One or more strings." },
    214 };
    215 
    216 /** Filename string. */
    217 static const DBGCVARDESC    g_aArgFilename[] =
    218 {
    219     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    220     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    221 };
    222 
    223 
    224 /** 'help' arguments. */
    225 static const DBGCVARDESC    g_aArgHelp[] =
    226 {
    227     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    228     {  0,           ~0,         DBGCVAR_CAT_STRING,     0,                              "cmd/op",       "Zero or more command or operator names." },
    229 };
    230 
    231 
    232 /** 'info' arguments. */
    233 static const DBGCVARDESC    g_aArgInfo[] =
    234 {
    235     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    236     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "info",         "The name of the info to display." },
    237     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "args",         "String arguments to the handler." },
    238 };
    239 
    240 
    241 /** loadsyms arguments. */
    242 static const DBGCVARDESC    g_aArgLoadSyms[] =
    243 {
    244     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    245     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    246     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "delta",        "Delta to add to the loaded symbols. (optional)" },
    247     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "module name",  "Module name." },
    248     {  0,           1,          DBGCVAR_CAT_POINTER,    DBGCVD_FLAGS_DEP_PREV,          "module address", "Module address." },
    249     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "module size",  "The module size. (optional)" },
    250 };
    251 
    252 
    253 /** log arguments. */
    254 static const DBGCVARDESC    g_aArgLog[] =
    255 {
    256     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    257     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "groups",       "Group modifier string (quote it!)." }
    258 };
    259 
    260 
    261 /** logdest arguments. */
    262 static const DBGCVARDESC    g_aArgLogDest[] =
    263 {
    264     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    265     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "dests",        "Destination modifier string (quote it!)." }
    266 };
    267 
    268 
    269 /** logflags arguments. */
    270 static const DBGCVARDESC    g_aArgLogFlags[] =
    271 {
    272     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    273     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "flags",        "Flag modifier string (quote it!)." }
    274 };
    275 
    276 
    277 /** 'set' arguments */
    278 static const DBGCVARDESC    g_aArgSet[] =
    279 {
    280     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    281     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "var",          "Variable name." },
    282     {  1,           1,          DBGCVAR_CAT_ANY,        0,                              "value",        "Value to assign to the variable." },
    283 };
    284 
    285 
    286 
    287 
    288 
    289 /** Command descriptors for the basic commands. */
    290 static const DBGCCMD    g_aCmds[] =
    291 {
    292     /* pszCmd,      cArgsMin, cArgsMax, paArgDescs,         cArgDescs,                  pResultDesc,        fFlags,     pfnHandler          pszSyntax,          ....pszDescription */
    293     { "bye",        0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    294     { "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." },
    295     { "exit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    296     { "format",     1,        1,        &g_aArgAny[0],      ELEMENTS(g_aArgAny),        NULL,               0,          dbgcCmdFormat,      "",                     "Evaluates an expression and formats it." },
    297     { "harakiri",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdHarakiri,    "",                     "Kills debugger process." },
    298     { "help",       0,        ~0,       &g_aArgHelp[0],     ELEMENTS(g_aArgHelp),       NULL,               0,          dbgcCmdHelp,        "[cmd/op [..]]",        "Display help. For help about info items try 'info help'." },
    299     { "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'." },
    300     { "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." },
    301     { "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." },
    302     { "log",        1,        1,        &g_aArgLog[0],      ELEMENTS(g_aArgLog),        NULL,               0,          dbgcCmdLog,         "<group string>",       "Modifies the logging group settings (VBOX_LOG)" },
    303     { "logdest",    1,        1,        &g_aArgLogDest[0],  ELEMENTS(g_aArgLogDest),    NULL,               0,          dbgcCmdLogDest,     "<dest string>",        "Modifies the logging destination (VBOX_LOG_DEST)." },
    304     { "logflags",   1,        1,        &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags),   NULL,               0,          dbgcCmdLogFlags,    "<flags string>",       "Modifies the logging flags (VBOX_LOG_FLAGS)." },
    305     { "quit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    306     { "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." },
    307     { "set",        2,        2,        &g_aArgSet[0],      ELEMENTS(g_aArgSet),        NULL,               0,          dbgcCmdSet,         "<var> <value>",        "Sets a global variable." },
    308     { "showvars",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdShowVars,    "",                     "List all the defined variables." },
    309     { "stop",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdStop,        "",                     "Stop execution." },
    310     { "unset",      1,        ~0,       &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr),   NULL,               0,          dbgcCmdUnset,       "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
    311 };
    312 
    313 
    31476/** Operators. */
    315 static const DBGCOP g_aOps[] =
     77const DBGCOP g_aOps[] =
    31678{
    31779    /* 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). */
     
    344106};
    345107
    346 /** Bitmap where set bits indicates the characters the may start an operator name. */
    347 static uint32_t g_bmOperatorChars[256 / (4*8)];
    348 
    349 /** Register symbol uUser value.
    350  * @{
    351  */
    352 /** If set the register set is the hypervisor and not the guest one. */
    353 #define SYMREG_FLAGS_HYPER      RT_BIT(20)
    354 /** If set a far conversion of the value will use the high 16 bit for the selector.
    355  * If clear the low 16 bit will be used. */
    356 #define SYMREG_FLAGS_HIGH_SEL   RT_BIT(21)
    357 /** The shift value to calc the size of a register symbol from the uUser value. */
    358 #define SYMREG_SIZE_SHIFT       (24)
    359 /** Get the offset */
    360 #define SYMREG_OFFSET(uUser)    (uUser & ((1 << 20) - 1))
    361 /** Get the size. */
    362 #define SYMREG_SIZE(uUser)      ((uUser >> SYMREG_SIZE_SHIFT) & 0xff)
    363 /** 1 byte. */
    364 #define SYMREG_SIZE_1           ( 1 << SYMREG_SIZE_SHIFT)
    365 /** 2 byte. */
    366 #define SYMREG_SIZE_2           ( 2 << SYMREG_SIZE_SHIFT)
    367 /** 4 byte. */
    368 #define SYMREG_SIZE_4           ( 4 << SYMREG_SIZE_SHIFT)
    369 /** 6 byte. */
    370 #define SYMREG_SIZE_6           ( 6 << SYMREG_SIZE_SHIFT)
    371 /** 8 byte. */
    372 #define SYMREG_SIZE_8           ( 8 << SYMREG_SIZE_SHIFT)
    373 /** 12 byte. */
    374 #define SYMREG_SIZE_12          (12 << SYMREG_SIZE_SHIFT)
    375 /** 16 byte. */
    376 #define SYMREG_SIZE_16          (16 << SYMREG_SIZE_SHIFT)
    377 /** @} */
    378 
    379 /** Builtin Symbols.
    380  * ASSUMES little endian register representation!
    381  */
    382 static const DBGCSYM    g_aSyms[] =
    383 {
    384     { "eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 },
    385     { "ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 },
    386     { "al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 },
    387     { "ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 },
    388 
    389     { "ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 },
    390     { "bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 },
    391     { "bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 },
    392     { "bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 },
    393 
    394     { "ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 },
    395     { "cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 },
    396     { "cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 },
    397     { "ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 },
    398 
    399     { "edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 },
    400     { "dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 },
    401     { "dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 },
    402     { "dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 },
    403 
    404     { "edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 },
    405     { "di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 },
    406 
    407     { "esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 },
    408     { "si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 },
    409 
    410     { "ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 },
    411     { "bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 },
    412 
    413     { "esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 },
    414     { "sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 },
    415 
    416     { "eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 },
    417     { "ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 },
    418 
    419     { "efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    420     { "eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    421     { "fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    422     { "flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    423 
    424     { "cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 },
    425     { "ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 },
    426     { "es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 },
    427     { "fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 },
    428     { "gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 },
    429     { "ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 },
    430 
    431     { "cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 },
    432     { "cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 },
    433     { "cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 },
    434     { "cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 },
    435 
    436     { "tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 },
    437     { "ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 },
    438 
    439     { "gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 },
    440     { "gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 },
    441     { "gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 },
    442 
    443     { "idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 },
    444     { "idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 },
    445     { "idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 },
    446 
    447     /* hypervisor */
    448 
    449     {".eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    450     {".ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    451     {".al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    452     {".ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    453 
    454     {".ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    455     {".bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    456     {".bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    457     {".bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    458 
    459     {".ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    460     {".cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    461     {".cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    462     {".ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    463 
    464     {".edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    465     {".dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    466     {".dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    467     {".dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    468 
    469     {".edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    470     {".di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    471 
    472     {".esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    473     {".si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    474 
    475     {".ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    476     {".bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    477 
    478     {".esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    479     {".sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    480 
    481     {".eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    482     {".ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    483 
    484     {".efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    485     {".eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    486     {".fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    487     {".flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    488 
    489     {".cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    490     {".ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    491     {".es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    492     {".fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    493     {".gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    494     {".ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    495 
    496     {".cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    497     {".cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    498     {".cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    499     {".cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    500 
    501     {".tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    502     {".ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    503 
    504     {".gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    505     {".gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    506     {".gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    507 
    508     {".idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    509     {".idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    510     {".idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    511 
    512 };
    513 
    514 
    515 /**
    516  * Prints full command help.
    517  */
    518 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal)
    519 {
    520     int rc;
    521 
    522     /* the command */
    523     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    524                             "%s%-*s %-30s %s",
    525                             fExternal ? "." : "",
    526                             fExternal ? 10 : 11,
    527                             pCmd->pszCmd,
    528                             pCmd->pszSyntax,
    529                             pCmd->pszDescription);
    530     if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax)
    531         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n");
    532     else if (pCmd->cArgsMin == pCmd->cArgsMax)
    533         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin);
    534     else if (pCmd->cArgsMax == ~0U)
    535         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin);
    536     else
    537         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax);
    538 
    539     /* argument descriptions. */
    540     for (unsigned i = 0; i < pCmd->cArgDescs; i++)
    541     {
    542         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    543                                 "    %-12s %s",
    544                                 pCmd->paArgDescs[i].pszName,
    545                                 pCmd->paArgDescs[i].pszDescription);
    546         if (!pCmd->paArgDescs[i].cTimesMin)
    547         {
    548             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    549                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n");
    550             else
    551                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax);
    552         }
    553         else
    554         {
    555             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    556                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin);
    557             else
    558                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
    559         }
    560     }
    561     return rc;
    562 }
    563 
    564 
    565 /**
    566  * The 'help' command.
    567  *
    568  * @returns VBox status.
    569  * @param   pCmd        Pointer to the command descriptor (as registered).
    570  * @param   pCmdHlp     Pointer to command helper functions.
    571  * @param   pVM         Pointer to the current VM (if any).
    572  * @param   paArgs      Pointer to (readonly) array of arguments.
    573  * @param   cArgs       Number of arguments in the array.
    574  */
    575 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    576 {
    577     PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    578     int         rc = VINF_SUCCESS;
    579     unsigned    i;
    580 
    581     if (!cArgs)
    582     {
    583         /*
    584          * All the stuff.
    585          */
    586         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    587                                 "VirtualBox Debugger\n"
    588                                 "-------------------\n"
    589                                 "\n"
    590                                 "Commands and Functions:\n");
    591         for (i = 0; i < ELEMENTS(g_aCmds); i++)
    592             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    593                                     "%-11s %-30s %s\n",
    594                                     g_aCmds[i].pszCmd,
    595                                     g_aCmds[i].pszSyntax,
    596                                     g_aCmds[i].pszDescription);
    597         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    598                                 "\n"
    599                                 "Emulation: %s\n", pDbgc->pszEmulation);
    600         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    601         for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++)
    602             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    603                                     "%-11s %-30s %s\n",
    604                                     pCmd->pszCmd,
    605                                     pCmd->pszSyntax,
    606                                     pCmd->pszDescription);
    607 
    608         if (g_pExtCmdsHead)
    609         {
    610             DBGCEXTCMDS_LOCK_RD();
    611             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    612                                     "\n"
    613                                     "External Commands and Functions:\n");
    614             for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    615                 for (i = 0; i < pExtCmd->cCmds; i++)
    616                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    617                                             ".%-10s %-30s %s\n",
    618                                             pExtCmd->paCmds[i].pszCmd,
    619                                             pExtCmd->paCmds[i].pszSyntax,
    620                                             pExtCmd->paCmds[i].pszDescription);
    621             DBGCEXTCMDS_UNLOCK_RD();
    622         }
    623 
    624         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    625                                 "\n"
    626                                 "Operators:\n");
    627         unsigned iPrecedence = 0;
    628         unsigned cLeft = ELEMENTS(g_aOps);
    629         while (cLeft > 0)
    630         {
    631             for (i = 0; i < ELEMENTS(g_aOps); i++)
    632                 if (g_aOps[i].iPrecedence == iPrecedence)
    633                 {
    634                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    635                                             "%-10s  %s  %s\n",
    636                                             g_aOps[i].szName,
    637                                             g_aOps[i].fBinary ? "Binary" : "Unary ",
    638                                             g_aOps[i].pszDescription);
    639                     cLeft--;
    640                 }
    641             iPrecedence++;
    642         }
    643     }
    644     else
    645     {
    646         /*
    647          * Search for the arguments (strings).
    648          */
    649         for (unsigned iArg = 0; iArg < cArgs; iArg++)
    650         {
    651             Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);
    652             bool fFound = false;
    653 
    654             /* lookup in the emulation command list first */
    655             for (i = 0; i < pDbgc->cEmulationCmds; i++)
    656                 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString))
    657                 {
    658                     rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);
    659                     fFound = true;
    660                     break;
    661                 }
    662 
    663             /* lookup in the command list (even when found in the emulation) */
    664             for (i = 0; i < ELEMENTS(g_aCmds); i++)
    665                 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString))
    666                 {
    667                     rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);
    668                     fFound = true;
    669                     break;
    670                 }
    671 
    672            /* external commands */
    673            if (     !fFound
    674                &&   g_pExtCmdsHead
    675                &&   paArgs[iArg].u.pszString[0] == '.')
    676            {
    677                DBGCEXTCMDS_LOCK_RD();
    678                for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    679                    for (i = 0; i < pExtCmd->cCmds; i++)
    680                        if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1))
    681                        {
    682                            rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true);
    683                            fFound = true;
    684                            break;
    685                        }
    686                DBGCEXTCMDS_UNLOCK_RD();
    687            }
    688 
    689            /* operators */
    690            if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
    691            {
    692                for (i = 0; i < ELEMENTS(g_aOps); i++)
    693                    if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))
    694                    {
    695                        rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    696                                                "%-10s  %s  %s\n",
    697                                                g_aOps[i].szName,
    698                                                g_aOps[i].fBinary ? "Binary" : "Unary ",
    699                                                g_aOps[i].pszDescription);
    700                        fFound = true;
    701                        break;
    702                    }
    703            }
    704 
    705            /* found? */
    706            if (!fFound)
    707                rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    708                                        "error: '%s' was not found!\n",
    709                                        paArgs[iArg].u.pszString);
    710         } /* foreach argument */
    711     }
    712 
    713     NOREF(pCmd);
    714     NOREF(pVM);
    715     NOREF(pResult);
    716     return rc;
    717 }
    718 
    719 
    720 /**
    721  * The 'quit', 'exit' and 'bye' commands.
    722  *
    723  * @returns VBox status.
    724  * @param   pCmd        Pointer to the command descriptor (as registered).
    725  * @param   pCmdHlp     Pointer to command helper functions.
    726  * @param   pVM         Pointer to the current VM (if any).
    727  * @param   paArgs      Pointer to (readonly) array of arguments.
    728  * @param   cArgs       Number of arguments in the array.
    729  */
    730 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    731 {
    732     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
    733     NOREF(pCmd);
    734     NOREF(pVM);
    735     NOREF(paArgs);
    736     NOREF(cArgs);
    737     NOREF(pResult);
    738     return VERR_DBGC_QUIT;
    739 }
    740 
    741 
    742 /**
    743  * The 'stop' command.
    744  *
    745  * @returns VBox status.
    746  * @param   pCmd        Pointer to the command descriptor (as registered).
    747  * @param   pCmdHlp     Pointer to command helper functions.
    748  * @param   pVM         Pointer to the current VM (if any).
    749  * @param   paArgs      Pointer to (readonly) array of arguments.
    750  * @param   cArgs       Number of arguments in the array.
    751  */
    752 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    753 {
    754     /*
    755      * Check if the VM is halted or not before trying to halt it.
    756      */
    757     int rc;
    758     if (DBGFR3IsHalted(pVM))
    759         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
    760     else
    761     {
    762         rc = DBGFR3Halt(pVM);
    763         if (VBOX_SUCCESS(rc))
    764             rc = VWRN_DBGC_CMD_PENDING;
    765         else
    766             rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
    767     }
    768 
    769     NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    770     return rc;
    771 }
    772 
    773 
    774 /**
    775  * The 'echo' command.
    776  *
    777  * @returns VBox status.
    778  * @param   pCmd        Pointer to the command descriptor (as registered).
    779  * @param   pCmdHlp     Pointer to command helper functions.
    780  * @param   pVM         Pointer to the current VM (if any).
    781  * @param   paArgs      Pointer to (readonly) array of arguments.
    782  * @param   cArgs       Number of arguments in the array.
    783  */
    784 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    785 {
    786     /*
    787      * Loop thru the arguments and print them with one space between.
    788      */
    789     int rc = 0;
    790     for (unsigned i = 0; i < cArgs; i++)
    791     {
    792         if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
    793             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
    794         else
    795             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
    796         if (VBOX_FAILURE(rc))
    797             return rc;
    798     }
    799     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    800     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    801 }
    802 
    803 
    804 /**
    805  * The 'runscript' command.
    806  *
    807  * @returns VBox status.
    808  * @param   pCmd        Pointer to the command descriptor (as registered).
    809  * @param   pCmdHlp     Pointer to command helper functions.
    810  * @param   pVM         Pointer to the current VM (if any).
    811  * @param   paArgs      Pointer to (readonly) array of arguments.
    812  * @param   cArgs       Number of arguments in the array.
    813  */
    814 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    815 {
    816     /* check that the parser did what it's supposed to do. */
    817     if (    cArgs != 1
    818         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    819         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
    820 
    821     /*
    822      * Try open the script.
    823      */
    824     const char *pszFilename = paArgs[0].u.pszString;
    825     FILE *pFile = fopen(pszFilename, "r");
    826     if (!pFile)
    827         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
    828 
    829     /*
    830      * Execute it line by line.
    831      */
    832     int rc = 0;
    833     unsigned iLine = 0;
    834     char szLine[8192];
    835     while (fgets(szLine, sizeof(szLine), pFile))
    836     {
    837         /* check that the line isn't too long. */
    838         char *pszEnd = strchr(szLine, '\0');
    839         if (pszEnd == &szLine[sizeof(szLine) - 1])
    840         {
    841             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
    842             break;
    843         }
    844         iLine++;
    845 
    846         /* strip leading blanks and check for comment / blank line. */
    847         char *psz = RTStrStripL(szLine);
    848         if (    *psz == '\0'
    849             ||  *psz == '\n'
    850             ||  *psz == '#')
    851             continue;
    852 
    853         /* strip trailing blanks and check for empty line (\r case). */
    854         while (     pszEnd > psz
    855                &&   isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */
    856             *--pszEnd = '\0';
    857 
    858         /** @todo check for Control-C / Cancel at this point... */
    859 
    860         /*
    861          * Execute the command.
    862          *
    863          * This is a bit wasteful with scratch space btw., can fix it later.
    864          * The whole return code crap should be fixed too, so that it's possible
    865          * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and
    866          * more importantly why it failed.
    867          */
    868         rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
    869         if (VBOX_FAILURE(rc))
    870         {
    871             if (rc == VERR_BUFFER_OVERFLOW)
    872                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
    873             break;
    874         }
    875         if (rc == VWRN_DBGC_CMD_PENDING)
    876         {
    877             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
    878             break;
    879         }
    880     }
    881 
    882     fclose(pFile);
    883 
    884     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    885     return rc;
    886 }
    887 
    888 
    889 /**
    890  * Print formatted string.
    891  *
    892  * @param   pHlp        Pointer to this structure.
    893  * @param   pszFormat   The format string.
    894  * @param   ...         Arguments.
    895  */
    896 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
    897 {
    898     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    899     va_list args;
    900     va_start(args,  pszFormat);
    901     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    902     va_end(args);
    903 }
    904 
    905 
    906 /**
    907  * Print formatted string.
    908  *
    909  * @param   pHlp        Pointer to this structure.
    910  * @param   pszFormat   The format string.
    911  * @param   args        Argument list.
    912  */
    913 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
    914 {
    915     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    916     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    917 }
    918 
    919 
    920 /**
    921  * The 'info' command.
    922  *
    923  * @returns VBox status.
    924  * @param   pCmd        Pointer to the command descriptor (as registered).
    925  * @param   pCmdHlp     Pointer to command helper functions.
    926  * @param   pVM         Pointer to the current VM (if any).
    927  * @param   paArgs      Pointer to (readonly) array of arguments.
    928  * @param   cArgs       Number of arguments in the array.
    929  */
    930 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    931 {
    932     /*
    933      * Validate input.
    934      */
    935     if (    cArgs < 1
    936         ||  cArgs > 2
    937         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING
    938         ||  paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
    939         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
    940     if (!pVM)
    941         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    942 
    943     /*
    944      * Dump it.
    945      */
    946     struct
    947     {
    948         DBGFINFOHLP Hlp;
    949         PDBGCCMDHLP pCmdHlp;
    950     } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
    951     int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
    952     if (VBOX_FAILURE(rc))
    953         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
    954 
    955     NOREF(pCmd); NOREF(pResult);
    956     return 0;
    957 }
    958 
    959 
    960 /**
    961  * The 'log' command.
    962  *
    963  * @returns VBox status.
    964  * @param   pCmd        Pointer to the command descriptor (as registered).
    965  * @param   pCmdHlp     Pointer to command helper functions.
    966  * @param   pVM         Pointer to the current VM (if any).
    967  * @param   paArgs      Pointer to (readonly) array of arguments.
    968  * @param   cArgs       Number of arguments in the array.
    969  */
    970 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    971 {
    972     int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
    973     if (VBOX_SUCCESS(rc))
    974         return VINF_SUCCESS;
    975     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    976     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    977 }
    978 
    979 
    980 /**
    981  * The 'logdest' command.
    982  *
    983  * @returns VBox status.
    984  * @param   pCmd        Pointer to the command descriptor (as registered).
    985  * @param   pCmdHlp     Pointer to command helper functions.
    986  * @param   pVM         Pointer to the current VM (if any).
    987  * @param   paArgs      Pointer to (readonly) array of arguments.
    988  * @param   cArgs       Number of arguments in the array.
    989  */
    990 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    991 {
    992     int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
    993     if (VBOX_SUCCESS(rc))
    994         return VINF_SUCCESS;
    995     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    996     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    997 }
    998 
    999 
    1000 /**
    1001  * The 'logflags' command.
    1002  *
    1003  * @returns VBox status.
    1004  * @param   pCmd        Pointer to the command descriptor (as registered).
    1005  * @param   pCmdHlp     Pointer to command helper functions.
    1006  * @param   pVM         Pointer to the current VM (if any).
    1007  * @param   paArgs      Pointer to (readonly) array of arguments.
    1008  * @param   cArgs       Number of arguments in the array.
    1009  */
    1010 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1011 {
    1012     int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
    1013     if (VBOX_SUCCESS(rc))
    1014         return VINF_SUCCESS;
    1015     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    1016     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    1017 }
    1018 
    1019 
    1020 /**
    1021  * The 'format' command.
    1022  *
    1023  * @returns VBox status.
    1024  * @param   pCmd        Pointer to the command descriptor (as registered).
    1025  * @param   pCmdHlp     Pointer to command helper functions.
    1026  * @param   pVM         Pointer to the current VM (if any).
    1027  * @param   paArgs      Pointer to (readonly) array of arguments.
    1028  * @param   cArgs       Number of arguments in the array.
    1029  */
    1030 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1031 {
    1032     LogFlow(("dbgcCmdFormat\n"));
    1033     static const char *apszRangeDesc[] =
    1034     {
    1035         "none", "bytes", "elements"
    1036     };
    1037     int rc;
    1038 
    1039     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    1040     {
    1041         switch (paArgs[iArg].enmType)
    1042         {
    1043             case DBGCVAR_TYPE_UNKNOWN:
    1044                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1045                     "Unknown variable type!\n");
    1046                 break;
    1047             case DBGCVAR_TYPE_GC_FLAT:
    1048                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1049                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1050                         "Guest flat address: %%%08x range %lld %s\n",
    1051                         paArgs[iArg].u.GCFlat,
    1052                         paArgs[iArg].u64Range,
    1053                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1054                 else
    1055                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1056                         "Guest flat address: %%%08x\n",
    1057                         paArgs[iArg].u.GCFlat);
    1058                 break;
    1059             case DBGCVAR_TYPE_GC_FAR:
    1060                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1061                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1062                         "Guest far address: %04x:%08x range %lld %s\n",
    1063                         paArgs[iArg].u.GCFar.sel,
    1064                         paArgs[iArg].u.GCFar.off,
    1065                         paArgs[iArg].u64Range,
    1066                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1067                 else
    1068                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1069                         "Guest far address: %04x:%08x\n",
    1070                         paArgs[iArg].u.GCFar.sel,
    1071                         paArgs[iArg].u.GCFar.off);
    1072                 break;
    1073             case DBGCVAR_TYPE_GC_PHYS:
    1074                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1075                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1076                         "Guest physical address: %%%%%08x range %lld %s\n",
    1077                         paArgs[iArg].u.GCPhys,
    1078                         paArgs[iArg].u64Range,
    1079                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1080                 else
    1081                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1082                         "Guest physical address: %%%%%08x\n",
    1083                         paArgs[iArg].u.GCPhys);
    1084                 break;
    1085             case DBGCVAR_TYPE_HC_FLAT:
    1086                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1087                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1088                         "Host flat address: %%%08x range %lld %s\n",
    1089                         paArgs[iArg].u.pvHCFlat,
    1090                         paArgs[iArg].u64Range,
    1091                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1092                 else
    1093                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1094                         "Host flat address: %%%08x\n",
    1095                         paArgs[iArg].u.pvHCFlat);
    1096                 break;
    1097             case DBGCVAR_TYPE_HC_FAR:
    1098                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1099                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1100                         "Host far address: %04x:%08x range %lld %s\n",
    1101                         paArgs[iArg].u.HCFar.sel,
    1102                         paArgs[iArg].u.HCFar.off,
    1103                         paArgs[iArg].u64Range,
    1104                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1105                 else
    1106                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1107                         "Host far address: %04x:%08x\n",
    1108                         paArgs[iArg].u.HCFar.sel,
    1109                         paArgs[iArg].u.HCFar.off);
    1110                 break;
    1111             case DBGCVAR_TYPE_HC_PHYS:
    1112                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1113                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1114                         "Host physical address: %VHp range %lld %s\n",
    1115                         paArgs[iArg].u.HCPhys,
    1116                         paArgs[iArg].u64Range,
    1117                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1118                 else
    1119                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1120                         "Host physical address: %VHp\n",
    1121                         paArgs[iArg].u.HCPhys);
    1122                 break;
    1123 
    1124             case DBGCVAR_TYPE_STRING:
    1125                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1126                     "String, %lld bytes long: %s\n",
    1127                     paArgs[iArg].u64Range,
    1128                     paArgs[iArg].u.pszString);
    1129                 break;
    1130 
    1131             case DBGCVAR_TYPE_NUMBER:
    1132                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1133                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1134                         "Number: hex %llx  dec 0i%lld  oct 0t%llo  range %lld %s\n",
    1135                         paArgs[iArg].u.u64Number,
    1136                         paArgs[iArg].u.u64Number,
    1137                         paArgs[iArg].u.u64Number,
    1138                         paArgs[iArg].u64Range,
    1139                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1140                 else
    1141                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1142                         "Number: hex %llx  dec 0i%lld  oct 0t%llo\n",
    1143                         paArgs[iArg].u.u64Number,
    1144                         paArgs[iArg].u.u64Number,
    1145                         paArgs[iArg].u.u64Number);
    1146                 break;
    1147 
    1148             default:
    1149                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1150                     "Invalid argument type %d\n",
    1151                     paArgs[iArg].enmType);
    1152                 break;
    1153         }
    1154     } /* arg loop */
    1155 
    1156     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1157     return 0;
    1158 }
    1159 
    1160 
    1161 /**
    1162  * The 'loadsyms' command.
    1163  *
    1164  * @returns VBox status.
    1165  * @param   pCmd        Pointer to the command descriptor (as registered).
    1166  * @param   pCmdHlp     Pointer to command helper functions.
    1167  * @param   pVM         Pointer to the current VM (if any).
    1168  * @param   paArgs      Pointer to (readonly) array of arguments.
    1169  * @param   cArgs       Number of arguments in the array.
    1170  */
    1171 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1172 {
    1173     /*
    1174      * Validate the parsing and make sense of the input.
    1175      * This is a mess as usual because we don't trust the parser yet.
    1176      */
    1177     if (    cArgs < 1
    1178         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1179     {
    1180         AssertMsgFailed(("Parse error, first argument required to be string!\n"));
    1181         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1182     }
    1183     DBGCVAR     AddrVar;
    1184     RTGCUINTPTR Delta = 0;
    1185     const char *pszModule = NULL;
    1186     RTGCUINTPTR ModuleAddress = 0;
    1187     unsigned    cbModule = 0;
    1188     if (cArgs > 1)
    1189     {
    1190         unsigned iArg = 1;
    1191         if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1192         {
    1193             Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
    1194             iArg++;
    1195         }
    1196         if (iArg < cArgs)
    1197         {
    1198             if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    1199             {
    1200                 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
    1201                 return VERR_PARSE_INCORRECT_ARG_TYPE;
    1202             }
    1203             pszModule = paArgs[iArg].u.pszString;
    1204             iArg++;
    1205             if (iArg < cArgs)
    1206             {
    1207                 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
    1208                 {
    1209                     AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
    1210                     return VERR_PARSE_INCORRECT_ARG_TYPE;
    1211                 }
    1212                 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
    1213                 if (VBOX_FAILURE(rc))
    1214                     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
    1215                 ModuleAddress = paArgs[iArg].u.GCFlat;
    1216                 iArg++;
    1217                 if (iArg < cArgs)
    1218                 {
    1219                     if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
    1220                     {
    1221                         AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
    1222                         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1223                     }
    1224                     cbModule = (unsigned)paArgs[iArg].u.u64Number;
    1225                     iArg++;
    1226                     if (iArg < cArgs)
    1227                     {
    1228                         AssertMsgFailed(("Parse error, too many arguments!\n"));
    1229                         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1230                     }
    1231                 }
    1232             }
    1233         }
    1234     }
    1235 
    1236     /*
    1237      * Call the debug info manager about this loading...
    1238      */
    1239     int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
    1240     if (VBOX_FAILURE(rc))
    1241         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",
    1242                                      paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
    1243 
    1244     NOREF(pCmd); NOREF(pResult);
    1245     return VINF_SUCCESS;
    1246 }
    1247 
    1248 
    1249 /**
    1250  * The 'set' command.
    1251  *
    1252  * @returns VBox status.
    1253  * @param   pCmd        Pointer to the command descriptor (as registered).
    1254  * @param   pCmdHlp     Pointer to command helper functions.
    1255  * @param   pVM         Pointer to the current VM (if any).
    1256  * @param   paArgs      Pointer to (readonly) array of arguments.
    1257  * @param   cArgs       Number of arguments in the array.
    1258  */
    1259 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1260 {
    1261     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1262 
    1263     /* parse sanity check. */
    1264     AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
    1265     if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1266         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1267 
    1268 
    1269     /*
    1270      * A variable must start with an alpha chars and only contain alpha numerical chars.
    1271      */
    1272     const char *pszVar = paArgs[0].u.pszString;
    1273     if (!isalpha(*pszVar) || *pszVar == '_')
    1274         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1275             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
    1276 
    1277     while (isalnum(*pszVar) || *pszVar == '_')
    1278         *pszVar++;
    1279     if (*pszVar)
    1280         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1281             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
    1282 
    1283 
    1284     /*
    1285      * Calc variable size.
    1286      */
    1287     size_t  cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
    1288     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1289         cbVar += 1 + (size_t)paArgs[1].u64Range;
    1290 
    1291     /*
    1292      * Look for existing one.
    1293      */
    1294     pszVar = paArgs[0].u.pszString;
    1295     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1296     {
    1297         if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    1298         {
    1299             /*
    1300              * Update existing variable.
    1301              */
    1302             void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
    1303             if (!pv)
    1304                 return VERR_PARSE_NO_MEMORY;
    1305             PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
    1306 
    1307             pVar->Var = paArgs[1];
    1308             memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
    1309             if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1310                 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    1311             return 0;
    1312         }
    1313     }
    1314 
    1315     /*
    1316      * Allocate another.
    1317      */
    1318     PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
    1319 
    1320     pVar->Var = paArgs[1];
    1321     memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
    1322     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1323         pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    1324 
    1325     /* need to reallocate the pointer array too? */
    1326     if (!(pDbgc->cVars % 0x20))
    1327     {
    1328         void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
    1329         if (!pv)
    1330         {
    1331             RTMemFree(pVar);
    1332             return VERR_PARSE_NO_MEMORY;
    1333         }
    1334         pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
    1335     }
    1336     pDbgc->papVars[pDbgc->cVars++] = pVar;
    1337 
    1338     NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
    1339     return 0;
    1340 }
    1341 
    1342 
    1343 /**
    1344  * The 'unset' command.
    1345  *
    1346  * @returns VBox status.
    1347  * @param   pCmd        Pointer to the command descriptor (as registered).
    1348  * @param   pCmdHlp     Pointer to command helper functions.
    1349  * @param   pVM         Pointer to the current VM (if any).
    1350  * @param   paArgs      Pointer to (readonly) array of arguments.
    1351  * @param   cArgs       Number of arguments in the array.
    1352  */
    1353 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1354 {
    1355     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1356 
    1357     /*
    1358      * Don't trust the parser.
    1359      */
    1360     for (unsigned  i = 0; i < cArgs; i++)
    1361         if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
    1362         {
    1363             AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
    1364             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1365         }
    1366 
    1367     /*
    1368      * Iterate the variables and unset them.
    1369      */
    1370     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    1371     {
    1372         const char *pszVar = paArgs[iArg].u.pszString;
    1373 
    1374         /*
    1375          * Look up the variable.
    1376          */
    1377         for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1378         {
    1379             if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    1380             {
    1381                 /*
    1382                  * Shuffle the array removing this entry.
    1383                  */
    1384                 void *pvFree = pDbgc->papVars[iVar];
    1385                 if (iVar + 1 < pDbgc->cVars)
    1386                     memmove(&pDbgc->papVars[iVar],
    1387                             &pDbgc->papVars[iVar + 1],
    1388                             (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
    1389                 pDbgc->papVars[--pDbgc->cVars] = NULL;
    1390 
    1391                 RTMemFree(pvFree);
    1392             }
    1393         } /* lookup */
    1394     } /* arg loop */
    1395 
    1396     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1397     return 0;
    1398 }
    1399 
    1400 
    1401 /**
    1402  * The 'loadvars' command.
    1403  *
    1404  * @returns VBox status.
    1405  * @param   pCmd        Pointer to the command descriptor (as registered).
    1406  * @param   pCmdHlp     Pointer to command helper functions.
    1407  * @param   pVM         Pointer to the current VM (if any).
    1408  * @param   paArgs      Pointer to (readonly) array of arguments.
    1409  * @param   cArgs       Number of arguments in the array.
    1410  */
    1411 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1412 {
    1413     /*
    1414      * Don't trust the parser.
    1415      */
    1416     if (    cArgs != 1
    1417         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1418     {
    1419         AssertMsgFailed(("Expected one string exactly!\n"));
    1420         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1421     }
    1422 
    1423     /*
    1424      * Iterate the variables and unset them.
    1425      */
    1426     FILE *pFile = fopen(paArgs[0].u.pszString, "r");
    1427     if (pFile)
    1428     {
    1429         char szLine[4096];
    1430         while (fgets(szLine, sizeof(szLine), pFile))
    1431         {
    1432             /* Strip it. */
    1433             char *psz = szLine;
    1434             while (isblank(*psz))
    1435                 psz++;
    1436             int i = (int)strlen(psz) - 1;
    1437             while (i >= 0 && isspace(psz[i]))
    1438                 psz[i--] ='\0';
    1439             /* Execute it if not comment or empty line. */
    1440             if (    *psz != '\0'
    1441                 &&  *psz != '#'
    1442                 &&  *psz != ';')
    1443             {
    1444                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
    1445                 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
    1446             }
    1447         }
    1448         fclose(pFile);
    1449     }
    1450     else
    1451         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
    1452 
    1453     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1454     return 0;
    1455 }
    1456 
    1457 
    1458 /**
    1459  * The 'showvars' command.
    1460  *
    1461  * @returns VBox status.
    1462  * @param   pCmd        Pointer to the command descriptor (as registered).
    1463  * @param   pCmdHlp     Pointer to command helper functions.
    1464  * @param   pVM         Pointer to the current VM (if any).
    1465  * @param   paArgs      Pointer to (readonly) array of arguments.
    1466  * @param   cArgs       Number of arguments in the array.
    1467  */
    1468 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1469 {
    1470     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1471 
    1472     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1473     {
    1474         int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
    1475         if (!rc)
    1476             rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
    1477         if (rc)
    1478             return rc;
    1479     }
    1480 
    1481     NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    1482     return 0;
    1483 }
    1484 
    1485 
    1486 /**
    1487  * The 'harakiri' command.
    1488  *
    1489  * @returns VBox status.
    1490  * @param   pCmd        Pointer to the command descriptor (as registered).
    1491  * @param   pCmdHlp     Pointer to command helper functions.
    1492  * @param   pVM         Pointer to the current VM (if any).
    1493  * @param   paArgs      Pointer to (readonly) array of arguments.
    1494  * @param   cArgs       Number of arguments in the array.
    1495  */
    1496 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1497 {
    1498     Log(("dbgcCmdHarakiri\n"));
    1499     for (;;)
    1500         exit(126);
    1501     NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    1502 }
    1503 
    1504 
    1505 
    1506 
    1507 
    1508 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1509 //
    1510 //
    1511 //      B u l t i n   S y m b o l s
    1512 //
    1513 //
    1514 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1515 
    1516 
    1517 
    1518 /**
    1519  * Get builtin register symbol.
    1520  *
    1521  * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
    1522  *
    1523  * @returns 0 on success.
    1524  * @returns VBox evaluation / parsing error code on failure.
    1525  *          The caller does the bitching.
    1526  * @param   pSymDesc    Pointer to the symbol descriptor.
    1527  * @param   pCmdHlp     Pointer to the command callback structure.
    1528  * @param   enmType     The result type.
    1529  * @param   pResult     Where to store the result.
    1530  */
    1531 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
    1532 {
    1533     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    1534 
    1535     /*
    1536      * pVM is required.
    1537      */
    1538     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1539     Assert(pDbgc->pVM);
    1540 
    1541     /*
    1542      * Get the right CPU context.
    1543      */
    1544     PCPUMCTX    pCtx;
    1545     int         rc;
    1546     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    1547         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    1548     else
    1549         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    1550     if (VBOX_FAILURE(rc))
    1551         return rc;
    1552 
    1553     /*
    1554      * Get the value.
    1555      */
    1556     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    1557     uint64_t    u64;
    1558     switch (SYMREG_SIZE(pSymDesc->uUser))
    1559     {
    1560         case 1: u64 = *(uint8_t *)pvValue; break;
    1561         case 2: u64 = *(uint16_t *)pvValue; break;
    1562         case 4: u64 = *(uint32_t *)pvValue; break;
    1563         case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
    1564         case 8: u64 = *(uint64_t *)pvValue; break;
    1565         default:
    1566             return VERR_PARSE_NOT_IMPLEMENTED;
    1567     }
    1568 
    1569     /*
    1570      * Construct the desired result.
    1571      */
    1572     if (enmType == DBGCVAR_TYPE_ANY)
    1573         enmType = DBGCVAR_TYPE_NUMBER;
    1574     pResult->pDesc          = NULL;
    1575     pResult->pNext          = NULL;
    1576     pResult->enmType        = enmType;
    1577     pResult->enmRangeType   = DBGCVAR_RANGE_NONE;
    1578     pResult->u64Range       = 0;
    1579 
    1580     switch (enmType)
    1581     {
    1582         case DBGCVAR_TYPE_GC_FLAT:
    1583             pResult->u.GCFlat = (RTGCPTR)u64;
    1584             break;
    1585 
    1586         case DBGCVAR_TYPE_GC_FAR:
    1587             switch (SYMREG_SIZE(pSymDesc->uUser))
    1588             {
    1589                 case 4:
    1590                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1591                     {
    1592                         pResult->u.GCFar.off = (uint16_t)u64;
    1593                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);
    1594                     }
    1595                     else
    1596                     {
    1597                         pResult->u.GCFar.sel = (uint16_t)u64;
    1598                         pResult->u.GCFar.off = (uint16_t)(u64 >> 16);
    1599                     }
    1600                     break;
    1601                 case 6:
    1602                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1603                     {
    1604                         pResult->u.GCFar.off = (uint32_t)u64;
    1605                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);
    1606                     }
    1607                     else
    1608                     {
    1609                         pResult->u.GCFar.sel = (uint32_t)u64;
    1610                         pResult->u.GCFar.off = (uint16_t)(u64 >> 32);
    1611                     }
    1612                     break;
    1613 
    1614                 default:
    1615                     return VERR_PARSE_BAD_RESULT_TYPE;
    1616             }
    1617             break;
    1618 
    1619         case DBGCVAR_TYPE_GC_PHYS:
    1620             pResult->u.GCPhys = (RTGCPHYS)u64;
    1621             break;
    1622 
    1623         case DBGCVAR_TYPE_HC_FLAT:
    1624             pResult->u.pvHCFlat = (void *)(uintptr_t)u64;
    1625             break;
    1626 
    1627         case DBGCVAR_TYPE_HC_FAR:
    1628             switch (SYMREG_SIZE(pSymDesc->uUser))
    1629             {
    1630                 case 4:
    1631                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1632                     {
    1633                         pResult->u.HCFar.off = (uint16_t)u64;
    1634                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);
    1635                     }
    1636                     else
    1637                     {
    1638                         pResult->u.HCFar.sel = (uint16_t)u64;
    1639                         pResult->u.HCFar.off = (uint16_t)(u64 >> 16);
    1640                     }
    1641                     break;
    1642                 case 6:
    1643                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1644                     {
    1645                         pResult->u.HCFar.off = (uint32_t)u64;
    1646                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);
    1647                     }
    1648                     else
    1649                     {
    1650                         pResult->u.HCFar.sel = (uint32_t)u64;
    1651                         pResult->u.HCFar.off = (uint16_t)(u64 >> 32);
    1652                     }
    1653                     break;
    1654 
    1655                 default:
    1656                     return VERR_PARSE_BAD_RESULT_TYPE;
    1657             }
    1658             break;
    1659 
    1660         case DBGCVAR_TYPE_HC_PHYS:
    1661             pResult->u.GCPhys = (RTGCPHYS)u64;
    1662             break;
    1663 
    1664         case DBGCVAR_TYPE_NUMBER:
    1665             pResult->u.u64Number = u64;
    1666             break;
    1667 
    1668         case DBGCVAR_TYPE_STRING:
    1669         case DBGCVAR_TYPE_UNKNOWN:
    1670         default:
    1671             return VERR_PARSE_BAD_RESULT_TYPE;
    1672 
    1673     }
    1674 
    1675     return 0;
    1676 }
    1677 
    1678 
    1679 /**
    1680  * Set builtin register symbol.
    1681  *
    1682  * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
    1683  *
    1684  * @returns 0 on success.
    1685  * @returns VBox evaluation / parsing error code on failure.
    1686  *          The caller does the bitching.
    1687  * @param   pSymDesc    Pointer to the symbol descriptor.
    1688  * @param   pCmdHlp     Pointer to the command callback structure.
    1689  * @param   pValue      The value to assign the symbol.
    1690  */
    1691 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)
    1692 {
    1693     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    1694 
    1695     /*
    1696      * pVM is required.
    1697      */
    1698     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1699     Assert(pDbgc->pVM);
    1700 
    1701     /*
    1702      * Get the right CPU context.
    1703      */
    1704     PCPUMCTX    pCtx;
    1705     int         rc;
    1706     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    1707         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    1708     else
    1709         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    1710     if (VBOX_FAILURE(rc))
    1711         return rc;
    1712 
    1713     /*
    1714      * Check the new value.
    1715      */
    1716     if (pValue->enmType != DBGCVAR_TYPE_NUMBER)
    1717         return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1718 
    1719     /*
    1720      * Set the value.
    1721      */
    1722     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    1723     switch (SYMREG_SIZE(pSymDesc->uUser))
    1724     {
    1725         case 1:
    1726             *(uint8_t *)pvValue  = (uint8_t)pValue->u.u64Number;
    1727             break;
    1728         case 2:
    1729             *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;
    1730             break;
    1731         case 4:
    1732             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    1733             break;
    1734         case 6:
    1735             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    1736             ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);
    1737             break;
    1738         case 8:
    1739             *(uint64_t *)pvValue = pValue->u.u64Number;
    1740             break;
    1741         default:
    1742             return VERR_PARSE_NOT_IMPLEMENTED;
    1743     }
    1744 
    1745     return VINF_SUCCESS;
    1746 }
    1747 
    1748 
    1749 
    1750 
    1751 
    1752 
    1753 
    1754 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1755 //
    1756 //
    1757 //      O p e r a t o r s
    1758 //
    1759 //
    1760 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
     108/** Number of operators in the operator array. */
     109const unsigned g_cOps = RT_ELEMENTS(g_aOps);
    1761110
    1762111
     
    1989338 * @param   pResult     Where to store the result.
    1990339 */
    1991 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
     340DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1992341{
    1993342//    LogFlow(("dbgcOpAddrFlat\n"));
     
    2057406 * @param   pResult     Where to store the result.
    2058407 */
    2059 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
     408DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2060409{
    2061410//    LogFlow(("dbgcOpAddrPhys\n"));
     
    2134483 * @param   pResult     Where to store the result.
    2135484 */
    2136 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
     485DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2137486{
    2138487//    LogFlow(("dbgcOpAddrPhys\n"));
     
    2216565 * @param   pResult     Where to store the result.
    2217566 */
    2218 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
     567DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2219568{
    2220569//    LogFlow(("dbgcOpAddrHost\n"));
     
    32011550
    32021551
    3203 
    3204 
    3205 
    3206 /**
    3207  * Output callback.
    3208  *
    3209  * @returns number of bytes written.
    3210  * @param   pvArg       User argument.
    3211  * @param   pachChars   Pointer to an array of utf-8 characters.
    3212  * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    3213  */
    3214 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
    3215 {
    3216     PDBGC   pDbgc = (PDBGC)pvArg;
    3217     if (cbChars)
    3218     {
    3219         int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
    3220         if (VBOX_FAILURE(rc))
    3221         {
    3222             pDbgc->rcOutput = rc;
    3223             cbChars = 0;
    3224         }
    3225     }
    3226 
    3227     return cbChars;
    3228 }
    3229 
    3230 
    3231 
    3232 
    3233 
    3234 
    3235 
    3236 
    3237 
    3238 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3239 //
    3240 //
    3241 //      C a l l b a c k   H e l p e r s
    3242 //
    3243 //
    3244 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3245 
    3246 
    3247 
    3248 /**
    3249  * Command helper for writing text to the debug console.
    3250  *
    3251  * @returns VBox status.
    3252  * @param   pCmdHlp     Pointer to the command callback structure.
    3253  * @param   pvBuf       What to write.
    3254  * @param   cbBuf       Number of bytes to write.
    3255  * @param   pcbWritten  Where to store the number of bytes actually written.
    3256  *                      If NULL the entire buffer must be successfully written.
    3257  */
    3258 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    3259 {
    3260     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3261     return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
    3262 }
    3263 
    3264 
    3265 /**
    3266  * Command helper for writing formatted text to the debug console.
    3267  *
    3268  * @returns VBox status.
    3269  * @param   pCmdHlp     Pointer to the command callback structure.
    3270  * @param   pcb         Where to store the number of bytes written.
    3271  * @param   pszFormat   The format string.
    3272  *                      This is using the log formatter, so it's format extensions can be used.
    3273  * @param   ...         Arguments specified in the format string.
    3274  */
    3275 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
    3276 {
    3277     /*
    3278      * Do the formatting and output.
    3279      */
    3280     va_list args;
    3281     va_start(args, pszFormat);
    3282     int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
    3283     va_end(args);
    3284 
    3285     return rc;
    3286 }
    3287 
    3288 /**
    3289  * Callback to format non-standard format specifiers.
    3290  *
    3291  * @returns The number of bytes formatted.
    3292  * @param   pvArg           Formatter argument.
    3293  * @param   pfnOutput       Pointer to output function.
    3294  * @param   pvArgOutput     Argument for the output function.
    3295  * @param   ppszFormat      Pointer to the format string pointer. Advance this till the char
    3296  *                          after the format specifier.
    3297  * @param   pArgs           Pointer to the argument list. Use this to fetch the arguments.
    3298  * @param   cchWidth        Format Width. -1 if not specified.
    3299  * @param   cchPrecision    Format Precision. -1 if not specified.
    3300  * @param   fFlags          Flags (RTSTR_NTFS_*).
    3301  * @param   chArgSize       The argument size specifier, 'l' or 'L'.
    3302  */
    3303 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
    3304                                                 const char **ppszFormat, va_list *pArgs, int cchWidth,
    3305                                                 int cchPrecision, unsigned fFlags, char chArgSize)
    3306 {
    3307     NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
    3308     if (**ppszFormat != 'D')
    3309     {
    3310         (*ppszFormat)++;
    3311         return 0;
    3312     }
    3313 
    3314     (*ppszFormat)++;
    3315     switch (**ppszFormat)
    3316     {
    3317         /*
    3318          * Print variable without range.
    3319          * The argument is a const pointer to the variable.
    3320          */
    3321         case 'V':
    3322         {
    3323             (*ppszFormat)++;
    3324             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    3325             switch (pVar->enmType)
    3326             {
    3327                 case DBGCVAR_TYPE_GC_FLAT:
    3328                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
    3329                 case DBGCVAR_TYPE_GC_FAR:
    3330                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
    3331                 case DBGCVAR_TYPE_GC_PHYS:
    3332                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
    3333                 case DBGCVAR_TYPE_HC_FLAT:
    3334                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
    3335                 case DBGCVAR_TYPE_HC_FAR:
    3336                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
    3337                 case DBGCVAR_TYPE_HC_PHYS:
    3338                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
    3339                 case DBGCVAR_TYPE_STRING:
    3340                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    3341                 case DBGCVAR_TYPE_NUMBER:
    3342                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
    3343 
    3344                 case DBGCVAR_TYPE_UNKNOWN:
    3345                 default:
    3346                     return pfnOutput(pvArgOutput, "??", 2);
    3347             }
    3348         }
    3349 
    3350         /*
    3351          * Print variable with range.
    3352          * The argument is a const pointer to the variable.
    3353          */
    3354         case 'v':
    3355         {
    3356             (*ppszFormat)++;
    3357             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    3358 
    3359             char szRange[32];
    3360             switch (pVar->enmRangeType)
    3361             {
    3362                 case DBGCVAR_RANGE_NONE:
    3363                     szRange[0] = '\0';
    3364                     break;
    3365                 case DBGCVAR_RANGE_ELEMENTS:
    3366                     RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
    3367                     break;
    3368                 case DBGCVAR_RANGE_BYTES:
    3369                     RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
    3370                     break;
    3371             }
    3372 
    3373             switch (pVar->enmType)
    3374             {
    3375                 case DBGCVAR_TYPE_GC_FLAT:
    3376                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
    3377                 case DBGCVAR_TYPE_GC_FAR:
    3378                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
    3379                 case DBGCVAR_TYPE_GC_PHYS:
    3380                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
    3381                 case DBGCVAR_TYPE_HC_FLAT:
    3382                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
    3383                 case DBGCVAR_TYPE_HC_FAR:
    3384                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
    3385                 case DBGCVAR_TYPE_HC_PHYS:
    3386                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
    3387                 case DBGCVAR_TYPE_STRING:
    3388                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    3389                 case DBGCVAR_TYPE_NUMBER:
    3390                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
    3391 
    3392                 case DBGCVAR_TYPE_UNKNOWN:
    3393                 default:
    3394                     return pfnOutput(pvArgOutput, "??", 2);
    3395             }
    3396         }
    3397 
    3398         default:
    3399             AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
    3400             return 0;
    3401     }
    3402 }
    3403 
    3404 
    3405 /**
    3406  * Command helper for writing formatted text to the debug console.
    3407  *
    3408  * @returns VBox status.
    3409  * @param   pCmdHlp     Pointer to the command callback structure.
    3410  * @param   pcb         Where to store the number of bytes written.
    3411  * @param   pszFormat   The format string.
    3412  *                      This is using the log formatter, so it's format extensions can be used.
    3413  * @param   args        Arguments specified in the format string.
    3414  */
    3415 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
    3416 {
    3417     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3418 
    3419     /*
    3420      * Do the formatting and output.
    3421      */
    3422     pDbgc->rcOutput = 0;
    3423     size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
    3424 
    3425     if (pcbWritten)
    3426         *pcbWritten = cb;
    3427 
    3428     return pDbgc->rcOutput;
    3429 }
    3430 
    3431 
    3432 /**
    3433  * Reports an error from a DBGF call.
    3434  *
    3435  * @returns VBox status code appropriate to return from a command.
    3436  * @param   pCmdHlp     Pointer to command helpers.
    3437  * @param   rc          The VBox status code returned by a DBGF call.
    3438  * @param   pszFormat   Format string for additional messages. Can be NULL.
    3439  * @param   ...         Format arguments, optional.
    3440  */
    3441 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
    3442 {
    3443     switch (rc)
    3444     {
    3445         case VINF_SUCCESS:
    3446             break;
    3447 
    3448         default:
    3449             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
    3450             if (VBOX_SUCCESS(rc) && pszFormat)
    3451                 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    3452             break;
    3453     }
    3454     return rc;
    3455 }
    3456 
    3457 
    3458 /**
    3459  * Reports an error from a DBGF call.
    3460  *
    3461  * @returns VBox status code appropriate to return from a command.
    3462  * @param   pCmdHlp     Pointer to command helpers.
    3463  * @param   rc          The VBox status code returned by a DBGF call.
    3464  * @param   pszFormat   Format string for additional messages. Can be NULL.
    3465  * @param   ...         Format arguments, optional.
    3466  */
    3467 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
    3468 {
    3469     va_list args;
    3470     va_start(args, pszFormat);
    3471     int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
    3472     va_end(args);
    3473     return rcRet;
    3474 }
    3475 
    3476 
    3477 /**
    3478  * Command helper for reading memory specified by a DBGC variable.
    3479  *
    3480  * @returns VBox status code appropriate to return from a command.
    3481  * @param   pCmdHlp     Pointer to the command callback structure.
    3482  * @param   pVM         VM handle if GC or physical HC address.
    3483  * @param   pvBuffer    Where to store the read data.
    3484  * @param   cbRead      Number of bytes to read.
    3485  * @param   pVarPointer DBGC variable specifying where to start reading.
    3486  * @param   pcbRead     Where to store the number of bytes actually read.
    3487  *                      This optional, but it's useful when read GC virtual memory where a
    3488  *                      page in the requested range might not be present.
    3489  *                      If not specified not-present failure or end of a HC physical page
    3490  *                      will cause failure.
    3491  */
    3492 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
    3493 {
    3494     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3495 
    3496     /*
    3497      * Dummy check.
    3498      */
    3499     if (cbRead == 0)
    3500     {
    3501         if (*pcbRead)
    3502             *pcbRead = 0;
    3503         return VINF_SUCCESS;
    3504     }
    3505 
    3506     /*
    3507      * Convert Far addresses getting size and the correct base address.
    3508      * Getting and checking the size is what makes this messy and slow.
    3509      */
    3510     DBGCVAR Var = *pVarPointer;
    3511     switch (pVarPointer->enmType)
    3512     {
    3513         case DBGCVAR_TYPE_GC_FAR:
    3514         {
    3515             /* Use DBGFR3AddrFromSelOff for the conversion. */
    3516             Assert(pDbgc->pVM);
    3517             DBGFADDRESS Address;
    3518             int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
    3519             if (VBOX_FAILURE(rc))
    3520                 return rc;
    3521 
    3522             /* don't bother with flat selectors (for now). */
    3523             if (!DBGFADDRESS_IS_FLAT(&Address))
    3524             {
    3525                 SELMSELINFO SelInfo;
    3526                 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
    3527                 if (VBOX_SUCCESS(rc))
    3528                 {
    3529                     RTGCUINTPTR cb; /* -1 byte */
    3530                     if (SELMSelInfoIsExpandDown(&SelInfo))
    3531                     {
    3532                         if (    !SelInfo.Raw.Gen.u1Granularity
    3533                             &&  Address.off > UINT16_C(0xffff))
    3534                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    3535                         if (Address.off <= SelInfo.cbLimit)
    3536                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    3537                         cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
    3538                     }
    3539                     else
    3540                     {
    3541                         if (Address.off > SelInfo.cbLimit)
    3542                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    3543                         cb = SelInfo.cbLimit - Address.off;
    3544                     }
    3545                     if (cbRead - 1 > cb)
    3546                     {
    3547                         if (!pcbRead)
    3548                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    3549                         cbRead = cb + 1;
    3550                     }
    3551                 }
    3552 
    3553                 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
    3554                 Var.u.GCFlat = Address.FlatPtr;
    3555             }
    3556             break;
    3557         }
    3558 
    3559         case DBGCVAR_TYPE_GC_FLAT:
    3560         case DBGCVAR_TYPE_GC_PHYS:
    3561         case DBGCVAR_TYPE_HC_FLAT:
    3562         case DBGCVAR_TYPE_HC_PHYS:
    3563             break;
    3564 
    3565         case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
    3566         default:
    3567             return VERR_NOT_IMPLEMENTED;
    3568     }
    3569 
    3570 
    3571 
    3572     /*
    3573      * Copy page by page.
    3574      */
    3575     size_t cbLeft = cbRead;
    3576     for (;;)
    3577     {
    3578         /*
    3579          * Calc read size.
    3580          */
    3581         size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
    3582         switch (pVarPointer->enmType)
    3583         {
    3584             case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
    3585             case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
    3586             case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
    3587             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! */
    3588             default: break;
    3589         }
    3590 
    3591         /*
    3592          * Perform read.
    3593          */
    3594         int rc;
    3595         switch (Var.enmType)
    3596         {
    3597             case DBGCVAR_TYPE_GC_FLAT:
    3598                 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
    3599                 break;
    3600             case DBGCVAR_TYPE_GC_PHYS:
    3601                 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
    3602                 break;
    3603 
    3604             case DBGCVAR_TYPE_HC_PHYS:
    3605             case DBGCVAR_TYPE_HC_FLAT:
    3606             case DBGCVAR_TYPE_HC_FAR:
    3607             {
    3608                 DBGCVAR Var2;
    3609                 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
    3610                 if (VBOX_SUCCESS(rc))
    3611                 {
    3612                     /** @todo protect this!!! */
    3613                     memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
    3614                     rc = 0;
    3615                 }
    3616                 else
    3617                     rc = VERR_INVALID_POINTER;
    3618                 break;
    3619             }
    3620 
    3621             default:
    3622                 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
    3623         }
    3624 
    3625         /*
    3626          * Check for failure.
    3627          */
    3628         if (VBOX_FAILURE(rc))
    3629         {
    3630             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    3631                 return VINF_SUCCESS;
    3632             return rc;
    3633         }
    3634 
    3635         /*
    3636          * Next.
    3637          */
    3638         cbLeft -= cb;
    3639         if (!cbLeft)
    3640             break;
    3641         pvBuffer = (char *)pvBuffer + cb;
    3642         rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
    3643         if (VBOX_FAILURE(rc))
    3644         {
    3645             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    3646                 return VINF_SUCCESS;
    3647             return rc;
    3648         }
    3649     }
    3650 
    3651     /*
    3652      * Done
    3653      */
    3654     if (pcbRead)
    3655         *pcbRead = cbRead;
    3656     return 0;
    3657 }
    3658 
    3659 /**
    3660  * Command helper for writing memory specified by a DBGC variable.
    3661  *
    3662  * @returns VBox status code appropriate to return from a command.
    3663  * @param   pCmdHlp     Pointer to the command callback structure.
    3664  * @param   pVM         VM handle if GC or physical HC address.
    3665  * @param   pvBuffer    What to write.
    3666  * @param   cbWrite     Number of bytes to write.
    3667  * @param   pVarPointer DBGC variable specifying where to start reading.
    3668  * @param   pcbWritten  Where to store the number of bytes written.
    3669  *                      This is optional. If NULL be aware that some of the buffer
    3670  *                      might have been written to the specified address.
    3671  */
    3672 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
    3673 {
    3674     NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
    3675     return VERR_NOT_IMPLEMENTED;
    3676 }
    3677 
    3678 
    3679 /**
    3680  * Evaluates an expression.
    3681  * (Hopefully the parser and functions are fully reentrant.)
    3682  *
    3683  * @returns VBox status code appropriate to return from a command.
    3684  * @param   pCmdHlp     Pointer to the command callback structure.
    3685  * @param   pResult     Where to store the result.
    3686  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    3687  * @param   ...         Format arguments.
    3688  */
    3689 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
    3690 {
    3691     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3692 
    3693     /*
    3694      * Format the expression.
    3695      */
    3696     char szExprFormatted[2048];
    3697     va_list args;
    3698     va_start(args, pszExpr);
    3699     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
    3700     va_end(args);
    3701     /* ignore overflows. */
    3702 
    3703     return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
    3704 }
    3705 
    3706 
    3707 /**
    3708  * Executes one command expression.
    3709  * (Hopefully the parser and functions are fully reentrant.)
    3710  *
    3711  * @returns VBox status code appropriate to return from a command.
    3712  * @param   pCmdHlp     Pointer to the command callback structure.
    3713  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    3714  * @param   ...         Format arguments.
    3715  */
    3716 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
    3717 {
    3718     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3719     /* Save the scratch state. */
    3720     char       *pszScratch  = pDbgc->pszScratch;
    3721     unsigned    iArg        = pDbgc->iArg;
    3722 
    3723     /*
    3724      * Format the expression.
    3725      */
    3726     va_list args;
    3727     va_start(args, pszExpr);
    3728     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    3729     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
    3730     va_end(args);
    3731     if (cb >= cbScratch)
    3732         return VERR_BUFFER_OVERFLOW;
    3733 
    3734     /*
    3735      * Execute the command.
    3736      * We save and restore the arg index and scratch buffer pointer.
    3737      */
    3738     pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
    3739     int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
    3740 
    3741     /* Restore the scratch state. */
    3742     pDbgc->iArg         = iArg;
    3743     pDbgc->pszScratch   = pszScratch;
    3744 
    3745     return rc;
    3746 }
    3747 
    3748 
    3749 /**
    3750  * Converts a DBGC variable to a DBGF address structure.
    3751  *
    3752  * @returns VBox status code.
    3753  * @param   pCmdHlp     Pointer to the command callback structure.
    3754  * @param   pVar        The variable to convert.
    3755  * @param   pAddress    The target address.
    3756  */
    3757 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    3758 {
    3759     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3760     return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
    3761 }
    3762 
    3763 
    3764 /**
    3765  * Converts a DBGC variable to a boolean.
    3766  *
    3767  * @returns VBox status code.
    3768  * @param   pCmdHlp     Pointer to the command callback structure.
    3769  * @param   pVar        The variable to convert.
    3770  * @param   pf          Where to store the boolean.
    3771  */
    3772 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
    3773 {
    3774     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    3775     NOREF(pDbgc);
    3776 
    3777     switch (pVar->enmType)
    3778     {
    3779         case DBGCVAR_TYPE_STRING:
    3780             /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
    3781             if (    !strcmp(pVar->u.pszString, "true")
    3782                 ||  !strcmp(pVar->u.pszString, "True")
    3783                 ||  !strcmp(pVar->u.pszString, "TRUE")
    3784                 ||  !strcmp(pVar->u.pszString, "on")
    3785                 ||  !strcmp(pVar->u.pszString, "On")
    3786                 ||  !strcmp(pVar->u.pszString, "oN")
    3787                 ||  !strcmp(pVar->u.pszString, "ON")
    3788                 ||  !strcmp(pVar->u.pszString, "enabled")
    3789                 ||  !strcmp(pVar->u.pszString, "Enabled")
    3790                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    3791             {
    3792                 *pf = true;
    3793                 return VINF_SUCCESS;
    3794             }
    3795             if (    !strcmp(pVar->u.pszString, "false")
    3796                 ||  !strcmp(pVar->u.pszString, "False")
    3797                 ||  !strcmp(pVar->u.pszString, "FALSE")
    3798                 ||  !strcmp(pVar->u.pszString, "off")
    3799                 ||  !strcmp(pVar->u.pszString, "Off")
    3800                 ||  !strcmp(pVar->u.pszString, "OFF")
    3801                 ||  !strcmp(pVar->u.pszString, "disabled")
    3802                 ||  !strcmp(pVar->u.pszString, "Disabled")
    3803                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    3804             {
    3805                 *pf = false;
    3806                 return VINF_SUCCESS;
    3807             }
    3808             return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
    3809 
    3810         case DBGCVAR_TYPE_GC_FLAT:
    3811         case DBGCVAR_TYPE_GC_PHYS:
    3812         case DBGCVAR_TYPE_HC_FLAT:
    3813         case DBGCVAR_TYPE_HC_PHYS:
    3814         case DBGCVAR_TYPE_NUMBER:
    3815             *pf = pVar->u.u64Number != 0;
    3816             return VINF_SUCCESS;
    3817 
    3818         case DBGCVAR_TYPE_HC_FAR:
    3819         case DBGCVAR_TYPE_GC_FAR:
    3820         case DBGCVAR_TYPE_SYMBOL:
    3821         default:
    3822             return VERR_PARSE_INCORRECT_ARG_TYPE;
    3823     }
    3824 }
    3825 
    3826 
    3827 
    3828 
    3829 
    3830 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3831 //
    3832 //
    3833 //      V a r i a b l e   M a n i p u l a t i o n
    3834 //
    3835 //
    3836 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3837 
    3838 
    3839 
    3840 /** @todo move me!*/
    3841 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
    3842 {
    3843     if (pVar)
    3844     {
    3845         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    3846         pVar->u.GCFlat = GCFlat;
    3847         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    3848         pVar->u64Range  = 0;
    3849     }
    3850 }
    3851 
    3852 
    3853 /** @todo move me!*/
    3854 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
    3855 {
    3856     if (pVar)
    3857     {
    3858         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    3859         pVar->u.GCFlat = GCFlat;
    3860         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    3861         pVar->u64Range  = cb;
    3862     }
    3863 }
    3864 
    3865 
    3866 /** @todo move me!*/
    3867 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    3868 {
    3869     if (pVar)
    3870     {
    3871         if (pVar2)
    3872             *pVar = *pVar2;
    3873         else
    3874         {
    3875             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    3876             memset(&pVar->u, 0, sizeof(pVar->u));
    3877             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    3878             pVar->u64Range  = 0;
    3879         }
    3880     }
    3881 }
    3882 
    3883 
    3884 /** @todo move me!*/
    3885 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    3886 {
    3887     if (pVar)
    3888     {
    3889         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    3890         pVar->u64Range  = cb;
    3891     }
    3892 }
    3893 
    3894 
    3895 /** @todo move me!*/
    3896 void dbgcVarSetNoRange(PDBGCVAR pVar)
    3897 {
    3898     if (pVar)
    3899     {
    3900         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    3901         pVar->u64Range  = 0;
    3902     }
    3903 }
    3904 
    3905 
    3906 /**
    3907  * Converts a DBGC variable to a DBGF address.
    3908  *
    3909  * @returns VBox status code.
    3910  * @param   pDbgc       The DBGC instance.
    3911  * @param   pVar        The variable.
    3912  * @param   pAddress    Where to store the address.
    3913  */
    3914 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    3915 {
    3916     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    3917     switch (pVar->enmType)
    3918     {
    3919         case DBGCVAR_TYPE_GC_FLAT:
    3920             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    3921             return VINF_SUCCESS;
    3922 
    3923         case DBGCVAR_TYPE_NUMBER:
    3924             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    3925             return VINF_SUCCESS;
    3926 
    3927         case DBGCVAR_TYPE_GC_FAR:
    3928             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    3929 
    3930         case DBGCVAR_TYPE_STRING:
    3931         case DBGCVAR_TYPE_SYMBOL:
    3932         {
    3933             DBGCVAR Var;
    3934             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    3935             if (VBOX_FAILURE(rc))
    3936                 return rc;
    3937             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    3938         }
    3939 
    3940         case DBGCVAR_TYPE_GC_PHYS:
    3941         case DBGCVAR_TYPE_HC_FLAT:
    3942         case DBGCVAR_TYPE_HC_FAR:
    3943         case DBGCVAR_TYPE_HC_PHYS:
    3944         default:
    3945             return VERR_PARSE_CONVERSION_FAILED;
    3946     }
    3947 }
    3948 
    3949 
    3950 
    3951 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3952 //
    3953 //
    3954 //      B r e a k p o i n t   M a n a g e m e n t
    3955 //
    3956 //
    3957 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3958 
    3959 
    3960 /**
    3961  * Adds a breakpoint to the DBGC breakpoint list.
    3962  */
    3963 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    3964 {
    3965     /*
    3966      * Check if it already exists.
    3967      */
    3968     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    3969     if (pBp)
    3970         return VERR_DBGC_BP_EXISTS;
    3971 
    3972     /*
    3973      * Add the breakpoint.
    3974      */
    3975     if (pszCmd)
    3976         pszCmd = RTStrStripL(pszCmd);
    3977     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    3978     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    3979     if (!pBp)
    3980         return VERR_NO_MEMORY;
    3981     if (cchCmd)
    3982         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    3983     else
    3984         pBp->szCmd[0] = '\0';
    3985     pBp->cchCmd = cchCmd;
    3986     pBp->iBp    = iBp;
    3987     pBp->pNext  = pDbgc->pFirstBp;
    3988     pDbgc->pFirstBp = pBp;
    3989 
    3990     return VINF_SUCCESS;
    3991 }
    3992 
    3993 /**
    3994  * Updates the a breakpoint.
    3995  *
    3996  * @returns VBox status code.
    3997  * @param   pDbgc       The DBGC instance.
    3998  * @param   iBp         The breakpoint to update.
    3999  * @param   pszCmd      The new command.
    4000  */
    4001 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    4002 {
    4003     /*
    4004      * Find the breakpoint.
    4005      */
    4006     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    4007     if (!pBp)
    4008         return VERR_DBGC_BP_NOT_FOUND;
    4009 
    4010     /*
    4011      * Do we need to reallocate?
    4012      */
    4013     if (pszCmd)
    4014         pszCmd = RTStrStripL(pszCmd);
    4015     if (!pszCmd || !*pszCmd)
    4016         pBp->szCmd[0] = '\0';
    4017     else
    4018     {
    4019         size_t cchCmd = strlen(pszCmd);
    4020         if (strlen(pBp->szCmd) >= cchCmd)
    4021         {
    4022             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    4023             pBp->cchCmd = cchCmd;
    4024         }
    4025         else
    4026         {
    4027             /*
    4028              * Yes, let's do it the simple way...
    4029              */
    4030             int rc = dbgcBpDelete(pDbgc, iBp);
    4031             AssertRC(rc);
    4032             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    4033         }
    4034     }
    4035     return VINF_SUCCESS;
    4036 }
    4037 
    4038 
    4039 /**
    4040  * Deletes a breakpoint.
    4041  *
    4042  * @returns VBox status code.
    4043  * @param   pDbgc       The DBGC instance.
    4044  * @param   iBp         The breakpoint to delete.
    4045  */
    4046 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    4047 {
    4048     /*
    4049      * Search thru the list, when found unlink and free it.
    4050      */
    4051     PDBGCBP pBpPrev = NULL;
    4052     PDBGCBP pBp = pDbgc->pFirstBp;
    4053     for (; pBp; pBp = pBp->pNext)
    4054     {
    4055         if (pBp->iBp == iBp)
    4056         {
    4057             if (pBpPrev)
    4058                 pBpPrev->pNext = pBp->pNext;
    4059             else
    4060                 pDbgc->pFirstBp = pBp->pNext;
    4061             RTMemFree(pBp);
    4062             return VINF_SUCCESS;
    4063         }
    4064         pBpPrev = pBp;
    4065     }
    4066 
    4067     return VERR_DBGC_BP_NOT_FOUND;
    4068 }
    4069 
    4070 
    4071 /**
    4072  * Get a breakpoint.
    4073  *
    4074  * @returns Pointer to the breakpoint.
    4075  * @returns NULL if the breakpoint wasn't found.
    4076  * @param   pDbgc       The DBGC instance.
    4077  * @param   iBp         The breakpoint to get.
    4078  */
    4079 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    4080 {
    4081     /*
    4082      * Enumerate the list.
    4083      */
    4084     PDBGCBP pBp = pDbgc->pFirstBp;
    4085     for (; pBp; pBp = pBp->pNext)
    4086         if (pBp->iBp == iBp)
    4087             return pBp;
    4088     return NULL;
    4089 }
    4090 
    4091 
    4092 /**
    4093  * Executes the command of a breakpoint.
    4094  *
    4095  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    4096  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    4097  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    4098  * @returns VBox status code from dbgcProcessCommand() other wise.
    4099  * @param   pDbgc       The DBGC instance.
    4100  * @param   iBp         The breakpoint to execute.
    4101  */
    4102 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    4103 {
    4104     /*
    4105      * Find the breakpoint.
    4106      */
    4107     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    4108     if (!pBp)
    4109         return VERR_DBGC_BP_NOT_FOUND;
    4110 
    4111     /*
    4112      * Anything to do?
    4113      */
    4114     if (!pBp->cchCmd)
    4115         return VINF_DBGC_BP_NO_COMMAND;
    4116 
    4117     /*
    4118      * Execute the command.
    4119      * This means copying it to the scratch buffer and process it as if it
    4120      * were user input. We must save and restore the state of the scratch buffer.
    4121      */
    4122     /* Save the scratch state. */
    4123     char       *pszScratch  = pDbgc->pszScratch;
    4124     unsigned    iArg        = pDbgc->iArg;
    4125 
    4126     /* Copy the command to the scratch buffer. */
    4127     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    4128     if (pBp->cchCmd >= cbScratch)
    4129         return VERR_BUFFER_OVERFLOW;
    4130     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    4131 
    4132     /* Execute the command. */
    4133     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    4134     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    4135 
    4136     /* Restore the scratch state. */
    4137     pDbgc->iArg         = iArg;
    4138     pDbgc->pszScratch   = pszScratch;
    4139 
    4140     return rc;
    4141 }
    4142 
    4143 
    4144 
    4145 
    4146 
    4147 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4148 //
    4149 //
    4150 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    4151 //
    4152 //
    4153 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    4154 
    4155 
    4156 
    4157 /**
    4158  * Prints any log lines from the log buffer.
    4159  *
    4160  * The caller must not call function this unless pDbgc->fLog is set.
    4161  *
    4162  * @returns VBox status. (output related)
    4163  * @param   pDbgc   Debugger console instance data.
    4164  */
    4165 static int dbgcProcessLog(PDBGC pDbgc)
    4166 {
    4167     /** @todo */
    4168     NOREF(pDbgc);
    4169     return 0;
    4170 }
    4171 
    4172 
    4173 
    4174 /**
    4175  * Handle input buffer overflow.
    4176  *
    4177  * Will read any available input looking for a '\n' to reset the buffer on.
    4178  *
    4179  * @returns VBox status.
    4180  * @param   pDbgc   Debugger console instance data.
    4181  */
    4182 static int dbgcInputOverflow(PDBGC pDbgc)
    4183 {
    4184     /*
    4185      * Assert overflow status and reset the input buffer.
    4186      */
    4187     if (!pDbgc->fInputOverflow)
    4188     {
    4189         pDbgc->fInputOverflow = true;
    4190         pDbgc->iRead = pDbgc->iWrite = 0;
    4191         pDbgc->cInputLines = 0;
    4192         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    4193     }
    4194 
    4195     /*
    4196      * Eat input till no more or there is a '\n'.
    4197      * When finding a '\n' we'll continue normal processing.
    4198      */
    4199     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    4200     {
    4201         size_t cbRead;
    4202         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    4203         if (VBOX_FAILURE(rc))
    4204             return rc;
    4205         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    4206         if (psz)
    4207         {
    4208             pDbgc->fInputOverflow = false;
    4209             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    4210             pDbgc->iWrite = (unsigned)cbRead;
    4211             pDbgc->cInputLines = 0;
    4212             break;
    4213         }
    4214     }
    4215 
    4216     return 0;
    4217 }
    4218 
    4219 
    4220 
    4221 /**
    4222  * Read input and do some preprocessing.
    4223  *
    4224  * @returns VBox status.
    4225  *          In addition to the iWrite and achInput, cInputLines is maintained.
    4226  *          In case of an input overflow the fInputOverflow flag will be set.
    4227  * @param   pDbgc   Debugger console instance data.
    4228  */
    4229 static int dbgcInputRead(PDBGC pDbgc)
    4230 {
    4231     /*
    4232      * We have ready input.
    4233      * Read it till we don't have any or we have a full input buffer.
    4234      */
    4235     int     rc = 0;
    4236     do
    4237     {
    4238         /*
    4239          * More available buffer space?
    4240          */
    4241         size_t cbLeft;
    4242         if (pDbgc->iWrite > pDbgc->iRead)
    4243             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    4244         else
    4245             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    4246         if (!cbLeft)
    4247         {
    4248             /* overflow? */
    4249             if (!pDbgc->cInputLines)
    4250                 rc = dbgcInputOverflow(pDbgc);
    4251             break;
    4252         }
    4253 
    4254         /*
    4255          * Read one char and interpret it.
    4256          */
    4257         char    achRead[128];
    4258         size_t  cbRead;
    4259         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    4260         if (VBOX_FAILURE(rc))
    4261             return rc;
    4262         char *psz = &achRead[0];
    4263         while (cbRead-- > 0)
    4264         {
    4265             char ch = *psz++;
    4266             switch (ch)
    4267             {
    4268                 /*
    4269                  * Ignore.
    4270                  */
    4271                 case '\0':
    4272                 case '\r':
    4273                 case '\a':
    4274                     break;
    4275 
    4276                 /*
    4277                  * Backspace.
    4278                  */
    4279                 case '\b':
    4280                     Log2(("DBGC: backspace\n"));
    4281                     if (pDbgc->iRead != pDbgc->iWrite)
    4282                     {
    4283                         unsigned iWriteUndo = pDbgc->iWrite;
    4284                         if (pDbgc->iWrite)
    4285                             pDbgc->iWrite--;
    4286                         else
    4287                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    4288 
    4289                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    4290                             pDbgc->iWrite = iWriteUndo;
    4291                     }
    4292                     break;
    4293 
    4294                 /*
    4295                  * Add char to buffer.
    4296                  */
    4297                 case '\t':
    4298                 case '\n':
    4299                 case ';':
    4300                     switch (ch)
    4301                     {
    4302                         case '\t': ch = ' '; break;
    4303                         case '\n': pDbgc->cInputLines++; break;
    4304                     }
    4305                 default:
    4306                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    4307                     pDbgc->achInput[pDbgc->iWrite] = ch;
    4308                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    4309                         pDbgc->iWrite = 0;
    4310                     break;
    4311             }
    4312         }
    4313 
    4314         /* Terminate it to make it easier to read in the debugger. */
    4315         pDbgc->achInput[pDbgc->iWrite] = '\0';
    4316     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    4317 
    4318     return rc;
    4319 }
    4320 
    4321 
    4322 /**
    4323  * Finds a builtin symbol.
    4324  * @returns Pointer to symbol descriptor on success.
    4325  * @returns NULL on failure.
    4326  * @param   pDbgc       The debug console instance.
    4327  * @param   pszSymbol   The symbol name.
    4328  */
    4329 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
    4330 {
    4331     for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)
    4332         if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
    4333             return &g_aSyms[iSym];
    4334 
    4335     /** @todo externally registered symbols. */
    4336     NOREF(pDbgc);
    4337     return NULL;
    4338 }
    4339 
    4340 
    4341 /**
    4342  * Resolves a symbol (or tries to do so at least).
    4343  *
    4344  * @returns 0 on success.
    4345  * @returns VBox status on failure.
    4346  * @param   pDbgc       The debug console instance.
    4347  * @param   pszSymbol   The symbol name.
    4348  * @param   enmType     The result type.
    4349  * @param   pResult     Where to store the result.
    4350  */
    4351 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    4352 {
    4353     /*
    4354      * Builtin?
    4355      */
    4356     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    4357     if (pSymDesc)
    4358     {
    4359         if (!pSymDesc->pfnGet)
    4360             return VERR_PARSE_WRITEONLY_SYMBOL;
    4361         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    4362     }
    4363 
    4364 
    4365     /*
    4366      * Ask PDM.
    4367      */
    4368     /** @todo resolve symbols using PDM. */
    4369 
    4370 
    4371     /*
    4372      * Ask the debug info manager.
    4373      */
    4374     DBGFSYMBOL Symbol;
    4375     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    4376     if (VBOX_SUCCESS(rc))
    4377     {
    4378         /*
    4379          * Default return is a flat gc address.
    4380          */
    4381         memset(pResult, 0,  sizeof(*pResult));
    4382         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    4383         pResult->u64Range     = Symbol.cb;
    4384         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    4385         pResult->u.GCFlat     = Symbol.Value;
    4386         DBGCVAR VarTmp;
    4387         switch (enmType)
    4388         {
    4389             /* nothing to do. */
    4390             case DBGCVAR_TYPE_GC_FLAT:
    4391             case DBGCVAR_TYPE_GC_FAR:
    4392             case DBGCVAR_TYPE_ANY:
    4393                 return VINF_SUCCESS;
    4394 
    4395             /* simply make it numeric. */
    4396             case DBGCVAR_TYPE_NUMBER:
    4397                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    4398                 pResult->u.u64Number = Symbol.Value;
    4399                 return VINF_SUCCESS;
    4400 
    4401             /* cast it. */
    4402 
    4403             case DBGCVAR_TYPE_GC_PHYS:
    4404                 VarTmp = *pResult;
    4405                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    4406 
    4407             case DBGCVAR_TYPE_HC_FAR:
    4408             case DBGCVAR_TYPE_HC_FLAT:
    4409                 VarTmp = *pResult;
    4410                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    4411 
    4412             case DBGCVAR_TYPE_HC_PHYS:
    4413                 VarTmp = *pResult;
    4414                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    4415 
    4416             default:
    4417                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    4418                 return VERR_INVALID_PARAMETER;
    4419         }
    4420     }
    4421 
    4422     return VERR_PARSE_NOT_IMPLEMENTED;
    4423 }
    4424 
    4425 
    4426 
    4427 /**
    4428  * Finds a routine.
    4429  *
    4430  * @returns Pointer to the command descriptor.
    4431  *          If the request was for an external command, the caller is responsible for
    4432  *          unlocking the external command list.
    4433  * @returns NULL if not found.
    4434  * @param   pDbgc       The debug console instance.
    4435  * @param   pachName    Pointer to the routine string (not terminated).
    4436  * @param   cchName     Length of the routine name.
    4437  * @param   fExternal   Whether or not the routine is external.
    4438  */
    4439 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
    4440 {
    4441     if (!fExternal)
    4442     {
    4443         /* emulation first, so commands can be overloaded (info ++). */
    4444         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    4445         unsigned cLeft = pDbgc->cEmulationCmds;
    4446         while (cLeft-- > 0)
    4447         {
    4448             if (    !strncmp(pachName, pCmd->pszCmd, cchName)
    4449                 &&  !pCmd->pszCmd[cchName])
    4450                 return pCmd;
    4451             pCmd++;
    4452         }
    4453 
    4454         for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
    4455         {
    4456             if (    !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
    4457                 &&  !g_aCmds[iCmd].pszCmd[cchName])
    4458                 return &g_aCmds[iCmd];
    4459         }
    4460     }
    4461     else
    4462     {
    4463         DBGCEXTCMDS_LOCK_RD();
    4464         for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
    4465         {
    4466             for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
    4467             {
    4468                 if (    !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
    4469                     &&  !pExtCmds->paCmds[iCmd].pszCmd[cchName])
    4470                     return &pExtCmds->paCmds[iCmd];
    4471             }
    4472         }
    4473         DBGCEXTCMDS_UNLOCK_RD();
    4474     }
    4475 
    4476     NOREF(pDbgc);
    4477     return NULL;
    4478 }
    4479 
    4480 
    44811552/**
    44821553 * Searches for an operator descriptor which matches the start of
     
    44911562 * @param   chPrev          The previous char. Some operators requires a blank in front of it.
    44921563 */
    4493 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
     1564PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
    44941565{
    44951566    PCDBGCOP    pOp = NULL;
     
    45281599}
    45291600
    4530 
    4531 /**
    4532  * Initalizes g_bmOperatorChars.
    4533  */
    4534 static void dbgcInitOpCharBitMap(void)
    4535 {
    4536     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    4537     for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)
    4538         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    4539 }
    4540 
    4541 
    4542 /**
    4543  * Checks whether the character may be the start of an operator.
    4544  *
    4545  * @returns true/false.
    4546  * @param   ch      The character.
    4547  */
    4548 DECLINLINE(bool) dbgcIsOpChar(char ch)
    4549 {
    4550     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    4551 }
    4552 
    4553 
    4554 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    4555 {
    4556     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    4557 
    4558     /*
    4559      * Removing any quoting and escapings.
    4560      */
    4561     char ch = *pszExpr;
    4562     if (ch == '"' || ch == '\'' || ch == '`')
    4563     {
    4564         if (pszExpr[--cchExpr] != ch)
    4565             return VERR_PARSE_UNBALANCED_QUOTE;
    4566         cchExpr--;
    4567         pszExpr++;
    4568 
    4569         /** @todo string unescaping. */
    4570     }
    4571     pszExpr[cchExpr] = '\0';
    4572 
    4573     /*
    4574      * Make the argument.
    4575      */
    4576     pArg->pDesc         = NULL;
    4577     pArg->pNext         = NULL;
    4578     pArg->enmType       = DBGCVAR_TYPE_STRING;
    4579     pArg->u.pszString   = pszExpr;
    4580     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    4581     pArg->u64Range      = cchExpr;
    4582 
    4583     NOREF(pDbgc);
    4584     return 0;
    4585 }
    4586 
    4587 
    4588 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    4589 {
    4590     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    4591     /*
    4592      * Convert to number.
    4593      */
    4594     uint64_t    u64 = 0;
    4595     char        ch;
    4596     while ((ch = *pszExpr) != '\0')
    4597     {
    4598         uint64_t    u64Prev = u64;
    4599         unsigned    u = ch - '0';
    4600         if (u < 10 && u < uBase)
    4601             u64 = u64 * uBase + u;
    4602         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    4603             u64 = u64 * uBase + u;
    4604         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    4605             u64 = u64 * uBase + u;
    4606         else
    4607             return VERR_PARSE_INVALID_NUMBER;
    4608 
    4609         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    4610         if (u64Prev != u64 / uBase)
    4611             return VERR_PARSE_NUMBER_TOO_BIG;
    4612 
    4613         /* next */
    4614         pszExpr++;
    4615     }
    4616 
    4617     /*
    4618      * Initialize the argument.
    4619      */
    4620     pArg->pDesc         = NULL;
    4621     pArg->pNext         = NULL;
    4622     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    4623     pArg->u.u64Number   = u64;
    4624     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    4625     pArg->u64Range      = 0;
    4626 
    4627     return 0;
    4628 }
    4629 
    4630 
    4631 /**
    4632  * Match variable and variable descriptor, promoting the variable if necessary.
    4633  *
    4634  * @returns VBox status code.
    4635  * @param   pDbgc       Debug console instanace.
    4636  * @param   pVar        Variable.
    4637  * @param   pVarDesc    Variable descriptor.
    4638  */
    4639 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    4640 {
    4641     /*
    4642      * (If match or promoted to match, return, else break.)
    4643      */
    4644     switch (pVarDesc->enmCategory)
    4645     {
    4646         /*
    4647          * Anything goes
    4648          */
    4649         case DBGCVAR_CAT_ANY:
    4650             return VINF_SUCCESS;
    4651 
    4652         /*
    4653          * Pointer with and without range.
    4654          * We can try resolve strings and symbols as symbols and
    4655          * promote numbers to flat GC pointers.
    4656          */
    4657         case DBGCVAR_CAT_POINTER_NO_RANGE:
    4658             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    4659                 return VERR_PARSE_NO_RANGE_ALLOWED;
    4660             /* fallthru */
    4661         case DBGCVAR_CAT_POINTER:
    4662             switch (pVar->enmType)
    4663             {
    4664                 case DBGCVAR_TYPE_GC_FLAT:
    4665                 case DBGCVAR_TYPE_GC_FAR:
    4666                 case DBGCVAR_TYPE_GC_PHYS:
    4667                 case DBGCVAR_TYPE_HC_FLAT:
    4668                 case DBGCVAR_TYPE_HC_FAR:
    4669                 case DBGCVAR_TYPE_HC_PHYS:
    4670                     return VINF_SUCCESS;
    4671 
    4672                 case DBGCVAR_TYPE_SYMBOL:
    4673                 case DBGCVAR_TYPE_STRING:
    4674                 {
    4675                     DBGCVAR Var;
    4676                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    4677                     if (VBOX_SUCCESS(rc))
    4678                     {
    4679                         /* deal with range */
    4680                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    4681                         {
    4682                             Var.enmRangeType = pVar->enmRangeType;
    4683                             Var.u64Range = pVar->u64Range;
    4684                         }
    4685                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    4686                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    4687                         *pVar = Var;
    4688                         return rc;
    4689                     }
    4690                     break;
    4691                 }
    4692 
    4693                 case DBGCVAR_TYPE_NUMBER:
    4694                 {
    4695                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    4696                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    4697                     pVar->u.GCFlat = GCPtr;
    4698                     return VINF_SUCCESS;
    4699                 }
    4700 
    4701                 default:
    4702                     break;
    4703             }
    4704             break;
    4705 
    4706         /*
    4707          * GC pointer with and without range.
    4708          * We can try resolve strings and symbols as symbols and
    4709          * promote numbers to flat GC pointers.
    4710          */
    4711         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    4712             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    4713                 return VERR_PARSE_NO_RANGE_ALLOWED;
    4714             /* fallthru */
    4715         case DBGCVAR_CAT_GC_POINTER:
    4716             switch (pVar->enmType)
    4717             {
    4718                 case DBGCVAR_TYPE_GC_FLAT:
    4719                 case DBGCVAR_TYPE_GC_FAR:
    4720                 case DBGCVAR_TYPE_GC_PHYS:
    4721                     return VINF_SUCCESS;
    4722 
    4723                 case DBGCVAR_TYPE_HC_FLAT:
    4724                 case DBGCVAR_TYPE_HC_FAR:
    4725                 case DBGCVAR_TYPE_HC_PHYS:
    4726                     return VERR_PARSE_CONVERSION_FAILED;
    4727 
    4728                 case DBGCVAR_TYPE_SYMBOL:
    4729                 case DBGCVAR_TYPE_STRING:
    4730                 {
    4731                     DBGCVAR Var;
    4732                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    4733                     if (VBOX_SUCCESS(rc))
    4734                     {
    4735                         /* deal with range */
    4736                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    4737                         {
    4738                             Var.enmRangeType = pVar->enmRangeType;
    4739                             Var.u64Range = pVar->u64Range;
    4740                         }
    4741                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    4742                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    4743                         *pVar = Var;
    4744                         return rc;
    4745                     }
    4746                     break;
    4747                 }
    4748 
    4749                 case DBGCVAR_TYPE_NUMBER:
    4750                 {
    4751                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    4752                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    4753                     pVar->u.GCFlat = GCPtr;
    4754                     return VINF_SUCCESS;
    4755                 }
    4756 
    4757                 default:
    4758                     break;
    4759             }
    4760             break;
    4761 
    4762         /*
    4763          * Number with or without a range.
    4764          * Numbers can be resolved from symbols, but we cannot demote a pointer
    4765          * to a number.
    4766          */
    4767         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    4768             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    4769                 return VERR_PARSE_NO_RANGE_ALLOWED;
    4770             /* fallthru */
    4771         case DBGCVAR_CAT_NUMBER:
    4772             switch (pVar->enmType)
    4773             {
    4774                 case DBGCVAR_TYPE_NUMBER:
    4775                     return VINF_SUCCESS;
    4776 
    4777                 case DBGCVAR_TYPE_SYMBOL:
    4778                 case DBGCVAR_TYPE_STRING:
    4779                 {
    4780                     DBGCVAR Var;
    4781                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    4782                     if (VBOX_SUCCESS(rc))
    4783                     {
    4784                         *pVar = Var;
    4785                         return rc;
    4786                     }
    4787                     break;
    4788                 }
    4789                 default:
    4790                     break;
    4791             }
    4792             break;
    4793 
    4794         /*
    4795          * Strings can easily be made from symbols (and of course strings).
    4796          * We could consider reformatting the addresses and numbers into strings later...
    4797          */
    4798         case DBGCVAR_CAT_STRING:
    4799             switch (pVar->enmType)
    4800             {
    4801                 case DBGCVAR_TYPE_SYMBOL:
    4802                     pVar->enmType = DBGCVAR_TYPE_STRING;
    4803                     /* fallthru */
    4804                 case DBGCVAR_TYPE_STRING:
    4805                     return VINF_SUCCESS;
    4806                 default:
    4807                     break;
    4808             }
    4809             break;
    4810 
    4811         /*
    4812          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    4813          */
    4814         case DBGCVAR_CAT_SYMBOL:
    4815             switch (pVar->enmType)
    4816             {
    4817                 case DBGCVAR_TYPE_STRING:
    4818                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    4819                     /* fallthru */
    4820                 case DBGCVAR_TYPE_SYMBOL:
    4821                     return VINF_SUCCESS;
    4822                 default:
    4823                     break;
    4824             }
    4825             break;
    4826 
    4827         /*
    4828          * Anything else is illegal.
    4829          */
    4830         default:
    4831             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    4832             break;
    4833     }
    4834 
    4835     return VERR_PARSE_NO_ARGUMENT_MATCH;
    4836 }
    4837 
    4838 
    4839 /**
    4840  * Matches a set of variables with a description set.
    4841  *
    4842  * This is typically used for routine arguments before a call. The effects in
    4843  * addition to the validation, is that some variables might be propagated to
    4844  * other types in order to match the description. The following transformations
    4845  * are supported:
    4846  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    4847  *      - Number to a pointer.
    4848  *      - Pointer to a number.
    4849  * @returns 0 on success with paVars.
    4850  * @returns VBox error code for match errors.
    4851  */
    4852 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    4853                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    4854                                 PDBGCVAR paVars, unsigned cVars)
    4855 {
    4856     /*
    4857      * Just do basic min / max checks first.
    4858      */
    4859     if (cVars < cVarsMin)
    4860         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    4861     if (cVars > cVarsMax)
    4862         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    4863 
    4864     /*
    4865      * Match the descriptors and actual variables.
    4866      */
    4867     PCDBGCVARDESC   pPrevDesc = NULL;
    4868     unsigned        cCurDesc = 0;
    4869     unsigned        iVar = 0;
    4870     unsigned        iVarDesc = 0;
    4871     while (iVar < cVars)
    4872     {
    4873         /* walk the descriptors */
    4874         if (iVarDesc >= cVarDescs)
    4875             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    4876         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    4877                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    4878             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    4879         {
    4880             iVarDesc++;
    4881             if (iVarDesc >= cVarDescs)
    4882                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    4883             cCurDesc = 0;
    4884         }
    4885 
    4886         /*
    4887          * Skip thru optional arguments until we find something which matches
    4888          * or can easily be promoted to what the descriptor want.
    4889          */
    4890         for (;;)
    4891         {
    4892             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    4893             if (VBOX_SUCCESS(rc))
    4894             {
    4895                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    4896                 cCurDesc++;
    4897                 break;
    4898             }
    4899 
    4900             /* can we advance? */
    4901             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    4902                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    4903             if (++iVarDesc >= cVarDescs)
    4904                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    4905             cCurDesc = 0;
    4906         }
    4907 
    4908         /* next var */
    4909         iVar++;
    4910     }
    4911 
    4912     /*
    4913      * Check that the rest of the descriptors are optional.
    4914      */
    4915     while (iVarDesc < cVarDescs)
    4916     {
    4917         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    4918             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    4919         cCurDesc = 0;
    4920 
    4921         /* next */
    4922         iVarDesc++;
    4923     }
    4924 
    4925     return 0;
    4926 }
    4927 
    4928 
    4929 /**
    4930  * Evaluates one argument with respect to unary operators.
    4931  *
    4932  * @returns 0 on success. pResult contains the result.
    4933  * @returns VBox error code on parse or other evaluation error.
    4934  *
    4935  * @param   pDbgc       Debugger console instance data.
    4936  * @param   pszExpr     The expression string.
    4937  * @param   pResult     Where to store the result of the expression evaluation.
    4938  */
    4939 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    4940 {
    4941     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    4942 
    4943     /*
    4944      * The state of the expression is now such that it will start by zero or more
    4945      * unary operators and being followed by an expression of some kind.
    4946      * The expression is either plain or in parenthesis.
    4947      *
    4948      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    4949      * ASSUME: unary operators are all of equal precedence.
    4950      */
    4951     int         rc = 0;
    4952     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    4953     if (pOp)
    4954     {
    4955         /* binary operators means syntax error. */
    4956         if (pOp->fBinary)
    4957             return VERR_PARSE_UNEXPECTED_OPERATOR;
    4958 
    4959         /*
    4960          * If the next expression (the one following the unary operator) is in a
    4961          * parenthesis a full eval is needed. If not the unary eval will suffice.
    4962          */
    4963         /* calc and strip next expr. */
    4964         char *pszExpr2 = pszExpr + pOp->cchName;
    4965         while (isblank(*pszExpr2))
    4966             pszExpr2++;
    4967 
    4968         if (!*pszExpr2)
    4969             rc = VERR_PARSE_EMPTY_ARGUMENT;
    4970         else
    4971         {
    4972             DBGCVAR Arg;
    4973             if (*pszExpr2 == '(')
    4974                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    4975             else
    4976                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    4977             if (VBOX_SUCCESS(rc))
    4978                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    4979         }
    4980     }
    4981     else
    4982     {
    4983         /*
    4984          * Didn't find any operators, so it we have to check if this can be an
    4985          * function call before assuming numeric or string expression.
    4986          *
    4987          * (ASSUMPTIONS:)
    4988          * A function name only contains alphanumerical chars and it can not start
    4989          * with a numerical character.
    4990          * Immediately following the name is a parenthesis which must over
    4991          * the remaining part of the expression.
    4992          */
    4993         bool    fExternal = *pszExpr == '.';
    4994         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    4995         char   *pszFunEnd = NULL;
    4996         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    4997         {
    4998             pszFunEnd = pszExpr + 1;
    4999             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    5000                 pszFunEnd++;
    5001             if (*pszFunEnd != '(')
    5002                 pszFunEnd = NULL;
    5003         }
    5004 
    5005         if (pszFunEnd)
    5006         {
    5007             /*
    5008              * Ok, it's a function call.
    5009              */
    5010             if (fExternal)
    5011                 pszExpr++, cchExpr--;
    5012             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    5013             if (!pFun)
    5014                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    5015             if (!pFun->pResultDesc)
    5016                 return VERR_PARSE_NOT_A_FUNCTION;
    5017 
    5018             /*
    5019              * Parse the expression in parenthesis.
    5020              */
    5021             cchExpr -= pszFunEnd - pszExpr;
    5022             pszExpr = pszFunEnd;
    5023             /** @todo implement multiple arguments. */
    5024             DBGCVAR     Arg;
    5025             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    5026             if (!rc)
    5027             {
    5028                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    5029                 if (!rc)
    5030                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    5031             }
    5032             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    5033                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    5034         }
    5035         else
    5036         {
    5037             /*
    5038              * Didn't find any operators, so it must be a plain expression.
    5039              * This might be numeric or a string expression.
    5040              */
    5041             char ch  = pszExpr[0];
    5042             char ch2 = pszExpr[1];
    5043             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    5044                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    5045             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    5046                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    5047             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    5048                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    5049             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    5050             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    5051             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    5052             else
    5053             {
    5054                 /*
    5055                  * Hexadecimal number or a string?
    5056                  */
    5057                 char *psz = pszExpr;
    5058                 while (isxdigit(*psz))
    5059                     psz++;
    5060                 if (!*psz)
    5061                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    5062                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    5063                 {
    5064                     *psz = '\0';
    5065                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    5066                 }
    5067                 else
    5068                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    5069             }
    5070         }
    5071     }
    5072 
    5073     return rc;
    5074 }
    5075 
    5076 
    5077 /**
    5078  * Evaluates one argument.
    5079  *
    5080  * @returns 0 on success. pResult contains the result.
    5081  * @returns VBox error code on parse or other evaluation error.
    5082  *
    5083  * @param   pDbgc       Debugger console instance data.
    5084  * @param   pszExpr     The expression string.
    5085  * @param   pResult     Where to store the result of the expression evaluation.
    5086  */
    5087 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    5088 {
    5089     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    5090     /*
    5091      * First we need to remove blanks in both ends.
    5092      * ASSUMES: There is no quoting unless the entire expression is a string.
    5093      */
    5094 
    5095     /* stripping. */
    5096     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    5097         pszExpr[--cchExpr] = '\0';
    5098     while (isblank(*pszExpr))
    5099         pszExpr++, cchExpr--;
    5100     if (!*pszExpr)
    5101         return VERR_PARSE_EMPTY_ARGUMENT;
    5102 
    5103     /* it there is any kind of quoting in the expression, it's string meat. */
    5104     if (strpbrk(pszExpr, "\"'`"))
    5105         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    5106 
    5107     /*
    5108      * Check if there are any parenthesis which needs removing.
    5109      */
    5110     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    5111     {
    5112         do
    5113         {
    5114             unsigned cPar = 1;
    5115             char    *psz = pszExpr + 1;
    5116             char     ch;
    5117             while ((ch = *psz) != '\0')
    5118             {
    5119                 if (ch == '(')
    5120                     cPar++;
    5121                 else if (ch == ')')
    5122                 {
    5123                     if (cPar <= 0)
    5124                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    5125                     cPar--;
    5126                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    5127                         break;
    5128                 }
    5129                 /* next */
    5130                 psz++;
    5131             }
    5132             if (ch)
    5133                 break;
    5134 
    5135             /* remove the parenthesis. */
    5136             pszExpr++;
    5137             cchExpr -= 2;
    5138             pszExpr[cchExpr] = '\0';
    5139 
    5140             /* strip blanks. */
    5141             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    5142                 pszExpr[--cchExpr] = '\0';
    5143             while (isblank(*pszExpr))
    5144                 pszExpr++, cchExpr--;
    5145             if (!*pszExpr)
    5146                 return VERR_PARSE_EMPTY_ARGUMENT;
    5147         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    5148     }
    5149 
    5150     /* tabs to spaces. */
    5151     char *psz = pszExpr;
    5152     while ((psz = strchr(psz, '\t')) != NULL)
    5153         *psz = ' ';
    5154 
    5155     /*
    5156      * Now, we need to look for the binary operator with the lowest precedence.
    5157      *
    5158      * If there are no operators we're left with a simple expression which we
    5159      * evaluate with respect to unary operators
    5160      */
    5161     char       *pszOpSplit = NULL;
    5162     PCDBGCOP    pOpSplit = NULL;
    5163     unsigned    cBinaryOps = 0;
    5164     unsigned    cPar = 0;
    5165     char        ch;
    5166     char        chPrev = ' ';
    5167     bool        fBinary = false;
    5168     psz = pszExpr;
    5169 
    5170     while ((ch = *psz) != '\0')
    5171     {
    5172         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    5173         /*
    5174          * Parenthesis.
    5175          */
    5176         if (ch == '(')
    5177         {
    5178             cPar++;
    5179             fBinary = false;
    5180         }
    5181         else if (ch == ')')
    5182         {
    5183             if (cPar <= 0)
    5184                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    5185             cPar--;
    5186             fBinary = true;
    5187         }
    5188         /*
    5189          * Potential operator.
    5190          */
    5191         else if (cPar == 0 && !isblank(ch))
    5192         {
    5193             PCDBGCOP pOp = dbgcIsOpChar(ch)
    5194                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    5195                          : NULL;
    5196             if (pOp)
    5197             {
    5198                 /* If not the right kind of operator we've got a syntax error. */
    5199                 if (pOp->fBinary != fBinary)
    5200                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    5201 
    5202                 /*
    5203                  * Update the parse state and skip the operator.
    5204                  */
    5205                 if (!pOpSplit)
    5206                 {
    5207                     pOpSplit = pOp;
    5208                     pszOpSplit = psz;
    5209                     cBinaryOps = fBinary;
    5210                 }
    5211                 else if (fBinary)
    5212                 {
    5213                     cBinaryOps++;
    5214                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    5215                     {
    5216                         pOpSplit = pOp;
    5217                         pszOpSplit = psz;
    5218                     }
    5219                 }
    5220 
    5221                 psz += pOp->cchName - 1;
    5222                 fBinary = false;
    5223             }
    5224             else
    5225                 fBinary = true;
    5226         }
    5227 
    5228         /* next */
    5229         psz++;
    5230         chPrev = ch;
    5231     } /* parse loop. */
    5232 
    5233 
    5234     /*
    5235      * Either we found an operator to divide the expression by
    5236      * or we didn't find any. In the first case it's divide and
    5237      * conquer. In the latter it's a single expression which
    5238      * needs dealing with its unary operators if any.
    5239      */
    5240     int rc;
    5241     if (    cBinaryOps
    5242         &&  pOpSplit->fBinary)
    5243     {
    5244         /* process 1st sub expression. */
    5245         *pszOpSplit = '\0';
    5246         DBGCVAR     Arg1;
    5247         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    5248         if (VBOX_SUCCESS(rc))
    5249         {
    5250             /* process 2nd sub expression. */
    5251             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    5252             DBGCVAR     Arg2;
    5253             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    5254             if (VBOX_SUCCESS(rc))
    5255                 /* apply the operator. */
    5256                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    5257         }
    5258     }
    5259     else if (cBinaryOps)
    5260     {
    5261         /* process sub expression. */
    5262         pszOpSplit += pOpSplit->cchName;
    5263         DBGCVAR     Arg;
    5264         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    5265         if (VBOX_SUCCESS(rc))
    5266             /* apply the operator. */
    5267             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    5268     }
    5269     else
    5270         /* plain expression or using unary operators perhaps with paratheses. */
    5271         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    5272 
    5273     return rc;
    5274 }
    5275 
    5276 
    5277 /**
    5278  * Parses the arguments of one command.
    5279  *
    5280  * @returns 0 on success.
    5281  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    5282  * @param   pDbgc       Debugger console instance data.
    5283  * @param   pCmd        Pointer to the command descriptor.
    5284  * @param   pszArg      Pointer to the arguments to parse.
    5285  * @param   paArgs      Where to store the parsed arguments.
    5286  * @param   cArgs       Size of the paArgs array.
    5287  * @param   pcArgs      Where to store the number of arguments.
    5288  *                      In the event of an error this is used to store the index of the offending argument.
    5289  */
    5290 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    5291 {
    5292     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    5293     /*
    5294      * Check if we have any argument and if the command takes any.
    5295      */
    5296     *pcArgs = 0;
    5297     /* strip leading blanks. */
    5298     while (*pszArgs && isblank(*pszArgs))
    5299         pszArgs++;
    5300     if (!*pszArgs)
    5301     {
    5302         if (!pCmd->cArgsMin)
    5303             return 0;
    5304         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    5305     }
    5306     /** @todo fixme - foo() doesn't work. */
    5307     if (!pCmd->cArgsMax)
    5308         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    5309 
    5310     /*
    5311      * This is a hack, it's "temporary" and should go away "when" the parser is
    5312      * modified to match arguments while parsing.
    5313      */
    5314     if (    pCmd->cArgsMax == 1
    5315         &&  pCmd->cArgsMin == 1
    5316         &&  pCmd->cArgDescs == 1
    5317         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    5318         &&  cArgs >= 1)
    5319     {
    5320         *pcArgs = 1;
    5321         RTStrStripR(pszArgs);
    5322         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    5323     }
    5324 
    5325 
    5326     /*
    5327      * The parse loop.
    5328      */
    5329     PDBGCVAR        pArg0 = &paArgs[0];
    5330     PDBGCVAR        pArg = pArg0;
    5331     *pcArgs = 0;
    5332     do
    5333     {
    5334         /*
    5335          * Can we have another argument?
    5336          */
    5337         if (*pcArgs >= pCmd->cArgsMax)
    5338             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    5339         if (pArg >= &paArgs[cArgs])
    5340             return VERR_PARSE_ARGUMENT_OVERFLOW;
    5341 
    5342         /*
    5343          * Find the end of the argument.
    5344          */
    5345         int     cPar    = 0;
    5346         char    chQuote = '\0';
    5347         char   *pszEnd  = NULL;
    5348         char   *psz     = pszArgs;
    5349         char    ch;
    5350         bool    fBinary = false;
    5351         for (;;)
    5352         {
    5353             /*
    5354              * Check for the end.
    5355              */
    5356             if ((ch = *psz) == '\0')
    5357             {
    5358                 if (chQuote)
    5359                     return VERR_PARSE_UNBALANCED_QUOTE;
    5360                 if (cPar)
    5361                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    5362                 pszEnd = psz;
    5363                 break;
    5364             }
    5365             /*
    5366              * When quoted we ignore everything but the quotation char.
    5367              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    5368              */
    5369             else if (ch == '\'' || ch == '"' || ch == '`')
    5370             {
    5371                 if (chQuote)
    5372                 {
    5373                     /* end quote? */
    5374                     if (ch == chQuote)
    5375                     {
    5376                         if (psz[1] == ch)
    5377                             psz++;          /* skip the escaped quote char */
    5378                         else
    5379                             chQuote = '\0'; /* end of quoted string. */
    5380                     }
    5381                 }
    5382                 else
    5383                     chQuote = ch;           /* open new quote */
    5384             }
    5385             /*
    5386              * Parenthesis can of course be nested.
    5387              */
    5388             else if (ch == '(')
    5389             {
    5390                 cPar++;
    5391                 fBinary = false;
    5392             }
    5393             else if (ch == ')')
    5394             {
    5395                 if (!cPar)
    5396                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    5397                 cPar--;
    5398                 fBinary = true;
    5399             }
    5400             else if (!chQuote && !cPar)
    5401             {
    5402                 /*
    5403                  * Encountering blanks may mean the end of it all. A binary operator
    5404                  * will force continued parsing.
    5405                  */
    5406                 if (isblank(*psz))
    5407                 {
    5408                     pszEnd = psz++;         /* just in case. */
    5409                     while (isblank(*psz))
    5410                         psz++;
    5411                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    5412                     if (!pOp || pOp->fBinary != fBinary)
    5413                         break;              /* the end. */
    5414                     psz += pOp->cchName;
    5415                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    5416                         psz++;
    5417                     fBinary = false;
    5418                     continue;
    5419                 }
    5420 
    5421                 /*
    5422                  * Look for operators without a space up front.
    5423                  */
    5424                 if (dbgcIsOpChar(*psz))
    5425                 {
    5426                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    5427                     if (pOp)
    5428                     {
    5429                         if (pOp->fBinary != fBinary)
    5430                         {
    5431                             pszEnd = psz;
    5432                             /** @todo this is a parsing error really. */
    5433                             break;              /* the end. */
    5434                         }
    5435                         psz += pOp->cchName;
    5436                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    5437                             psz++;
    5438                         fBinary = false;
    5439                         continue;
    5440                     }
    5441                 }
    5442                 fBinary = true;
    5443             }
    5444 
    5445             /* next char */
    5446             psz++;
    5447         }
    5448         *pszEnd = '\0';
    5449         /* (psz = next char to process) */
    5450 
    5451         /*
    5452          * Parse and evaluate the argument.
    5453          */
    5454         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    5455         if (VBOX_FAILURE(rc))
    5456             return rc;
    5457 
    5458         /*
    5459          * Next.
    5460          */
    5461         pArg++;
    5462         (*pcArgs)++;
    5463         pszArgs = psz;
    5464         while (*pszArgs && isblank(*pszArgs))
    5465             pszArgs++;
    5466     } while (*pszArgs);
    5467 
    5468     /*
    5469      * Match the arguments.
    5470      */
    5471     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    5472 }
    5473 
    5474 
    5475 /**
    5476  * Process one command.
    5477  *
    5478  * @returns VBox status code. Any error indicates the termination of the console session.
    5479  * @param   pDbgc   Debugger console instance data.
    5480  * @param   pszCmd  Pointer to the command.
    5481  * @param   cchCmd  Length of the command.
    5482  */
    5483 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    5484 {
    5485     char *pszCmdInput = pszCmd;
    5486 
    5487     /*
    5488      * Skip blanks.
    5489      */
    5490     while (isblank(*pszCmd))
    5491         pszCmd++, cchCmd--;
    5492 
    5493     /* external command? */
    5494     bool fExternal = *pszCmd == '.';
    5495     if (fExternal)
    5496         pszCmd++, cchCmd--;
    5497 
    5498     /*
    5499      * Find arguments.
    5500      */
    5501     char *pszArgs = pszCmd;
    5502     while (isalnum(*pszArgs))
    5503         pszArgs++;
    5504     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    5505     {
    5506         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    5507         return 0;
    5508     }
    5509 
    5510     /*
    5511      * Find the command.
    5512      */
    5513     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    5514     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    5515         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    5516 
    5517     /*
    5518      * Parse arguments (if any).
    5519      */
    5520     unsigned    cArgs;
    5521     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    5522 
    5523     /*
    5524      * Execute the command.
    5525      */
    5526     if (!rc)
    5527     {
    5528         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    5529     }
    5530     else
    5531     {
    5532         /* report parse / eval error. */
    5533         switch (rc)
    5534         {
    5535             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    5536                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5537                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    5538                 break;
    5539             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    5540                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5541                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    5542                 break;
    5543             case VERR_PARSE_ARGUMENT_OVERFLOW:
    5544                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5545                     "Syntax error: Too many arguments.\n");
    5546                 break;
    5547             case VERR_PARSE_UNBALANCED_QUOTE:
    5548                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5549                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    5550                 break;
    5551             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    5552                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5553                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    5554                 break;
    5555             case VERR_PARSE_EMPTY_ARGUMENT:
    5556                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5557                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    5558                 break;
    5559             case VERR_PARSE_UNEXPECTED_OPERATOR:
    5560                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5561                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    5562                 break;
    5563             case VERR_PARSE_INVALID_NUMBER:
    5564                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5565                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    5566                 break;
    5567             case VERR_PARSE_NUMBER_TOO_BIG:
    5568                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5569                     "Error: Numeric overflow (argument %d).\n", cArgs);
    5570                 break;
    5571             case VERR_PARSE_INVALID_OPERATION:
    5572                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5573                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    5574                 break;
    5575             case VERR_PARSE_FUNCTION_NOT_FOUND:
    5576                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5577                     "Error: Function not found (argument %d).\n", cArgs);
    5578                 break;
    5579             case VERR_PARSE_NOT_A_FUNCTION:
    5580                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5581                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    5582                 break;
    5583             case VERR_PARSE_NO_MEMORY:
    5584                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5585                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    5586                 break;
    5587             case VERR_PARSE_INCORRECT_ARG_TYPE:
    5588                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5589                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    5590                 break;
    5591             case VERR_PARSE_VARIABLE_NOT_FOUND:
    5592                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5593                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    5594                 break;
    5595             case VERR_PARSE_CONVERSION_FAILED:
    5596                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5597                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    5598                 break;
    5599             case VERR_PARSE_NOT_IMPLEMENTED:
    5600                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5601                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    5602                 break;
    5603             case VERR_PARSE_BAD_RESULT_TYPE:
    5604                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5605                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    5606                 break;
    5607             case VERR_PARSE_WRITEONLY_SYMBOL:
    5608                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5609                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    5610                 break;
    5611 
    5612             default:
    5613                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5614                     "Error: Unknown error %d!\n", rc);
    5615                 return rc;
    5616         }
    5617 
    5618         /*
    5619          * Parse errors are non fatal.
    5620          */
    5621         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    5622             rc = 0;
    5623     }
    5624 
    5625     return rc;
    5626 }
    5627 
    5628 
    5629 /**
    5630  * Process all commands current in the buffer.
    5631  *
    5632  * @returns VBox status code. Any error indicates the termination of the console session.
    5633  * @param   pDbgc   Debugger console instance data.
    5634  */
    5635 static int dbgcProcessCommands(PDBGC pDbgc)
    5636 {
    5637     int rc = 0;
    5638     while (pDbgc->cInputLines)
    5639     {
    5640         /*
    5641          * Empty the log buffer if we're hooking the log.
    5642          */
    5643         if (pDbgc->fLog)
    5644         {
    5645             rc = dbgcProcessLog(pDbgc);
    5646             if (VBOX_FAILURE(rc))
    5647                 break;
    5648         }
    5649 
    5650         if (pDbgc->iRead == pDbgc->iWrite)
    5651         {
    5652             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    5653             pDbgc->cInputLines = 0;
    5654             return 0;
    5655         }
    5656 
    5657         /*
    5658          * Copy the command to the parse buffer.
    5659          */
    5660         char    ch;
    5661         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    5662         char   *pszTrg = &pDbgc->achScratch[0];
    5663         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    5664         {
    5665             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    5666                 psz = &pDbgc->achInput[0];
    5667 
    5668             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    5669             {
    5670                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    5671                 pDbgc->cInputLines = 0;
    5672                 return 0;
    5673             }
    5674 
    5675             pszTrg++;
    5676         }
    5677         *pszTrg = '\0';
    5678 
    5679         /*
    5680          * Advance the buffer.
    5681          */
    5682         pDbgc->iRead = psz - &pDbgc->achInput[0];
    5683         if (ch == '\n')
    5684             pDbgc->cInputLines--;
    5685 
    5686         /*
    5687          * Parse and execute this command.
    5688          */
    5689         pDbgc->pszScratch = psz;
    5690         pDbgc->iArg       = 0;
    5691         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    5692         if (rc)
    5693             break;
    5694     }
    5695 
    5696     return rc;
    5697 }
    5698 
    5699 
    5700 /**
    5701  * Reads input, parses it and executes commands on '\n'.
    5702  *
    5703  * @returns VBox status.
    5704  * @param   pDbgc   Debugger console instance data.
    5705  */
    5706 static int dbgcProcessInput(PDBGC pDbgc)
    5707 {
    5708     /*
    5709      * We know there's input ready, so let's read it first.
    5710      */
    5711     int rc = dbgcInputRead(pDbgc);
    5712     if (VBOX_FAILURE(rc))
    5713         return rc;
    5714 
    5715     /*
    5716      * Now execute any ready commands.
    5717      */
    5718     if (pDbgc->cInputLines)
    5719     {
    5720         /** @todo this fReady stuff is broken. */
    5721         pDbgc->fReady = false;
    5722         rc = dbgcProcessCommands(pDbgc);
    5723         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    5724             pDbgc->fReady = true;
    5725         if (    VBOX_SUCCESS(rc)
    5726             &&  pDbgc->iRead == pDbgc->iWrite
    5727             &&  pDbgc->fReady)
    5728             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    5729     }
    5730 
    5731     return rc;
    5732 }
    5733 
    5734 
    5735 /**
    5736  * Gets the event context identifier string.
    5737  * @returns Read only string.
    5738  * @param   enmCtx          The context.
    5739  */
    5740 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    5741 {
    5742     switch (enmCtx)
    5743     {
    5744         case DBGFEVENTCTX_RAW:      return "raw";
    5745         case DBGFEVENTCTX_REM:      return "rem";
    5746         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    5747         case DBGFEVENTCTX_HYPER:    return "hyper";
    5748         case DBGFEVENTCTX_OTHER:    return "other";
    5749 
    5750         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    5751         default:
    5752             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    5753             return "!Unknown Event Ctx!";
    5754     }
    5755 }
    5756 
    5757 
    5758 /**
    5759  * Processes debugger events.
    5760  *
    5761  * @returns VBox status.
    5762  * @param   pDbgc   DBGC Instance data.
    5763  * @param   pEvent  Pointer to event data.
    5764  */
    5765 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    5766 {
    5767     /*
    5768      * Flush log first.
    5769      */
    5770     if (pDbgc->fLog)
    5771     {
    5772         int rc = dbgcProcessLog(pDbgc);
    5773         if (VBOX_FAILURE(rc))
    5774             return rc;
    5775     }
    5776 
    5777     /*
    5778      * Process the event.
    5779      */
    5780     pDbgc->pszScratch = &pDbgc->achInput[0];
    5781     pDbgc->iArg       = 0;
    5782     bool fPrintPrompt = true;
    5783     int rc = VINF_SUCCESS;
    5784     switch (pEvent->enmType)
    5785     {
    5786         /*
    5787          * The first part is events we have initiated with commands.
    5788          */
    5789         case DBGFEVENT_HALT_DONE:
    5790         {
    5791             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    5792                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    5793             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    5794             if (VBOX_SUCCESS(rc))
    5795                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5796             break;
    5797         }
    5798 
    5799 
    5800         /*
    5801          * The second part is events which can occur at any time.
    5802          */
    5803         case DBGFEVENT_FATAL_ERROR:
    5804         {
    5805             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    5806                                          dbgcGetEventCtx(pEvent->enmCtx));
    5807             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    5808             if (VBOX_SUCCESS(rc))
    5809                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5810             break;
    5811         }
    5812 
    5813         case DBGFEVENT_BREAKPOINT:
    5814         case DBGFEVENT_BREAKPOINT_HYPER:
    5815         {
    5816             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    5817             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    5818 
    5819             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    5820             switch (rc)
    5821             {
    5822                 case VERR_DBGC_BP_NOT_FOUND:
    5823                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    5824                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    5825                     break;
    5826 
    5827                 case VINF_DBGC_BP_NO_COMMAND:
    5828                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    5829                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    5830                     break;
    5831 
    5832                 case VINF_BUFFER_OVERFLOW:
    5833                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    5834                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    5835                     break;
    5836 
    5837                 default:
    5838                     break;
    5839             }
    5840             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    5841                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5842             else
    5843                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    5844             break;
    5845         }
    5846 
    5847         case DBGFEVENT_STEPPED:
    5848         case DBGFEVENT_STEPPED_HYPER:
    5849         {
    5850             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    5851 
    5852             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    5853             if (VBOX_SUCCESS(rc))
    5854                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5855             break;
    5856         }
    5857 
    5858         case DBGFEVENT_ASSERTION_HYPER:
    5859         {
    5860             pDbgc->fRegCtxGuest = false;
    5861 
    5862             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5863                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    5864                                          "%s"
    5865                                          "%s"
    5866                                          "\n",
    5867                                          dbgcGetEventCtx(pEvent->enmCtx),
    5868                                          pEvent->u.Assert.pszMsg1,
    5869                                          pEvent->u.Assert.pszMsg2);
    5870             if (VBOX_SUCCESS(rc))
    5871                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5872             break;
    5873         }
    5874 
    5875         case DBGFEVENT_DEV_STOP:
    5876         {
    5877             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5878                                          "\n"
    5879                                          "dbgf event: DBGFSTOP (%s)\n"
    5880                                          "File:     %s\n"
    5881                                          "Line:     %d\n"
    5882                                          "Function: %s\n",
    5883                                          dbgcGetEventCtx(pEvent->enmCtx),
    5884                                          pEvent->u.Src.pszFile,
    5885                                          pEvent->u.Src.uLine,
    5886                                          pEvent->u.Src.pszFunction);
    5887             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    5888                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    5889                                          "Message:  %s\n",
    5890                                              pEvent->u.Src.pszMessage);
    5891             if (VBOX_SUCCESS(rc))
    5892                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    5893             break;
    5894         }
    5895 
    5896 
    5897         case DBGFEVENT_INVALID_COMMAND:
    5898         {
    5899             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    5900             fPrintPrompt = !pDbgc->fReady;
    5901             break;
    5902         }
    5903 
    5904         case DBGFEVENT_TERMINATING:
    5905         {
    5906             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    5907             rc = VERR_GENERAL_FAILURE;
    5908             break;
    5909         }
    5910 
    5911 
    5912         default:
    5913         {
    5914             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    5915             fPrintPrompt = !pDbgc->fReady;
    5916             break;
    5917         }
    5918     }
    5919 
    5920     /*
    5921      * Prompt, anyone?
    5922      */
    5923     if (fPrintPrompt && VBOX_SUCCESS(rc))
    5924     {
    5925         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    5926     }
    5927 
    5928     return rc;
    5929 }
    5930 
    5931 
    5932 
    5933 
    5934 
    5935 /**
    5936  * Make a console instance.
    5937  *
    5938  * This will not return until either an 'exit' command is issued or a error code
    5939  * indicating connection loss is encountered.
    5940  *
    5941  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    5942  * @returns The VBox status code causing the console termination.
    5943  *
    5944  * @param   pVM         VM Handle.
    5945  * @param   pBack       Pointer to the backend structure. This must contain
    5946  *                      a full set of function pointers to service the console.
    5947  * @param   fFlags      Reserved, must be zero.
    5948  * @remark  A forced termination of the console is easiest done by forcing the
    5949  *          callbacks to return fatal failures.
    5950  */
    5951 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    5952 {
    5953     /*
    5954      * Validate input.
    5955      */
    5956     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    5957     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    5958     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    5959 
    5960     /*
    5961      * Allocate and initialize instance data
    5962      */
    5963     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    5964     if (!pDbgc)
    5965         return VERR_NO_MEMORY;
    5966 
    5967     pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    5968     pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
    5969     pDbgc->CmdHlp.pfnPrintf     = dbgcHlpPrintf;
    5970     pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
    5971     pDbgc->CmdHlp.pfnVBoxError  = dbgcHlpVBoxError;
    5972     pDbgc->CmdHlp.pfnMemRead    = dbgcHlpMemRead;
    5973     pDbgc->CmdHlp.pfnMemWrite   = dbgcHlpMemWrite;
    5974     pDbgc->CmdHlp.pfnEval       = dbgcHlpEval;
    5975     pDbgc->CmdHlp.pfnExec       = dbgcHlpExec;
    5976     pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    5977     pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
    5978     pDbgc->pBack            = pBack;
    5979     pDbgc->pVM              = NULL;
    5980     pDbgc->pszEmulation     = "CodeView/WinDbg";
    5981     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    5982     pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    5983     //pDbgc->fLog             = false;
    5984     pDbgc->fRegCtxGuest     = true;
    5985     pDbgc->fRegTerse        = true;
    5986     //pDbgc->DisasmPos        = {0};
    5987     //pDbgc->SourcePos        = {0};
    5988     //pDbgc->DumpPos          = {0};
    5989     //pDbgc->cbDumpElement    = 0;
    5990     //pDbgc->cVars            = 0;
    5991     //pDbgc->paVars           = NULL;
    5992     //pDbgc->pFirstBp         = NULL;
    5993     //pDbgc->uInputZero       = 0;
    5994     //pDbgc->iRead            = 0;
    5995     //pDbgc->iWrite           = 0;
    5996     //pDbgc->cInputLines      = 0;
    5997     //pDbgc->fInputOverflow   = false;
    5998     pDbgc->fReady           = true;
    5999     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    6000     //pDbgc->iArg             = 0;
    6001     //pDbgc->rcOutput         = 0;
    6002 
    6003     dbgcInitOpCharBitMap();
    6004 
    6005     /*
    6006      * Print welcome message.
    6007      */
    6008     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    6009         "Welcome to the VirtualBox Debugger!\n");
    6010     if (VBOX_FAILURE(rc))
    6011         goto l_failure;
    6012 
    6013     /*
    6014      * Attach to the VM.
    6015      */
    6016     rc = DBGFR3Attach(pVM);
    6017     if (VBOX_FAILURE(rc))
    6018     {
    6019         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    6020         goto l_failure;
    6021     }
    6022     pDbgc->pVM = pVM;
    6023 
    6024     /*
    6025      * Print commandline and auto select result.
    6026      */
    6027     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    6028         "Current VM is %08x\n" /** @todo get and print the VM name! */
    6029         "VBoxDbg> ",
    6030         pDbgc->pVM);
    6031     if (VBOX_FAILURE(rc))
    6032         goto l_failure;
    6033 
    6034     /*
    6035      * Main Debugger Loop.
    6036      *
    6037      * This loop will either block on waiting for input or on waiting on
    6038      * debug events. If we're forwarding the log we cannot wait for long
    6039      * before we must flush the log.
    6040      */
    6041     for (rc = 0;;)
    6042     {
    6043         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    6044         {
    6045             /*
    6046              * Wait for a debug event.
    6047              */
    6048             PCDBGFEVENT pEvent;
    6049             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    6050             if (VBOX_SUCCESS(rc))
    6051             {
    6052                 rc = dbgcProcessEvent(pDbgc, pEvent);
    6053                 if (VBOX_FAILURE(rc))
    6054                     break;
    6055             }
    6056             else if (rc != VERR_TIMEOUT)
    6057                 break;
    6058 
    6059             /*
    6060              * Check for input.
    6061              */
    6062             if (pBack->pfnInput(pDbgc->pBack, 0))
    6063             {
    6064                 rc = dbgcProcessInput(pDbgc);
    6065                 if (VBOX_FAILURE(rc))
    6066                     break;
    6067             }
    6068         }
    6069         else
    6070         {
    6071             /*
    6072              * Wait for input. If Logging is enabled we'll only wait very briefly.
    6073              */
    6074             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    6075             {
    6076                 rc = dbgcProcessInput(pDbgc);
    6077                 if (VBOX_FAILURE(rc))
    6078                     break;
    6079             }
    6080         }
    6081 
    6082         /*
    6083          * Forward log output.
    6084          */
    6085         if (pDbgc->fLog)
    6086         {
    6087             rc = dbgcProcessLog(pDbgc);
    6088             if (VBOX_FAILURE(rc))
    6089                 break;
    6090         }
    6091     }
    6092 
    6093 
    6094 l_failure:
    6095     /*
    6096      * Cleanup console debugger session.
    6097      */
    6098     /* Disable log hook. */
    6099     if (pDbgc->fLog)
    6100     {
    6101 
    6102     }
    6103 
    6104     /* Detach from the VM. */
    6105     if (pDbgc->pVM)
    6106         DBGFR3Detach(pDbgc->pVM);
    6107 
    6108     /* finally, free the instance memory. */
    6109     RTMemFree(pDbgc);
    6110 
    6111     return rc;
    6112 }
    6113 
    6114 
    6115 
    6116 /**
    6117  * Register one or more external commands.
    6118  *
    6119  * @returns VBox status.
    6120  * @param   paCommands      Pointer to an array of command descriptors.
    6121  *                          The commands must be unique. It's not possible
    6122  *                          to register the same commands more than once.
    6123  * @param   cCommands       Number of commands.
    6124  */
    6125 DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    6126 {
    6127     /*
    6128      * Lock the list.
    6129      */
    6130     DBGCEXTCMDS_LOCK_WR();
    6131     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    6132     while (pCur)
    6133     {
    6134         if (paCommands == pCur->paCmds)
    6135         {
    6136             DBGCEXTCMDS_UNLOCK_WR();
    6137             AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
    6138             return VWRN_DBGC_ALREADY_REGISTERED;
    6139         }
    6140         pCur = pCur->pNext;
    6141     }
    6142 
    6143     /*
    6144      * Allocate new chunk.
    6145      */
    6146     int rc = 0;
    6147     pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
    6148     if (pCur)
    6149     {
    6150         pCur->cCmds  = cCommands;
    6151         pCur->paCmds = paCommands;
    6152         pCur->pNext = g_pExtCmdsHead;
    6153         g_pExtCmdsHead = pCur;
    6154     }
    6155     else
    6156         rc = VERR_NO_MEMORY;
    6157     DBGCEXTCMDS_UNLOCK_WR();
    6158 
    6159     return rc;
    6160 }
    6161 
    6162 
    6163 /**
    6164  * Deregister one or more external commands previously registered by
    6165  * DBGCRegisterCommands().
    6166  *
    6167  * @returns VBox status.
    6168  * @param   paCommands      Pointer to an array of command descriptors
    6169  *                          as given to DBGCRegisterCommands().
    6170  * @param   cCommands       Number of commands.
    6171  */
    6172 DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    6173 {
    6174     /*
    6175      * Lock the list.
    6176      */
    6177     DBGCEXTCMDS_LOCK_WR();
    6178     PDBGCEXTCMDS pPrev = NULL;
    6179     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    6180     while (pCur)
    6181     {
    6182         if (paCommands == pCur->paCmds)
    6183         {
    6184             if (pPrev)
    6185                 pPrev->pNext = pCur->pNext;
    6186             else
    6187                 g_pExtCmdsHead = pCur->pNext;
    6188             DBGCEXTCMDS_UNLOCK_WR();
    6189 
    6190             RTMemFree(pCur);
    6191             return VINF_SUCCESS;
    6192         }
    6193         pPrev = pCur;
    6194         pCur = pCur->pNext;
    6195     }
    6196     DBGCEXTCMDS_UNLOCK_WR();
    6197 
    6198     NOREF(cCommands);
    6199     return VERR_DBGC_COMMANDS_NOT_REGISTERED;
    6200 }
    6201 
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r5672 r5673  
    148148static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    149149
    150 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    151 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    152 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    153 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    154 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    155 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    156 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    157 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    158 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    159 
    160 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    161 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    162 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    163 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    164 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    165 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    166 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    167 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    168 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    169 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    170 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    171 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    172 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    173 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    174 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    175 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
    176 
    177150static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    178151static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    179152
    180 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
    181153static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    182154static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
     
    311283};
    312284
    313 
    314 /** Operators. */
    315 static const DBGCOP g_aOps[] =
    316 {
    317     /* 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). */
    318     /* szName,          cchName, fBinary,    iPrecedence,    pfnHandlerUnary,    pfnHandlerBitwise  */
    319     { {'-'},            1,       false,      1,              dbgcOpMinus,        NULL,                       "Unary minus." },
    320     { {'+'},            1,       false,      1,              dbgcOpPluss,        NULL,                       "Unary pluss." },
    321     { {'!'},            1,       false,      1,              dbgcOpBooleanNot,   NULL,                       "Boolean not." },
    322     { {'~'},            1,       false,      1,              dbgcOpBitwiseNot,   NULL,                       "Bitwise complement." },
    323     { {':'},            1,       true,       2,              NULL,               dbgcOpAddrFar,              "Far pointer." },
    324     { {'%'},            1,       false,      3,              dbgcOpAddrFlat,     NULL,                       "Flat address." },
    325     { {'%','%'},        2,       false,      3,              dbgcOpAddrPhys,     NULL,                       "Physical address." },
    326     { {'#'},            1,       false,      3,              dbgcOpAddrHost,     NULL,                       "Flat host address." },
    327     { {'#','%','%'},    3,       false,      3,              dbgcOpAddrHostPhys, NULL,                       "Physical host address." },
    328     { {'$'},            1,       false,      3,              dbgcOpVar,          NULL,                       "Reference a variable." },
    329     { {'*'},            1,       true,       10,             NULL,               dbgcOpMult,                 "Multiplication." },
    330     { {'/'},            1,       true,       11,             NULL,               dbgcOpDiv,                  "Division." },
    331     { {'%'},            1,       true,       12,             NULL,               dbgcOpMod,                  "Modulus." },
    332     { {'+'},            1,       true,       13,             NULL,               dbgcOpAdd,                  "Addition." },
    333     { {'-'},            1,       true,       14,             NULL,               dbgcOpSub,                  "Subtraction." },
    334     { {'<','<'},        2,       true,       15,             NULL,               dbgcOpBitwiseShiftLeft,     "Bitwise left shift." },
    335     { {'>','>'},        2,       true,       16,             NULL,               dbgcOpBitwiseShiftRight,    "Bitwise right shift." },
    336     { {'&'},            1,       true,       17,             NULL,               dbgcOpBitwiseAnd,           "Bitwise and." },
    337     { {'^'},            1,       true,       18,             NULL,               dbgcOpBitwiseXor,           "Bitwise exclusiv or." },
    338     { {'|'},            1,       true,       19,             NULL,               dbgcOpBitwiseOr,            "Bitwise inclusive or." },
    339     { {'&','&'},        2,       true,       20,             NULL,               dbgcOpBooleanAnd,           "Boolean and." },
    340     { {'|','|'},        2,       true,       21,             NULL,               dbgcOpBooleanOr,            "Boolean or." },
    341     { {'L'},            1,       true,       22,             NULL,               dbgcOpRangeLength,          "Range elements." },
    342     { {'L','B'},        2,       true,       23,             NULL,               dbgcOpRangeLengthBytes,     "Range bytes." },
    343     { {'T'},            1,       true,       24,             NULL,               dbgcOpRangeTo,              "Range to." }
    344 };
    345 
    346 /** Bitmap where set bits indicates the characters the may start an operator name. */
    347 static uint32_t g_bmOperatorChars[256 / (4*8)];
    348285
    349286/** Register symbol uUser value.
     
    513450
    514451
     452/** Bitmap where set bits indicates the characters the may start an operator name. */
     453static uint32_t g_bmOperatorChars[256 / (4*8)];
     454
     455
     456
     457
     458
     459
     460
     461
    515462/**
    516463 * Prints full command help.
     
    626573                                "Operators:\n");
    627574        unsigned iPrecedence = 0;
    628         unsigned cLeft = ELEMENTS(g_aOps);
     575        unsigned cLeft = g_cOps;
    629576        while (cLeft > 0)
    630577        {
    631             for (i = 0; i < ELEMENTS(g_aOps); i++)
     578            for (i = 0; i < g_cOps; i++)
    632579                if (g_aOps[i].iPrecedence == iPrecedence)
    633580                {
     
    690637           if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
    691638           {
    692                for (i = 0; i < ELEMENTS(g_aOps); i++)
     639               for (i = 0; i < g_cOps; i++)
    693640                   if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))
    694641                   {
     
    17551702//
    17561703//
    1757 //      O p e r a t o r s
    1758 //
    1759 //
    1760 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1761 
    1762 
    1763 /**
    1764  * Minus (unary).
    1765  *
    1766  * @returns 0 on success.
    1767  * @returns VBox evaluation / parsing error code on failure.
    1768  *          The caller does the bitching.
    1769  * @param   pDbgc       Debugger console instance data.
    1770  * @param   pArg        The argument.
    1771  * @param   pResult     Where to store the result.
    1772  */
    1773 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1774 {
    1775 //    LogFlow(("dbgcOpMinus\n"));
    1776     *pResult = *pArg;
    1777     switch (pArg->enmType)
    1778     {
    1779         case DBGCVAR_TYPE_GC_FLAT:
    1780             pResult->u.GCFlat       = -(RTGCINTPTR)pResult->u.GCFlat;
    1781             break;
    1782         case DBGCVAR_TYPE_GC_FAR:
    1783             pResult->u.GCFar.off    = -(int32_t)pResult->u.GCFar.off;
    1784             break;
    1785         case DBGCVAR_TYPE_GC_PHYS:
    1786             pResult->u.GCPhys       = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;
    1787             break;
    1788         case DBGCVAR_TYPE_HC_FLAT:
    1789             pResult->u.pvHCFlat     = (void *) -(intptr_t)pResult->u.pvHCFlat;
    1790             break;
    1791         case DBGCVAR_TYPE_HC_FAR:
    1792             pResult->u.HCFar.off    = -(int32_t)pResult->u.HCFar.off;
    1793             break;
    1794         case DBGCVAR_TYPE_HC_PHYS:
    1795             pResult->u.HCPhys       = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;
    1796             break;
    1797         case DBGCVAR_TYPE_NUMBER:
    1798             pResult->u.u64Number    = -(int64_t)pResult->u.u64Number;
    1799             break;
    1800 
    1801         case DBGCVAR_TYPE_UNKNOWN:
    1802         case DBGCVAR_TYPE_STRING:
    1803         default:
    1804             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1805     }
    1806     NOREF(pDbgc);
    1807     return 0;
    1808 }
    1809 
    1810 
    1811 /**
    1812  * Pluss (unary).
    1813  *
    1814  * @returns 0 on success.
    1815  * @returns VBox evaluation / parsing error code on failure.
    1816  *          The caller does the bitching.
    1817  * @param   pDbgc       Debugger console instance data.
    1818  * @param   pArg        The argument.
    1819  * @param   pResult     Where to store the result.
    1820  */
    1821 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1822 {
    1823 //    LogFlow(("dbgcOpPluss\n"));
    1824     *pResult = *pArg;
    1825     switch (pArg->enmType)
    1826     {
    1827         case DBGCVAR_TYPE_GC_FLAT:
    1828         case DBGCVAR_TYPE_GC_FAR:
    1829         case DBGCVAR_TYPE_GC_PHYS:
    1830         case DBGCVAR_TYPE_HC_FLAT:
    1831         case DBGCVAR_TYPE_HC_FAR:
    1832         case DBGCVAR_TYPE_HC_PHYS:
    1833         case DBGCVAR_TYPE_NUMBER:
    1834             break;
    1835 
    1836         case DBGCVAR_TYPE_UNKNOWN:
    1837         case DBGCVAR_TYPE_STRING:
    1838         default:
    1839             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1840     }
    1841     NOREF(pDbgc);
    1842     return 0;
    1843 }
    1844 
    1845 
    1846 /**
    1847  * Boolean not (unary).
    1848  *
    1849  * @returns 0 on success.
    1850  * @returns VBox evaluation / parsing error code on failure.
    1851  *          The caller does the bitching.
    1852  * @param   pDbgc       Debugger console instance data.
    1853  * @param   pArg        The argument.
    1854  * @param   pResult     Where to store the result.
    1855  */
    1856 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1857 {
    1858 //    LogFlow(("dbgcOpBooleanNot\n"));
    1859     *pResult = *pArg;
    1860     switch (pArg->enmType)
    1861     {
    1862         case DBGCVAR_TYPE_GC_FLAT:
    1863             pResult->u.u64Number    = !pResult->u.GCFlat;
    1864             break;
    1865         case DBGCVAR_TYPE_GC_FAR:
    1866             pResult->u.u64Number    = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;
    1867             break;
    1868         case DBGCVAR_TYPE_GC_PHYS:
    1869             pResult->u.u64Number    = !pResult->u.GCPhys;
    1870             break;
    1871         case DBGCVAR_TYPE_HC_FLAT:
    1872             pResult->u.u64Number    = !pResult->u.pvHCFlat;
    1873             break;
    1874         case DBGCVAR_TYPE_HC_FAR:
    1875             pResult->u.u64Number    = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;
    1876             break;
    1877         case DBGCVAR_TYPE_HC_PHYS:
    1878             pResult->u.u64Number    = !pResult->u.HCPhys;
    1879             break;
    1880         case DBGCVAR_TYPE_NUMBER:
    1881             pResult->u.u64Number    = !pResult->u.u64Number;
    1882             break;
    1883         case DBGCVAR_TYPE_STRING:
    1884             pResult->u.u64Number    = !pResult->u64Range;
    1885             break;
    1886 
    1887         case DBGCVAR_TYPE_UNKNOWN:
    1888         default:
    1889             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1890     }
    1891     pResult->enmType = DBGCVAR_TYPE_NUMBER;
    1892     NOREF(pDbgc);
    1893     return 0;
    1894 }
    1895 
    1896 
    1897 /**
    1898  * Bitwise not (unary).
    1899  *
    1900  * @returns 0 on success.
    1901  * @returns VBox evaluation / parsing error code on failure.
    1902  *          The caller does the bitching.
    1903  * @param   pDbgc       Debugger console instance data.
    1904  * @param   pArg        The argument.
    1905  * @param   pResult     Where to store the result.
    1906  */
    1907 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1908 {
    1909 //    LogFlow(("dbgcOpBitwiseNot\n"));
    1910     *pResult = *pArg;
    1911     switch (pArg->enmType)
    1912     {
    1913         case DBGCVAR_TYPE_GC_FLAT:
    1914             pResult->u.GCFlat       = ~pResult->u.GCFlat;
    1915             break;
    1916         case DBGCVAR_TYPE_GC_FAR:
    1917             pResult->u.GCFar.off    = ~pResult->u.GCFar.off;
    1918             break;
    1919         case DBGCVAR_TYPE_GC_PHYS:
    1920             pResult->u.GCPhys       = ~pResult->u.GCPhys;
    1921             break;
    1922         case DBGCVAR_TYPE_HC_FLAT:
    1923             pResult->u.pvHCFlat     = (void *)~(uintptr_t)pResult->u.pvHCFlat;
    1924             break;
    1925         case DBGCVAR_TYPE_HC_FAR:
    1926             pResult->u.HCFar.off= ~pResult->u.HCFar.off;
    1927             break;
    1928         case DBGCVAR_TYPE_HC_PHYS:
    1929             pResult->u.HCPhys       = ~pResult->u.HCPhys;
    1930             break;
    1931         case DBGCVAR_TYPE_NUMBER:
    1932             pResult->u.u64Number    = ~pResult->u.u64Number;
    1933             break;
    1934 
    1935         case DBGCVAR_TYPE_UNKNOWN:
    1936         case DBGCVAR_TYPE_STRING:
    1937         default:
    1938             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1939     }
    1940     NOREF(pDbgc);
    1941     return 0;
    1942 }
    1943 
    1944 
    1945 /**
    1946  * Reference variable (unary).
    1947  *
    1948  * @returns 0 on success.
    1949  * @returns VBox evaluation / parsing error code on failure.
    1950  *          The caller does the bitching.
    1951  * @param   pDbgc       Debugger console instance data.
    1952  * @param   pArg        The argument.
    1953  * @param   pResult     Where to store the result.
    1954  */
    1955 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1956 {
    1957 //    LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));
    1958     /*
    1959      * Parse sanity.
    1960      */
    1961     if (pArg->enmType != DBGCVAR_TYPE_STRING)
    1962         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1963 
    1964     /*
    1965      * Lookup the variable.
    1966      */
    1967     const char *pszVar = pArg->u.pszString;
    1968     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1969     {
    1970         if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    1971         {
    1972             *pResult = pDbgc->papVars[iVar]->Var;
    1973             return 0;
    1974         }
    1975     }
    1976 
    1977     return VERR_PARSE_VARIABLE_NOT_FOUND;
    1978 }
    1979 
    1980 
    1981 /**
    1982  * Flat address (unary).
    1983  *
    1984  * @returns VINF_SUCCESS on success.
    1985  * @returns VBox evaluation / parsing error code on failure.
    1986  *          The caller does the bitching.
    1987  * @param   pDbgc       Debugger console instance data.
    1988  * @param   pArg        The argument.
    1989  * @param   pResult     Where to store the result.
    1990  */
    1991 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    1992 {
    1993 //    LogFlow(("dbgcOpAddrFlat\n"));
    1994     int     rc;
    1995     *pResult = *pArg;
    1996 
    1997     switch (pArg->enmType)
    1998     {
    1999         case DBGCVAR_TYPE_GC_FLAT:
    2000             return VINF_SUCCESS;
    2001 
    2002         case DBGCVAR_TYPE_GC_FAR:
    2003         {
    2004             Assert(pDbgc->pVM);
    2005             DBGFADDRESS Address;
    2006             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    2007             if (VBOX_SUCCESS(rc))
    2008             {
    2009                 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
    2010                 pResult->u.GCFlat = Address.FlatPtr;
    2011                 return VINF_SUCCESS;
    2012             }
    2013             return VERR_PARSE_CONVERSION_FAILED;
    2014         }
    2015 
    2016         case DBGCVAR_TYPE_GC_PHYS:
    2017             //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
    2018             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2019 
    2020         case DBGCVAR_TYPE_HC_FLAT:
    2021             return VINF_SUCCESS;
    2022 
    2023         case DBGCVAR_TYPE_HC_FAR:
    2024             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2025 
    2026         case DBGCVAR_TYPE_HC_PHYS:
    2027             Assert(pDbgc->pVM);
    2028             pResult->enmType        = DBGCVAR_TYPE_HC_FLAT;
    2029             rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);
    2030             if (VBOX_SUCCESS(rc))
    2031                 return VINF_SUCCESS;
    2032             return VERR_PARSE_CONVERSION_FAILED;
    2033 
    2034         case DBGCVAR_TYPE_NUMBER:
    2035             pResult->enmType    = DBGCVAR_TYPE_GC_FLAT;
    2036             pResult->u.GCFlat   = (RTGCPTR)pResult->u.u64Number;
    2037             return VINF_SUCCESS;
    2038 
    2039         case DBGCVAR_TYPE_STRING:
    2040             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);
    2041 
    2042         case DBGCVAR_TYPE_UNKNOWN:
    2043         default:
    2044             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2045     }
    2046 }
    2047 
    2048 
    2049 /**
    2050  * Physical address (unary).
    2051  *
    2052  * @returns 0 on success.
    2053  * @returns VBox evaluation / parsing error code on failure.
    2054  *          The caller does the bitching.
    2055  * @param   pDbgc       Debugger console instance data.
    2056  * @param   pArg        The argument.
    2057  * @param   pResult     Where to store the result.
    2058  */
    2059 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2060 {
    2061 //    LogFlow(("dbgcOpAddrPhys\n"));
    2062     int     rc;
    2063 
    2064     *pResult = *pArg;
    2065     switch (pArg->enmType)
    2066     {
    2067         case DBGCVAR_TYPE_GC_FLAT:
    2068             Assert(pDbgc->pVM);
    2069             pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    2070             rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);
    2071             if (VBOX_SUCCESS(rc))
    2072                 return 0;
    2073             /** @todo more memory types! */
    2074             return VERR_PARSE_CONVERSION_FAILED;
    2075 
    2076         case DBGCVAR_TYPE_GC_FAR:
    2077         {
    2078             Assert(pDbgc->pVM);
    2079             DBGFADDRESS Address;
    2080             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    2081             if (VBOX_SUCCESS(rc))
    2082             {
    2083                 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    2084                 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);
    2085                 if (VBOX_SUCCESS(rc))
    2086                     return 0;
    2087                 /** @todo more memory types! */
    2088             }
    2089             return VERR_PARSE_CONVERSION_FAILED;
    2090         }
    2091 
    2092         case DBGCVAR_TYPE_GC_PHYS:
    2093             return 0;
    2094 
    2095         case DBGCVAR_TYPE_HC_FLAT:
    2096             Assert(pDbgc->pVM);
    2097             pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
    2098             rc = PGMR3DbgHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);
    2099             if (VBOX_SUCCESS(rc))
    2100                 return 0;
    2101             /** @todo more memory types! */
    2102             return VERR_PARSE_CONVERSION_FAILED;
    2103 
    2104         case DBGCVAR_TYPE_HC_FAR:
    2105             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2106 
    2107         case DBGCVAR_TYPE_HC_PHYS:
    2108             return 0;
    2109 
    2110         case DBGCVAR_TYPE_NUMBER:
    2111             pResult->enmType    = DBGCVAR_TYPE_GC_PHYS;
    2112             pResult->u.GCPhys   = (RTGCPHYS)pResult->u.u64Number;
    2113             return 0;
    2114 
    2115         case DBGCVAR_TYPE_STRING:
    2116             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);
    2117 
    2118         case DBGCVAR_TYPE_UNKNOWN:
    2119         default:
    2120             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2121     }
    2122     return 0;
    2123 }
    2124 
    2125 
    2126 /**
    2127  * Physical host address (unary).
    2128  *
    2129  * @returns 0 on success.
    2130  * @returns VBox evaluation / parsing error code on failure.
    2131  *          The caller does the bitching.
    2132  * @param   pDbgc       Debugger console instance data.
    2133  * @param   pArg        The argument.
    2134  * @param   pResult     Where to store the result.
    2135  */
    2136 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2137 {
    2138 //    LogFlow(("dbgcOpAddrPhys\n"));
    2139     int     rc;
    2140 
    2141     *pResult = *pArg;
    2142     switch (pArg->enmType)
    2143     {
    2144         case DBGCVAR_TYPE_GC_FLAT:
    2145             Assert(pDbgc->pVM);
    2146             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    2147             rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
    2148             if (VBOX_SUCCESS(rc))
    2149                 return 0;
    2150             /** @todo more memory types. */
    2151             return VERR_PARSE_CONVERSION_FAILED;
    2152 
    2153         case DBGCVAR_TYPE_GC_FAR:
    2154         {
    2155             Assert(pDbgc->pVM);
    2156             DBGFADDRESS Address;
    2157             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    2158             if (VBOX_SUCCESS(rc))
    2159             {
    2160                 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    2161                 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);
    2162                 if (VBOX_SUCCESS(rc))
    2163                     return 0;
    2164                 /** @todo more memory types. */
    2165             }
    2166             return VERR_PARSE_CONVERSION_FAILED;
    2167         }
    2168 
    2169         case DBGCVAR_TYPE_GC_PHYS:
    2170             Assert(pDbgc->pVM);
    2171             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    2172             rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
    2173             if (VBOX_SUCCESS(rc))
    2174                 return 0;
    2175             return VERR_PARSE_CONVERSION_FAILED;
    2176 
    2177         case DBGCVAR_TYPE_HC_FLAT:
    2178             Assert(pDbgc->pVM);
    2179             pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
    2180             rc = PGMR3DbgHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);
    2181             if (VBOX_SUCCESS(rc))
    2182                 return 0;
    2183             /** @todo more memory types! */
    2184             return VERR_PARSE_CONVERSION_FAILED;
    2185 
    2186         case DBGCVAR_TYPE_HC_FAR:
    2187             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2188 
    2189         case DBGCVAR_TYPE_HC_PHYS:
    2190             return 0;
    2191 
    2192         case DBGCVAR_TYPE_NUMBER:
    2193             pResult->enmType    = DBGCVAR_TYPE_HC_PHYS;
    2194             pResult->u.HCPhys   = (RTGCPHYS)pResult->u.u64Number;
    2195             return 0;
    2196 
    2197         case DBGCVAR_TYPE_STRING:
    2198             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);
    2199 
    2200         case DBGCVAR_TYPE_UNKNOWN:
    2201         default:
    2202             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2203     }
    2204     return 0;
    2205 }
    2206 
    2207 
    2208 /**
    2209  * Host address (unary).
    2210  *
    2211  * @returns 0 on success.
    2212  * @returns VBox evaluation / parsing error code on failure.
    2213  *          The caller does the bitching.
    2214  * @param   pDbgc       Debugger console instance data.
    2215  * @param   pArg        The argument.
    2216  * @param   pResult     Where to store the result.
    2217  */
    2218 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
    2219 {
    2220 //    LogFlow(("dbgcOpAddrHost\n"));
    2221     int     rc;
    2222 
    2223     *pResult = *pArg;
    2224     switch (pArg->enmType)
    2225     {
    2226         case DBGCVAR_TYPE_GC_FLAT:
    2227             Assert(pDbgc->pVM);
    2228             pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    2229             rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);
    2230             if (VBOX_SUCCESS(rc))
    2231                 return 0;
    2232             /** @todo more memory types. */
    2233             return VERR_PARSE_CONVERSION_FAILED;
    2234 
    2235         case DBGCVAR_TYPE_GC_FAR:
    2236         {
    2237             Assert(pDbgc->pVM);
    2238             DBGFADDRESS Address;
    2239             rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
    2240             if (VBOX_SUCCESS(rc))
    2241             {
    2242                 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    2243                 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);
    2244                 if (VBOX_SUCCESS(rc))
    2245                     return 0;
    2246                 /** @todo more memory types. */
    2247             }
    2248             return VERR_PARSE_CONVERSION_FAILED;
    2249         }
    2250 
    2251         case DBGCVAR_TYPE_GC_PHYS:
    2252             Assert(pDbgc->pVM);
    2253             pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
    2254             rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);
    2255             if (VBOX_SUCCESS(rc))
    2256                 return 0;
    2257             return VERR_PARSE_CONVERSION_FAILED;
    2258 
    2259         case DBGCVAR_TYPE_HC_FLAT:
    2260             return 0;
    2261 
    2262         case DBGCVAR_TYPE_HC_FAR:
    2263         case DBGCVAR_TYPE_HC_PHYS:
    2264             /** @todo !*/
    2265             return VERR_PARSE_CONVERSION_FAILED;
    2266 
    2267         case DBGCVAR_TYPE_NUMBER:
    2268             pResult->enmType    = DBGCVAR_TYPE_HC_FLAT;
    2269             pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;
    2270             return 0;
    2271 
    2272         case DBGCVAR_TYPE_STRING:
    2273             return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);
    2274 
    2275         case DBGCVAR_TYPE_UNKNOWN:
    2276         default:
    2277             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2278     }
    2279 }
    2280 
    2281 /**
    2282  * Bitwise not (unary).
    2283  *
    2284  * @returns 0 on success.
    2285  * @returns VBox evaluation / parsing error code on failure.
    2286  *          The caller does the bitching.
    2287  * @param   pDbgc       Debugger console instance data.
    2288  * @param   pArg        The argument.
    2289  * @param   pResult     Where to store the result.
    2290  */
    2291 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2292 {
    2293 //    LogFlow(("dbgcOpAddrFar\n"));
    2294     int     rc;
    2295 
    2296     switch (pArg1->enmType)
    2297     {
    2298         case DBGCVAR_TYPE_STRING:
    2299             rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
    2300             if (VBOX_FAILURE(rc))
    2301                 return rc;
    2302             break;
    2303         case DBGCVAR_TYPE_NUMBER:
    2304             *pResult = *pArg1;
    2305             break;
    2306 
    2307         case DBGCVAR_TYPE_GC_FLAT:
    2308         case DBGCVAR_TYPE_GC_FAR:
    2309         case DBGCVAR_TYPE_GC_PHYS:
    2310         case DBGCVAR_TYPE_HC_FLAT:
    2311         case DBGCVAR_TYPE_HC_FAR:
    2312         case DBGCVAR_TYPE_HC_PHYS:
    2313         case DBGCVAR_TYPE_UNKNOWN:
    2314         default:
    2315             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2316     }
    2317     pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;
    2318 
    2319     /* common code for the two types we support. */
    2320     switch (pArg2->enmType)
    2321     {
    2322         case DBGCVAR_TYPE_GC_FLAT:
    2323             pResult->u.GCFar.off = pArg2->u.GCFlat;
    2324             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    2325             break;
    2326 
    2327         case DBGCVAR_TYPE_HC_FLAT:
    2328             pResult->u.HCFar.off = pArg2->u.GCFlat;
    2329             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    2330             break;
    2331 
    2332         case DBGCVAR_TYPE_NUMBER:
    2333             pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;
    2334             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    2335             break;
    2336 
    2337         case DBGCVAR_TYPE_STRING:
    2338         {
    2339             DBGCVAR Var;
    2340             rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    2341             if (VBOX_FAILURE(rc))
    2342                 return rc;
    2343             pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;
    2344             pResult->enmType    = DBGCVAR_TYPE_GC_FAR;
    2345             break;
    2346         }
    2347 
    2348         case DBGCVAR_TYPE_GC_FAR:
    2349         case DBGCVAR_TYPE_GC_PHYS:
    2350         case DBGCVAR_TYPE_HC_FAR:
    2351         case DBGCVAR_TYPE_HC_PHYS:
    2352         case DBGCVAR_TYPE_UNKNOWN:
    2353         default:
    2354             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2355     }
    2356     return 0;
    2357 
    2358 }
    2359 
    2360 
    2361 /**
    2362  * Multiplication operator (binary).
    2363  *
    2364  * @returns 0 on success.
    2365  * @returns VBox evaluation / parsing error code on failure.
    2366  *          The caller does the bitching.
    2367  * @param   pDbgc       Debugger console instance data.
    2368  * @param   pArg1       The first argument.
    2369  * @param   pArg2       The 2nd argument.
    2370  * @param   pResult     Where to store the result.
    2371  */
    2372 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2373 {
    2374 //    LogFlow(("dbgcOpMult\n"));
    2375     int     rc;
    2376 
    2377     /*
    2378      * Switch the factors so we preserve pointers, far pointers are considered more
    2379      * important that physical and flat pointers.
    2380      */
    2381     if (    DBGCVAR_ISPOINTER(pArg2->enmType)
    2382         &&  (   !DBGCVAR_ISPOINTER(pArg1->enmType)
    2383              || (   DBGCVAR_IS_FAR_PTR(pArg2->enmType)
    2384                  && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))
    2385     {
    2386         PCDBGCVAR pTmp = pArg1;
    2387         pArg2 = pArg1;
    2388         pArg1 = pTmp;
    2389     }
    2390 
    2391     /*
    2392      * Convert the 2nd number into a number we use multiply the first with.
    2393      */
    2394     DBGCVAR Factor2 = *pArg2;
    2395     if (    Factor2.enmType == DBGCVAR_TYPE_STRING
    2396         ||  Factor2.enmType == DBGCVAR_TYPE_SYMBOL)
    2397     {
    2398         rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);
    2399         if (VBOX_FAILURE(rc))
    2400             return rc;
    2401     }
    2402     uint64_t u64Factor;
    2403     switch (Factor2.enmType)
    2404     {
    2405         case DBGCVAR_TYPE_GC_FLAT:  u64Factor = Factor2.u.GCFlat; break;
    2406         case DBGCVAR_TYPE_GC_FAR:   u64Factor = Factor2.u.GCFar.off; break;
    2407         case DBGCVAR_TYPE_GC_PHYS:  u64Factor = Factor2.u.GCPhys; break;
    2408         case DBGCVAR_TYPE_HC_FLAT:  u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;
    2409         case DBGCVAR_TYPE_HC_FAR:   u64Factor = Factor2.u.HCFar.off; break;
    2410         case DBGCVAR_TYPE_HC_PHYS:  u64Factor = Factor2.u.HCPhys; break;
    2411         case DBGCVAR_TYPE_NUMBER:   u64Factor = Factor2.u.u64Number; break;
    2412         default:
    2413             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2414     }
    2415 
    2416     /*
    2417      * Fix symbols in the 1st factor.
    2418      */
    2419     *pResult = *pArg1;
    2420     if (    pResult->enmType == DBGCVAR_TYPE_STRING
    2421         ||  pResult->enmType == DBGCVAR_TYPE_SYMBOL)
    2422     {
    2423         rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
    2424         if (VBOX_FAILURE(rc))
    2425             return rc;
    2426     }
    2427 
    2428     /*
    2429      * Do the multiplication.
    2430      */
    2431     switch (pArg1->enmType)
    2432     {
    2433         case DBGCVAR_TYPE_GC_FLAT:  pResult->u.GCFlat *= u64Factor; break;
    2434         case DBGCVAR_TYPE_GC_FAR:   pResult->u.GCFar.off *= u64Factor; break;
    2435         case DBGCVAR_TYPE_GC_PHYS:  pResult->u.GCPhys *= u64Factor; break;
    2436         case DBGCVAR_TYPE_HC_FLAT:
    2437             pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);
    2438             break;
    2439         case DBGCVAR_TYPE_HC_FAR:   pResult->u.HCFar.off *= u64Factor; break;
    2440         case DBGCVAR_TYPE_HC_PHYS:  pResult->u.HCPhys *= u64Factor; break;
    2441         case DBGCVAR_TYPE_NUMBER:   pResult->u.u64Number *= u64Factor; break;
    2442         default:
    2443             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2444     }
    2445     return 0;
    2446 }
    2447 
    2448 
    2449 /**
    2450  * Division operator (binary).
    2451  *
    2452  * @returns 0 on success.
    2453  * @returns VBox evaluation / parsing error code on failure.
    2454  *          The caller does the bitching.
    2455  * @param   pDbgc       Debugger console instance data.
    2456  * @param   pArg1       The first argument.
    2457  * @param   pArg2       The 2nd argument.
    2458  * @param   pResult     Where to store the result.
    2459  */
    2460 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2461 {
    2462     LogFlow(("dbgcOpDiv\n"));
    2463     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    2464     return -1;
    2465 }
    2466 
    2467 
    2468 /**
    2469  * Modulus operator (binary).
    2470  *
    2471  * @returns 0 on success.
    2472  * @returns VBox evaluation / parsing error code on failure.
    2473  *          The caller does the bitching.
    2474  * @param   pDbgc       Debugger console instance data.
    2475  * @param   pArg1       The first argument.
    2476  * @param   pArg2       The 2nd argument.
    2477  * @param   pResult     Where to store the result.
    2478  */
    2479 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2480 {
    2481     LogFlow(("dbgcOpMod\n"));
    2482     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    2483     return -1;
    2484 }
    2485 
    2486 
    2487 /**
    2488  * Addition operator (binary).
    2489  *
    2490  * @returns 0 on success.
    2491  * @returns VBox evaluation / parsing error code on failure.
    2492  *          The caller does the bitching.
    2493  * @param   pDbgc       Debugger console instance data.
    2494  * @param   pArg1       The first argument.
    2495  * @param   pArg2       The 2nd argument.
    2496  * @param   pResult     Where to store the result.
    2497  */
    2498 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2499 {
    2500 //    LogFlow(("dbgcOpAdd\n"));
    2501 
    2502     /*
    2503      * An addition operation will return (when possible) the left side type in the
    2504      * expression. We make an omission for numbers, where we'll take the right side
    2505      * type instead. An expression where only the left hand side is a string we'll
    2506      * use the right hand type assuming that the string is a symbol.
    2507      */
    2508     if (    (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)
    2509         ||  (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))
    2510     {
    2511         PCDBGCVAR pTmp = pArg2;
    2512         pArg2 = pArg1;
    2513         pArg1 = pTmp;
    2514     }
    2515     DBGCVAR     Sym1, Sym2;
    2516     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    2517     {
    2518         int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
    2519         if (VBOX_FAILURE(rc))
    2520             return rc;
    2521         pArg1 = &Sym1;
    2522 
    2523         rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
    2524         if (VBOX_FAILURE(rc))
    2525             return rc;
    2526         pArg2 = &Sym2;
    2527     }
    2528 
    2529     int         rc;
    2530     DBGCVAR     Var;
    2531     DBGCVAR     Var2;
    2532     switch (pArg1->enmType)
    2533     {
    2534         /*
    2535          * GC Flat
    2536          */
    2537         case DBGCVAR_TYPE_GC_FLAT:
    2538             switch (pArg2->enmType)
    2539             {
    2540                 case DBGCVAR_TYPE_HC_FLAT:
    2541                 case DBGCVAR_TYPE_HC_FAR:
    2542                 case DBGCVAR_TYPE_HC_PHYS:
    2543                     return VERR_PARSE_INVALID_OPERATION;
    2544                 default:
    2545                     *pResult = *pArg1;
    2546                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    2547                     if (VBOX_FAILURE(rc))
    2548                         return rc;
    2549                     pResult->u.GCFlat += pArg2->u.GCFlat;
    2550                     break;
    2551             }
    2552             break;
    2553 
    2554         /*
    2555          * GC Far
    2556          */
    2557         case DBGCVAR_TYPE_GC_FAR:
    2558             switch (pArg2->enmType)
    2559             {
    2560                 case DBGCVAR_TYPE_HC_FLAT:
    2561                 case DBGCVAR_TYPE_HC_FAR:
    2562                 case DBGCVAR_TYPE_HC_PHYS:
    2563                     return VERR_PARSE_INVALID_OPERATION;
    2564                 case DBGCVAR_TYPE_NUMBER:
    2565                     *pResult = *pArg1;
    2566                     pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;
    2567                     break;
    2568                 default:
    2569                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    2570                     if (VBOX_FAILURE(rc))
    2571                         return rc;
    2572                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    2573                     if (VBOX_FAILURE(rc))
    2574                         return rc;
    2575                     pResult->u.GCFlat += pArg2->u.GCFlat;
    2576                     break;
    2577             }
    2578             break;
    2579 
    2580         /*
    2581          * GC Phys
    2582          */
    2583         case DBGCVAR_TYPE_GC_PHYS:
    2584             switch (pArg2->enmType)
    2585             {
    2586                 case DBGCVAR_TYPE_HC_FLAT:
    2587                 case DBGCVAR_TYPE_HC_FAR:
    2588                 case DBGCVAR_TYPE_HC_PHYS:
    2589                     return VERR_PARSE_INVALID_OPERATION;
    2590                 default:
    2591                     *pResult = *pArg1;
    2592                     rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
    2593                     if (VBOX_FAILURE(rc))
    2594                         return rc;
    2595                     if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
    2596                         return VERR_PARSE_INVALID_OPERATION;
    2597                     pResult->u.GCPhys += Var.u.GCPhys;
    2598                     break;
    2599             }
    2600             break;
    2601 
    2602         /*
    2603          * HC Flat
    2604          */
    2605         case DBGCVAR_TYPE_HC_FLAT:
    2606             *pResult = *pArg1;
    2607             rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    2608             if (VBOX_FAILURE(rc))
    2609                 return rc;
    2610             rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    2611             if (VBOX_FAILURE(rc))
    2612                 return rc;
    2613             pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
    2614             break;
    2615 
    2616         /*
    2617          * HC Far
    2618          */
    2619         case DBGCVAR_TYPE_HC_FAR:
    2620             switch (pArg2->enmType)
    2621             {
    2622                 case DBGCVAR_TYPE_NUMBER:
    2623                     *pResult = *pArg1;
    2624                     pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;
    2625                     break;
    2626 
    2627                 default:
    2628                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    2629                     if (VBOX_FAILURE(rc))
    2630                         return rc;
    2631                     rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    2632                     if (VBOX_FAILURE(rc))
    2633                         return rc;
    2634                     rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    2635                     if (VBOX_FAILURE(rc))
    2636                         return rc;
    2637                     pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
    2638                     break;
    2639             }
    2640             break;
    2641 
    2642         /*
    2643          * HC Phys
    2644          */
    2645         case DBGCVAR_TYPE_HC_PHYS:
    2646             *pResult = *pArg1;
    2647             rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
    2648             if (VBOX_FAILURE(rc))
    2649                 return rc;
    2650             pResult->u.HCPhys += Var.u.HCPhys;
    2651             break;
    2652 
    2653         /*
    2654          * Numbers (see start of function)
    2655          */
    2656         case DBGCVAR_TYPE_NUMBER:
    2657             *pResult = *pArg1;
    2658             switch (pArg2->enmType)
    2659             {
    2660                 case DBGCVAR_TYPE_SYMBOL:
    2661                 case DBGCVAR_TYPE_STRING:
    2662                     rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    2663                     if (VBOX_FAILURE(rc))
    2664                         return rc;
    2665                 case DBGCVAR_TYPE_NUMBER:
    2666                     pResult->u.u64Number += pArg2->u.u64Number;
    2667                     break;
    2668                 default:
    2669                     return VERR_PARSE_INVALID_OPERATION;
    2670             }
    2671             break;
    2672 
    2673         default:
    2674             return VERR_PARSE_INVALID_OPERATION;
    2675 
    2676     }
    2677     return 0;
    2678 }
    2679 
    2680 
    2681 /**
    2682  * Subtration operator (binary).
    2683  *
    2684  * @returns 0 on success.
    2685  * @returns VBox evaluation / parsing error code on failure.
    2686  *          The caller does the bitching.
    2687  * @param   pDbgc       Debugger console instance data.
    2688  * @param   pArg1       The first argument.
    2689  * @param   pArg2       The 2nd argument.
    2690  * @param   pResult     Where to store the result.
    2691  */
    2692 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2693 {
    2694 //    LogFlow(("dbgcOpSub\n"));
    2695 
    2696     /*
    2697      * An subtraction operation will return the left side type in the expression.
    2698      * However, if the left hand side is a number and the right hand a pointer of
    2699      * some kind we'll convert the left hand side to the same type as the right hand.
    2700      * Any strings will be attempted resolved as symbols.
    2701      */
    2702     DBGCVAR     Sym1, Sym2;
    2703     if (    pArg2->enmType == DBGCVAR_TYPE_STRING
    2704         &&  (   pArg1->enmType == DBGCVAR_TYPE_NUMBER
    2705              || pArg1->enmType == DBGCVAR_TYPE_STRING))
    2706     {
    2707         int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
    2708         if (VBOX_FAILURE(rc))
    2709             return rc;
    2710         pArg2 = &Sym2;
    2711     }
    2712 
    2713     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    2714     {
    2715         DBGCVARTYPE enmType;
    2716         switch (pArg2->enmType)
    2717         {
    2718             case DBGCVAR_TYPE_NUMBER:
    2719                 enmType = DBGCVAR_TYPE_ANY;
    2720                 break;
    2721             case DBGCVAR_TYPE_GC_FLAT:
    2722             case DBGCVAR_TYPE_GC_PHYS:
    2723             case DBGCVAR_TYPE_HC_FLAT:
    2724             case DBGCVAR_TYPE_HC_PHYS:
    2725                 enmType = pArg2->enmType;
    2726                 break;
    2727             case DBGCVAR_TYPE_GC_FAR:
    2728                 enmType = DBGCVAR_TYPE_GC_FLAT;
    2729                 break;
    2730             case DBGCVAR_TYPE_HC_FAR:
    2731                 enmType = DBGCVAR_TYPE_HC_FLAT;
    2732                 break;
    2733 
    2734             default:
    2735             case DBGCVAR_TYPE_STRING:
    2736                 AssertMsgFailed(("Can't happen\n"));
    2737                 enmType = DBGCVAR_TYPE_STRING;
    2738                 break;
    2739         }
    2740         if (enmType != DBGCVAR_TYPE_STRING)
    2741         {
    2742             int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
    2743             if (VBOX_FAILURE(rc))
    2744                 return rc;
    2745             pArg1 = &Sym1;
    2746         }
    2747     }
    2748     else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)
    2749     {
    2750         PFNDBGCOPUNARY pOp = NULL;
    2751         switch (pArg2->enmType)
    2752         {
    2753             case DBGCVAR_TYPE_GC_FAR:
    2754             case DBGCVAR_TYPE_GC_FLAT:
    2755                 pOp = dbgcOpAddrFlat;
    2756                 break;
    2757             case DBGCVAR_TYPE_GC_PHYS:
    2758                 pOp = dbgcOpAddrPhys;
    2759                 break;
    2760             case DBGCVAR_TYPE_HC_FAR:
    2761             case DBGCVAR_TYPE_HC_FLAT:
    2762                 pOp = dbgcOpAddrHost;
    2763                 break;
    2764             case DBGCVAR_TYPE_HC_PHYS:
    2765                 pOp = dbgcOpAddrHostPhys;
    2766                 break;
    2767             case DBGCVAR_TYPE_NUMBER:
    2768                 break;
    2769             default:
    2770             case DBGCVAR_TYPE_STRING:
    2771                 AssertMsgFailed(("Can't happen\n"));
    2772                 break;
    2773         }
    2774         if (pOp)
    2775         {
    2776             int rc = pOp(pDbgc, pArg1, &Sym1);
    2777             if (VBOX_FAILURE(rc))
    2778                 return rc;
    2779             pArg1 = &Sym1;
    2780         }
    2781     }
    2782 
    2783 
    2784     /*
    2785      * Normal processing.
    2786      */
    2787     int         rc;
    2788     DBGCVAR     Var;
    2789     DBGCVAR     Var2;
    2790     switch (pArg1->enmType)
    2791     {
    2792         /*
    2793          * GC Flat
    2794          */
    2795         case DBGCVAR_TYPE_GC_FLAT:
    2796             switch (pArg2->enmType)
    2797             {
    2798                 case DBGCVAR_TYPE_HC_FLAT:
    2799                 case DBGCVAR_TYPE_HC_FAR:
    2800                 case DBGCVAR_TYPE_HC_PHYS:
    2801                     return VERR_PARSE_INVALID_OPERATION;
    2802                 default:
    2803                     *pResult = *pArg1;
    2804                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    2805                     if (VBOX_FAILURE(rc))
    2806                         return rc;
    2807                     pResult->u.GCFlat -= pArg2->u.GCFlat;
    2808                     break;
    2809             }
    2810             break;
    2811 
    2812         /*
    2813          * GC Far
    2814          */
    2815         case DBGCVAR_TYPE_GC_FAR:
    2816             switch (pArg2->enmType)
    2817             {
    2818                 case DBGCVAR_TYPE_HC_FLAT:
    2819                 case DBGCVAR_TYPE_HC_FAR:
    2820                 case DBGCVAR_TYPE_HC_PHYS:
    2821                     return VERR_PARSE_INVALID_OPERATION;
    2822                 case DBGCVAR_TYPE_NUMBER:
    2823                     *pResult = *pArg1;
    2824                     pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;
    2825                     break;
    2826                 default:
    2827                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    2828                     if (VBOX_FAILURE(rc))
    2829                         return rc;
    2830                     rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
    2831                     if (VBOX_FAILURE(rc))
    2832                         return rc;
    2833                     pResult->u.GCFlat -= pArg2->u.GCFlat;
    2834                     break;
    2835             }
    2836             break;
    2837 
    2838         /*
    2839          * GC Phys
    2840          */
    2841         case DBGCVAR_TYPE_GC_PHYS:
    2842             switch (pArg2->enmType)
    2843             {
    2844                 case DBGCVAR_TYPE_HC_FLAT:
    2845                 case DBGCVAR_TYPE_HC_FAR:
    2846                 case DBGCVAR_TYPE_HC_PHYS:
    2847                     return VERR_PARSE_INVALID_OPERATION;
    2848                 default:
    2849                     *pResult = *pArg1;
    2850                     rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
    2851                     if (VBOX_FAILURE(rc))
    2852                         return rc;
    2853                     if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
    2854                         return VERR_PARSE_INVALID_OPERATION;
    2855                     pResult->u.GCPhys -= Var.u.GCPhys;
    2856                     break;
    2857             }
    2858             break;
    2859 
    2860         /*
    2861          * HC Flat
    2862          */
    2863         case DBGCVAR_TYPE_HC_FLAT:
    2864             *pResult = *pArg1;
    2865             rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    2866             if (VBOX_FAILURE(rc))
    2867                 return rc;
    2868             rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    2869             if (VBOX_FAILURE(rc))
    2870                 return rc;
    2871             pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
    2872             break;
    2873 
    2874         /*
    2875          * HC Far
    2876          */
    2877         case DBGCVAR_TYPE_HC_FAR:
    2878             switch (pArg2->enmType)
    2879             {
    2880                 case DBGCVAR_TYPE_NUMBER:
    2881                     *pResult = *pArg1;
    2882                     pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;
    2883                     break;
    2884 
    2885                 default:
    2886                     rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
    2887                     if (VBOX_FAILURE(rc))
    2888                         return rc;
    2889                     rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
    2890                     if (VBOX_FAILURE(rc))
    2891                         return rc;
    2892                     rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
    2893                     if (VBOX_FAILURE(rc))
    2894                         return rc;
    2895                     pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
    2896                     break;
    2897             }
    2898             break;
    2899 
    2900         /*
    2901          * HC Phys
    2902          */
    2903         case DBGCVAR_TYPE_HC_PHYS:
    2904             *pResult = *pArg1;
    2905             rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
    2906             if (VBOX_FAILURE(rc))
    2907                 return rc;
    2908             pResult->u.HCPhys -= Var.u.HCPhys;
    2909             break;
    2910 
    2911         /*
    2912          * Numbers (see start of function)
    2913          */
    2914         case DBGCVAR_TYPE_NUMBER:
    2915             *pResult = *pArg1;
    2916             switch (pArg2->enmType)
    2917             {
    2918                 case DBGCVAR_TYPE_SYMBOL:
    2919                 case DBGCVAR_TYPE_STRING:
    2920                     rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    2921                     if (VBOX_FAILURE(rc))
    2922                         return rc;
    2923                 case DBGCVAR_TYPE_NUMBER:
    2924                     pResult->u.u64Number -= pArg2->u.u64Number;
    2925                     break;
    2926                 default:
    2927                     return VERR_PARSE_INVALID_OPERATION;
    2928             }
    2929             break;
    2930 
    2931         default:
    2932             return VERR_PARSE_INVALID_OPERATION;
    2933 
    2934     }
    2935     return 0;
    2936 }
    2937 
    2938 
    2939 /**
    2940  * Bitwise shift left operator (binary).
    2941  *
    2942  * @returns 0 on success.
    2943  * @returns VBox evaluation / parsing error code on failure.
    2944  *          The caller does the bitching.
    2945  * @param   pDbgc       Debugger console instance data.
    2946  * @param   pArg1       The first argument.
    2947  * @param   pArg2       The 2nd argument.
    2948  * @param   pResult     Where to store the result.
    2949  */
    2950 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2951 {
    2952     LogFlow(("dbgcOpBitwiseShiftLeft\n"));
    2953     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    2954     return -1;
    2955 }
    2956 
    2957 
    2958 /**
    2959  * Bitwise shift right operator (binary).
    2960  *
    2961  * @returns 0 on success.
    2962  * @returns VBox evaluation / parsing error code on failure.
    2963  *          The caller does the bitching.
    2964  * @param   pDbgc       Debugger console instance data.
    2965  * @param   pArg1       The first argument.
    2966  * @param   pArg2       The 2nd argument.
    2967  * @param   pResult     Where to store the result.
    2968  */
    2969 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2970 {
    2971     LogFlow(("dbgcOpBitwiseShiftRight\n"));
    2972     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    2973     return -1;
    2974 }
    2975 
    2976 
    2977 /**
    2978  * Bitwise and operator (binary).
    2979  *
    2980  * @returns 0 on success.
    2981  * @returns VBox evaluation / parsing error code on failure.
    2982  *          The caller does the bitching.
    2983  * @param   pDbgc       Debugger console instance data.
    2984  * @param   pArg1       The first argument.
    2985  * @param   pArg2       The 2nd argument.
    2986  * @param   pResult     Where to store the result.
    2987  */
    2988 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    2989 {
    2990     LogFlow(("dbgcOpBitwiseAnd\n"));
    2991     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    2992     return -1;
    2993 }
    2994 
    2995 
    2996 /**
    2997  * Bitwise exclusive or operator (binary).
    2998  *
    2999  * @returns 0 on success.
    3000  * @returns VBox evaluation / parsing error code on failure.
    3001  *          The caller does the bitching.
    3002  * @param   pDbgc       Debugger console instance data.
    3003  * @param   pArg1       The first argument.
    3004  * @param   pArg2       The 2nd argument.
    3005  * @param   pResult     Where to store the result.
    3006  */
    3007 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3008 {
    3009     LogFlow(("dbgcOpBitwiseXor\n"));
    3010     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    3011     return -1;
    3012 }
    3013 
    3014 
    3015 /**
    3016  * Bitwise inclusive or operator (binary).
    3017  *
    3018  * @returns 0 on success.
    3019  * @returns VBox evaluation / parsing error code on failure.
    3020  *          The caller does the bitching.
    3021  * @param   pDbgc       Debugger console instance data.
    3022  * @param   pArg1       The first argument.
    3023  * @param   pArg2       The 2nd argument.
    3024  * @param   pResult     Where to store the result.
    3025  */
    3026 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3027 {
    3028     LogFlow(("dbgcOpBitwiseOr\n"));
    3029     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    3030     return -1;
    3031 }
    3032 
    3033 
    3034 /**
    3035  * Boolean and operator (binary).
    3036  *
    3037  * @returns 0 on success.
    3038  * @returns VBox evaluation / parsing error code on failure.
    3039  *          The caller does the bitching.
    3040  * @param   pDbgc       Debugger console instance data.
    3041  * @param   pArg1       The first argument.
    3042  * @param   pArg2       The 2nd argument.
    3043  * @param   pResult     Where to store the result.
    3044  */
    3045 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3046 {
    3047     LogFlow(("dbgcOpBooleanAnd\n"));
    3048     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    3049     return -1;
    3050 }
    3051 
    3052 
    3053 /**
    3054  * Boolean or operator (binary).
    3055  *
    3056  * @returns 0 on success.
    3057  * @returns VBox evaluation / parsing error code on failure.
    3058  *          The caller does the bitching.
    3059  * @param   pDbgc       Debugger console instance data.
    3060  * @param   pArg1       The first argument.
    3061  * @param   pArg2       The 2nd argument.
    3062  * @param   pResult     Where to store the result.
    3063  */
    3064 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3065 {
    3066     LogFlow(("dbgcOpBooleanOr\n"));
    3067     NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
    3068     return -1;
    3069 }
    3070 
    3071 
    3072 /**
    3073  * Range to operator (binary).
    3074  *
    3075  * @returns 0 on success.
    3076  * @returns VBox evaluation / parsing error code on failure.
    3077  *          The caller does the bitching.
    3078  * @param   pDbgc       Debugger console instance data.
    3079  * @param   pArg1       The first argument.
    3080  * @param   pArg2       The 2nd argument.
    3081  * @param   pResult     Where to store the result.
    3082  */
    3083 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3084 {
    3085 //    LogFlow(("dbgcOpRangeLength\n"));
    3086     /*
    3087      * Make result. Strings needs to be resolved into symbols.
    3088      */
    3089     if (pArg1->enmType == DBGCVAR_TYPE_STRING)
    3090     {
    3091         int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
    3092         if (VBOX_FAILURE(rc))
    3093             return rc;
    3094     }
    3095     else
    3096         *pResult = *pArg1;
    3097 
    3098     /*
    3099      * Convert 2nd argument to element count.
    3100      */
    3101     pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;
    3102     switch (pArg2->enmType)
    3103     {
    3104         case DBGCVAR_TYPE_NUMBER:
    3105             pResult->u64Range = pArg2->u.u64Number;
    3106             break;
    3107 
    3108         case DBGCVAR_TYPE_STRING:
    3109         {
    3110             int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
    3111             if (VBOX_FAILURE(rc))
    3112                 return rc;
    3113             pResult->u64Range = pArg2->u.u64Number;
    3114             break;
    3115         }
    3116 
    3117         default:
    3118             return VERR_PARSE_INVALID_OPERATION;
    3119     }
    3120 
    3121     return VINF_SUCCESS;
    3122 }
    3123 
    3124 
    3125 /**
    3126  * Range to operator (binary).
    3127  *
    3128  * @returns 0 on success.
    3129  * @returns VBox evaluation / parsing error code on failure.
    3130  *          The caller does the bitching.
    3131  * @param   pDbgc       Debugger console instance data.
    3132  * @param   pArg1       The first argument.
    3133  * @param   pArg2       The 2nd argument.
    3134  * @param   pResult     Where to store the result.
    3135  */
    3136 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3137 {
    3138 //    LogFlow(("dbgcOpRangeLengthBytes\n"));
    3139     int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);
    3140     if (VBOX_SUCCESS(rc))
    3141         pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
    3142     return rc;
    3143 }
    3144 
    3145 
    3146 /**
    3147  * Range to operator (binary).
    3148  *
    3149  * @returns 0 on success.
    3150  * @returns VBox evaluation / parsing error code on failure.
    3151  *          The caller does the bitching.
    3152  * @param   pDbgc       Debugger console instance data.
    3153  * @param   pArg1       The first argument.
    3154  * @param   pArg2       The 2nd argument.
    3155  * @param   pResult     Where to store the result.
    3156  */
    3157 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
    3158 {
    3159 //    LogFlow(("dbgcOpRangeTo\n"));
    3160     /*
    3161      * Calc number of bytes between the two args.
    3162      */
    3163     DBGCVAR Diff;
    3164     int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);
    3165     if (VBOX_FAILURE(rc))
    3166         return rc;
    3167 
    3168     /*
    3169      * Use the diff as the range of Arg1.
    3170      */
    3171     *pResult = *pArg1;
    3172     pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
    3173     switch (Diff.enmType)
    3174     {
    3175         case DBGCVAR_TYPE_GC_FLAT:
    3176             pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;
    3177             break;
    3178         case DBGCVAR_TYPE_GC_PHYS:
    3179             pResult->u64Range = Diff.u.GCPhys;
    3180             break;
    3181         case DBGCVAR_TYPE_HC_FLAT:
    3182             pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;
    3183             break;
    3184         case DBGCVAR_TYPE_HC_PHYS:
    3185             pResult->u64Range = Diff.u.HCPhys;
    3186             break;
    3187         case DBGCVAR_TYPE_NUMBER:
    3188             pResult->u64Range = Diff.u.u64Number;
    3189             break;
    3190 
    3191         case DBGCVAR_TYPE_GC_FAR:
    3192         case DBGCVAR_TYPE_STRING:
    3193         case DBGCVAR_TYPE_HC_FAR:
    3194         default:
    3195             AssertMsgFailed(("Impossible!\n"));
    3196             return VERR_PARSE_INVALID_OPERATION;
    3197     }
    3198 
    3199     return 0;
    3200 }
    3201 
    3202 
    3203 
    3204 
    3205 
    3206 /**
    3207  * Output callback.
    3208  *
    3209  * @returns number of bytes written.
    3210  * @param   pvArg       User argument.
    3211  * @param   pachChars   Pointer to an array of utf-8 characters.
    3212  * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    3213  */
    3214 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
    3215 {
    3216     PDBGC   pDbgc = (PDBGC)pvArg;
    3217     if (cbChars)
    3218     {
    3219         int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
    3220         if (VBOX_FAILURE(rc))
    3221         {
    3222             pDbgc->rcOutput = rc;
    3223             cbChars = 0;
    3224         }
    3225     }
    3226 
    3227     return cbChars;
    3228 }
    3229 
    3230 
    3231 
    3232 
    3233 
    3234 
    3235 
    3236 
    3237 
    3238 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    3239 //
    3240 //
    32411704//      C a l l b a c k   H e l p e r s
    32421705//
     
    34011864    }
    34021865}
     1866
     1867
     1868/**
     1869 * Output callback.
     1870 *
     1871 * @returns number of bytes written.
     1872 * @param   pvArg       User argument.
     1873 * @param   pachChars   Pointer to an array of utf-8 characters.
     1874 * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
     1875 */
     1876static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
     1877{
     1878    PDBGC   pDbgc = (PDBGC)pvArg;
     1879    if (cbChars)
     1880    {
     1881        int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
     1882        if (VBOX_FAILURE(rc))
     1883        {
     1884            pDbgc->rcOutput = rc;
     1885            cbChars = 0;
     1886        }
     1887    }
     1888
     1889    return cbChars;
     1890}
     1891
    34031892
    34041893
     
    43492838 * @param   pResult     Where to store the result.
    43502839 */
    4351 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
     2840int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    43522841{
    43532842    /*
     
    44802969
    44812970/**
    4482  * Searches for an operator descriptor which matches the start of
    4483  * the expression given us.
    4484  *
    4485  * @returns Pointer to the operator on success.
    4486  * @param   pDbgc           The debug console instance.
    4487  * @param   pszExpr         Pointer to the expression string which might start with an operator.
    4488  * @param   fPreferBinary   Whether to favour binary or unary operators.
    4489  *                          Caller must assert that it's the disired type! Both types will still
    4490  *                          be returned, this is only for resolving duplicates.
    4491  * @param   chPrev          The previous char. Some operators requires a blank in front of it.
    4492  */
    4493 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
    4494 {
    4495     PCDBGCOP    pOp = NULL;
    4496     for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)
    4497     {
    4498         if (     g_aOps[iOp].szName[0] == pszExpr[0]
    4499             &&  (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])
    4500             &&  (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))
    4501         {
    4502             /*
    4503              * Check that we don't mistake it for some other operator which have more chars.
    4504              */
    4505             unsigned j;
    4506             for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)
    4507                 if (    g_aOps[j].cchName > g_aOps[iOp].cchName
    4508                     &&  g_aOps[j].szName[0] == pszExpr[0]
    4509                     &&  (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])
    4510                     &&  (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )
    4511                     break;
    4512             if (j < ELEMENTS(g_aOps))
    4513                 continue;       /* we'll catch it later. (for theoretical +,++,+++ cases.) */
    4514             pOp = &g_aOps[iOp];
    4515 
    4516             /*
    4517              * Prefered type?
    4518              */
    4519             if (g_aOps[iOp].fBinary == fPreferBinary)
    4520                 break;
    4521         }
    4522     }
    4523 
    4524     if (pOp)
    4525         Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));
    4526     NOREF(pDbgc); NOREF(chPrev);
    4527     return pOp;
    4528 }
    4529 
    4530 
    4531 /**
    45322971 * Initalizes g_bmOperatorChars.
    45332972 */
     
    45352974{
    45362975    memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    4537     for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)
     2976    for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    45382977        ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    45392978}
  • trunk/src/VBox/Debugger/Makefile.kmk

    r5669 r5673  
    3636Debugger_SOURCES   = \
    3737        DBGConsole.cpp \
     38        DBGCOps.cpp \
    3839        DBGCEmulateCodeView.cpp \
    3940        DBGCTcp.cpp
     
    9899        VBoxDbgStats.cpp \
    99100        DBGConsole.cpp \
     101        DBGCOps.cpp \
    100102        DBGCEmulateCodeView.cpp
    101103
Note: See TracChangeset for help on using the changeset viewer.

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