VirtualBox

Changeset 5674 in vbox


Ignore:
Timestamp:
Nov 11, 2007 5:34:02 AM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
26018
Message:

Split out the built-in symbols.

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

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/DBGCBuiltInSymbols.cpp

    r5673 r5674  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Built-In Symbols.
    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 
    10017
    10118
     
    13148*   Internal Functions                                                         *
    13249*******************************************************************************/
    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 
    15050static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    15151static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    152 
    153 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    154 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
    15552
    15653
     
    15855*   Global Variables                                                           *
    15956*******************************************************************************/
    160 /**
    161  * Pointer to head of the list of external commands.
    162  */
    163 static PDBGCEXTCMDS     g_pExtCmdsHead;     /** @todo rw protect g_pExtCmdsHead! */
    164 /** Locks the g_pExtCmdsHead list for reading. */
    165 #define DBGCEXTCMDS_LOCK_RD()       do { } while (0)
    166 /** Locks the g_pExtCmdsHead list for writing. */
    167 #define DBGCEXTCMDS_LOCK_WR()       do { } while (0)
    168 /** UnLocks the g_pExtCmdsHead list after reading. */
    169 #define DBGCEXTCMDS_UNLOCK_RD()     do { } while (0)
    170 /** UnLocks the g_pExtCmdsHead list after writing. */
    171 #define DBGCEXTCMDS_UNLOCK_WR()     do { } while (0)
    172 
    173 
    174 /** One argument of any kind. */
    175 static const DBGCVARDESC    g_aArgAny[] =
    176 {
    177     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    178     {  0,           1,          DBGCVAR_CAT_ANY,        0,                              "var",          "Any type of argument." },
    179 };
    180 
    181 /** Multiple string arguments (min 1). */
    182 static const DBGCVARDESC    g_aArgMultiStr[] =
    183 {
    184     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    185     {  1,           ~0,         DBGCVAR_CAT_STRING,     0,                              "strings",      "One or more strings." },
    186 };
    187 
    188 /** Filename string. */
    189 static const DBGCVARDESC    g_aArgFilename[] =
    190 {
    191     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    192     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    193 };
    194 
    195 
    196 /** 'help' arguments. */
    197 static const DBGCVARDESC    g_aArgHelp[] =
    198 {
    199     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    200     {  0,           ~0,         DBGCVAR_CAT_STRING,     0,                              "cmd/op",       "Zero or more command or operator names." },
    201 };
    202 
    203 
    204 /** 'info' arguments. */
    205 static const DBGCVARDESC    g_aArgInfo[] =
    206 {
    207     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    208     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "info",         "The name of the info to display." },
    209     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "args",         "String arguments to the handler." },
    210 };
    211 
    212 
    213 /** loadsyms arguments. */
    214 static const DBGCVARDESC    g_aArgLoadSyms[] =
    215 {
    216     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    217     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "path",         "Filename string." },
    218     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "delta",        "Delta to add to the loaded symbols. (optional)" },
    219     {  0,           1,          DBGCVAR_CAT_STRING,     0,                              "module name",  "Module name." },
    220     {  0,           1,          DBGCVAR_CAT_POINTER,    DBGCVD_FLAGS_DEP_PREV,          "module address", "Module address." },
    221     {  0,           1,          DBGCVAR_CAT_NUMBER,     0,                              "module size",  "The module size. (optional)" },
    222 };
    223 
    224 
    225 /** log arguments. */
    226 static const DBGCVARDESC    g_aArgLog[] =
    227 {
    228     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    229     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "groups",       "Group modifier string (quote it!)." }
    230 };
    231 
    232 
    233 /** logdest arguments. */
    234 static const DBGCVARDESC    g_aArgLogDest[] =
    235 {
    236     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    237     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "dests",        "Destination modifier string (quote it!)." }
    238 };
    239 
    240 
    241 /** logflags arguments. */
    242 static const DBGCVARDESC    g_aArgLogFlags[] =
    243 {
    244     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    245     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "flags",        "Flag modifier string (quote it!)." }
    246 };
    247 
    248 
    249 /** 'set' arguments */
    250 static const DBGCVARDESC    g_aArgSet[] =
    251 {
    252     /* cTimesMin,   cTimesMax,  enmCategory,            fFlags,                         pszName,        pszDescription */
    253     {  1,           1,          DBGCVAR_CAT_STRING,     0,                              "var",          "Variable name." },
    254     {  1,           1,          DBGCVAR_CAT_ANY,        0,                              "value",        "Value to assign to the variable." },
    255 };
    256 
    257 
    258 
    259 
    260 
    261 /** Command descriptors for the basic commands. */
    262 static const DBGCCMD    g_aCmds[] =
    263 {
    264     /* pszCmd,      cArgsMin, cArgsMax, paArgDescs,         cArgDescs,                  pResultDesc,        fFlags,     pfnHandler          pszSyntax,          ....pszDescription */
    265     { "bye",        0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    266     { "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." },
    267     { "exit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    268     { "format",     1,        1,        &g_aArgAny[0],      ELEMENTS(g_aArgAny),        NULL,               0,          dbgcCmdFormat,      "",                     "Evaluates an expression and formats it." },
    269     { "harakiri",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdHarakiri,    "",                     "Kills debugger process." },
    270     { "help",       0,        ~0,       &g_aArgHelp[0],     ELEMENTS(g_aArgHelp),       NULL,               0,          dbgcCmdHelp,        "[cmd/op [..]]",        "Display help. For help about info items try 'info help'." },
    271     { "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'." },
    272     { "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." },
    273     { "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." },
    274     { "log",        1,        1,        &g_aArgLog[0],      ELEMENTS(g_aArgLog),        NULL,               0,          dbgcCmdLog,         "<group string>",       "Modifies the logging group settings (VBOX_LOG)" },
    275     { "logdest",    1,        1,        &g_aArgLogDest[0],  ELEMENTS(g_aArgLogDest),    NULL,               0,          dbgcCmdLogDest,     "<dest string>",        "Modifies the logging destination (VBOX_LOG_DEST)." },
    276     { "logflags",   1,        1,        &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags),   NULL,               0,          dbgcCmdLogFlags,    "<flags string>",       "Modifies the logging flags (VBOX_LOG_FLAGS)." },
    277     { "quit",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdQuit,        "",                     "Exits the debugger." },
    278     { "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." },
    279     { "set",        2,        2,        &g_aArgSet[0],      ELEMENTS(g_aArgSet),        NULL,               0,          dbgcCmdSet,         "<var> <value>",        "Sets a global variable." },
    280     { "showvars",   0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdShowVars,    "",                     "List all the defined variables." },
    281     { "stop",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdStop,        "",                     "Stop execution." },
    282     { "unset",      1,        ~0,       &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr),   NULL,               0,          dbgcCmdUnset,       "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
    283 };
    284 
    285 
    28657/** Register symbol uUser value.
    28758 * @{
     
    450221
    451222
    452 /** Bitmap where set bits indicates the characters the may start an operator name. */
    453 static uint32_t g_bmOperatorChars[256 / (4*8)];
    454 
    455 
    456 
    457 
    458 
    459 
    460 
    461 
    462 /**
    463  * Prints full command help.
    464  */
    465 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal)
    466 {
    467     int rc;
    468 
    469     /* the command */
    470     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    471                             "%s%-*s %-30s %s",
    472                             fExternal ? "." : "",
    473                             fExternal ? 10 : 11,
    474                             pCmd->pszCmd,
    475                             pCmd->pszSyntax,
    476                             pCmd->pszDescription);
    477     if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax)
    478         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n");
    479     else if (pCmd->cArgsMin == pCmd->cArgsMax)
    480         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin);
    481     else if (pCmd->cArgsMax == ~0U)
    482         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin);
    483     else
    484         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax);
    485 
    486     /* argument descriptions. */
    487     for (unsigned i = 0; i < pCmd->cArgDescs; i++)
    488     {
    489         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    490                                 "    %-12s %s",
    491                                 pCmd->paArgDescs[i].pszName,
    492                                 pCmd->paArgDescs[i].pszDescription);
    493         if (!pCmd->paArgDescs[i].cTimesMin)
    494         {
    495             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    496                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n");
    497             else
    498                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax);
    499         }
    500         else
    501         {
    502             if (pCmd->paArgDescs[i].cTimesMax == ~0U)
    503                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin);
    504             else
    505                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
    506         }
    507     }
    508     return rc;
    509 }
    510 
    511 
    512 /**
    513  * The 'help' command.
    514  *
    515  * @returns VBox status.
    516  * @param   pCmd        Pointer to the command descriptor (as registered).
    517  * @param   pCmdHlp     Pointer to command helper functions.
    518  * @param   pVM         Pointer to the current VM (if any).
    519  * @param   paArgs      Pointer to (readonly) array of arguments.
    520  * @param   cArgs       Number of arguments in the array.
    521  */
    522 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    523 {
    524     PDBGC       pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    525     int         rc = VINF_SUCCESS;
    526     unsigned    i;
    527 
    528     if (!cArgs)
    529     {
    530         /*
    531          * All the stuff.
    532          */
    533         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    534                                 "VirtualBox Debugger\n"
    535                                 "-------------------\n"
    536                                 "\n"
    537                                 "Commands and Functions:\n");
    538         for (i = 0; i < ELEMENTS(g_aCmds); i++)
    539             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    540                                     "%-11s %-30s %s\n",
    541                                     g_aCmds[i].pszCmd,
    542                                     g_aCmds[i].pszSyntax,
    543                                     g_aCmds[i].pszDescription);
    544         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    545                                 "\n"
    546                                 "Emulation: %s\n", pDbgc->pszEmulation);
    547         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    548         for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++)
    549             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    550                                     "%-11s %-30s %s\n",
    551                                     pCmd->pszCmd,
    552                                     pCmd->pszSyntax,
    553                                     pCmd->pszDescription);
    554 
    555         if (g_pExtCmdsHead)
    556         {
    557             DBGCEXTCMDS_LOCK_RD();
    558             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    559                                     "\n"
    560                                     "External Commands and Functions:\n");
    561             for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    562                 for (i = 0; i < pExtCmd->cCmds; i++)
    563                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    564                                             ".%-10s %-30s %s\n",
    565                                             pExtCmd->paCmds[i].pszCmd,
    566                                             pExtCmd->paCmds[i].pszSyntax,
    567                                             pExtCmd->paCmds[i].pszDescription);
    568             DBGCEXTCMDS_UNLOCK_RD();
    569         }
    570 
    571         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    572                                 "\n"
    573                                 "Operators:\n");
    574         unsigned iPrecedence = 0;
    575         unsigned cLeft = g_cOps;
    576         while (cLeft > 0)
    577         {
    578             for (i = 0; i < g_cOps; i++)
    579                 if (g_aOps[i].iPrecedence == iPrecedence)
    580                 {
    581                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    582                                             "%-10s  %s  %s\n",
    583                                             g_aOps[i].szName,
    584                                             g_aOps[i].fBinary ? "Binary" : "Unary ",
    585                                             g_aOps[i].pszDescription);
    586                     cLeft--;
    587                 }
    588             iPrecedence++;
    589         }
    590     }
    591     else
    592     {
    593         /*
    594          * Search for the arguments (strings).
    595          */
    596         for (unsigned iArg = 0; iArg < cArgs; iArg++)
    597         {
    598             Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);
    599             bool fFound = false;
    600 
    601             /* lookup in the emulation command list first */
    602             for (i = 0; i < pDbgc->cEmulationCmds; i++)
    603                 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString))
    604                 {
    605                     rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);
    606                     fFound = true;
    607                     break;
    608                 }
    609 
    610             /* lookup in the command list (even when found in the emulation) */
    611             for (i = 0; i < ELEMENTS(g_aCmds); i++)
    612                 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString))
    613                 {
    614                     rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);
    615                     fFound = true;
    616                     break;
    617                 }
    618 
    619            /* external commands */
    620            if (     !fFound
    621                &&   g_pExtCmdsHead
    622                &&   paArgs[iArg].u.pszString[0] == '.')
    623            {
    624                DBGCEXTCMDS_LOCK_RD();
    625                for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
    626                    for (i = 0; i < pExtCmd->cCmds; i++)
    627                        if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1))
    628                        {
    629                            rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true);
    630                            fFound = true;
    631                            break;
    632                        }
    633                DBGCEXTCMDS_UNLOCK_RD();
    634            }
    635 
    636            /* operators */
    637            if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
    638            {
    639                for (i = 0; i < g_cOps; i++)
    640                    if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))
    641                    {
    642                        rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    643                                                "%-10s  %s  %s\n",
    644                                                g_aOps[i].szName,
    645                                                g_aOps[i].fBinary ? "Binary" : "Unary ",
    646                                                g_aOps[i].pszDescription);
    647                        fFound = true;
    648                        break;
    649                    }
    650            }
    651 
    652            /* found? */
    653            if (!fFound)
    654                rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    655                                        "error: '%s' was not found!\n",
    656                                        paArgs[iArg].u.pszString);
    657         } /* foreach argument */
    658     }
    659 
    660     NOREF(pCmd);
    661     NOREF(pVM);
    662     NOREF(pResult);
    663     return rc;
    664 }
    665 
    666 
    667 /**
    668  * The 'quit', 'exit' and 'bye' commands.
    669  *
    670  * @returns VBox status.
    671  * @param   pCmd        Pointer to the command descriptor (as registered).
    672  * @param   pCmdHlp     Pointer to command helper functions.
    673  * @param   pVM         Pointer to the current VM (if any).
    674  * @param   paArgs      Pointer to (readonly) array of arguments.
    675  * @param   cArgs       Number of arguments in the array.
    676  */
    677 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    678 {
    679     pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
    680     NOREF(pCmd);
    681     NOREF(pVM);
    682     NOREF(paArgs);
    683     NOREF(cArgs);
    684     NOREF(pResult);
    685     return VERR_DBGC_QUIT;
    686 }
    687 
    688 
    689 /**
    690  * The 'stop' command.
    691  *
    692  * @returns VBox status.
    693  * @param   pCmd        Pointer to the command descriptor (as registered).
    694  * @param   pCmdHlp     Pointer to command helper functions.
    695  * @param   pVM         Pointer to the current VM (if any).
    696  * @param   paArgs      Pointer to (readonly) array of arguments.
    697  * @param   cArgs       Number of arguments in the array.
    698  */
    699 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    700 {
    701     /*
    702      * Check if the VM is halted or not before trying to halt it.
    703      */
    704     int rc;
    705     if (DBGFR3IsHalted(pVM))
    706         rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
    707     else
    708     {
    709         rc = DBGFR3Halt(pVM);
    710         if (VBOX_SUCCESS(rc))
    711             rc = VWRN_DBGC_CMD_PENDING;
    712         else
    713             rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
    714     }
    715 
    716     NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    717     return rc;
    718 }
    719 
    720 
    721 /**
    722  * The 'echo' command.
    723  *
    724  * @returns VBox status.
    725  * @param   pCmd        Pointer to the command descriptor (as registered).
    726  * @param   pCmdHlp     Pointer to command helper functions.
    727  * @param   pVM         Pointer to the current VM (if any).
    728  * @param   paArgs      Pointer to (readonly) array of arguments.
    729  * @param   cArgs       Number of arguments in the array.
    730  */
    731 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    732 {
    733     /*
    734      * Loop thru the arguments and print them with one space between.
    735      */
    736     int rc = 0;
    737     for (unsigned i = 0; i < cArgs; i++)
    738     {
    739         if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
    740             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
    741         else
    742             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
    743         if (VBOX_FAILURE(rc))
    744             return rc;
    745     }
    746     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    747     return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
    748 }
    749 
    750 
    751 /**
    752  * The 'runscript' command.
    753  *
    754  * @returns VBox status.
    755  * @param   pCmd        Pointer to the command descriptor (as registered).
    756  * @param   pCmdHlp     Pointer to command helper functions.
    757  * @param   pVM         Pointer to the current VM (if any).
    758  * @param   paArgs      Pointer to (readonly) array of arguments.
    759  * @param   cArgs       Number of arguments in the array.
    760  */
    761 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    762 {
    763     /* check that the parser did what it's supposed to do. */
    764     if (    cArgs != 1
    765         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    766         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
    767 
    768     /*
    769      * Try open the script.
    770      */
    771     const char *pszFilename = paArgs[0].u.pszString;
    772     FILE *pFile = fopen(pszFilename, "r");
    773     if (!pFile)
    774         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
    775 
    776     /*
    777      * Execute it line by line.
    778      */
    779     int rc = 0;
    780     unsigned iLine = 0;
    781     char szLine[8192];
    782     while (fgets(szLine, sizeof(szLine), pFile))
    783     {
    784         /* check that the line isn't too long. */
    785         char *pszEnd = strchr(szLine, '\0');
    786         if (pszEnd == &szLine[sizeof(szLine) - 1])
    787         {
    788             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
    789             break;
    790         }
    791         iLine++;
    792 
    793         /* strip leading blanks and check for comment / blank line. */
    794         char *psz = RTStrStripL(szLine);
    795         if (    *psz == '\0'
    796             ||  *psz == '\n'
    797             ||  *psz == '#')
    798             continue;
    799 
    800         /* strip trailing blanks and check for empty line (\r case). */
    801         while (     pszEnd > psz
    802                &&   isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */
    803             *--pszEnd = '\0';
    804 
    805         /** @todo check for Control-C / Cancel at this point... */
    806 
    807         /*
    808          * Execute the command.
    809          *
    810          * This is a bit wasteful with scratch space btw., can fix it later.
    811          * The whole return code crap should be fixed too, so that it's possible
    812          * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and
    813          * more importantly why it failed.
    814          */
    815         rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
    816         if (VBOX_FAILURE(rc))
    817         {
    818             if (rc == VERR_BUFFER_OVERFLOW)
    819                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
    820             break;
    821         }
    822         if (rc == VWRN_DBGC_CMD_PENDING)
    823         {
    824             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
    825             break;
    826         }
    827     }
    828 
    829     fclose(pFile);
    830 
    831     NOREF(pCmd); NOREF(pResult); NOREF(pVM);
    832     return rc;
    833 }
    834 
    835 
    836 /**
    837  * Print formatted string.
    838  *
    839  * @param   pHlp        Pointer to this structure.
    840  * @param   pszFormat   The format string.
    841  * @param   ...         Arguments.
    842  */
    843 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
    844 {
    845     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    846     va_list args;
    847     va_start(args,  pszFormat);
    848     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    849     va_end(args);
    850 }
    851 
    852 
    853 /**
    854  * Print formatted string.
    855  *
    856  * @param   pHlp        Pointer to this structure.
    857  * @param   pszFormat   The format string.
    858  * @param   args        Argument list.
    859  */
    860 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
    861 {
    862     PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
    863     pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    864 }
    865 
    866 
    867 /**
    868  * The 'info' command.
    869  *
    870  * @returns VBox status.
    871  * @param   pCmd        Pointer to the command descriptor (as registered).
    872  * @param   pCmdHlp     Pointer to command helper functions.
    873  * @param   pVM         Pointer to the current VM (if any).
    874  * @param   paArgs      Pointer to (readonly) array of arguments.
    875  * @param   cArgs       Number of arguments in the array.
    876  */
    877 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    878 {
    879     /*
    880      * Validate input.
    881      */
    882     if (    cArgs < 1
    883         ||  cArgs > 2
    884         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING
    885         ||  paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
    886         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
    887     if (!pVM)
    888         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
    889 
    890     /*
    891      * Dump it.
    892      */
    893     struct
    894     {
    895         DBGFINFOHLP Hlp;
    896         PDBGCCMDHLP pCmdHlp;
    897     } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
    898     int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
    899     if (VBOX_FAILURE(rc))
    900         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
    901 
    902     NOREF(pCmd); NOREF(pResult);
    903     return 0;
    904 }
    905 
    906 
    907 /**
    908  * The 'log' command.
    909  *
    910  * @returns VBox status.
    911  * @param   pCmd        Pointer to the command descriptor (as registered).
    912  * @param   pCmdHlp     Pointer to command helper functions.
    913  * @param   pVM         Pointer to the current VM (if any).
    914  * @param   paArgs      Pointer to (readonly) array of arguments.
    915  * @param   cArgs       Number of arguments in the array.
    916  */
    917 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    918 {
    919     int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
    920     if (VBOX_SUCCESS(rc))
    921         return VINF_SUCCESS;
    922     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    923     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    924 }
    925 
    926 
    927 /**
    928  * The 'logdest' command.
    929  *
    930  * @returns VBox status.
    931  * @param   pCmd        Pointer to the command descriptor (as registered).
    932  * @param   pCmdHlp     Pointer to command helper functions.
    933  * @param   pVM         Pointer to the current VM (if any).
    934  * @param   paArgs      Pointer to (readonly) array of arguments.
    935  * @param   cArgs       Number of arguments in the array.
    936  */
    937 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    938 {
    939     int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
    940     if (VBOX_SUCCESS(rc))
    941         return VINF_SUCCESS;
    942     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    943     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    944 }
    945 
    946 
    947 /**
    948  * The 'logflags' command.
    949  *
    950  * @returns VBox status.
    951  * @param   pCmd        Pointer to the command descriptor (as registered).
    952  * @param   pCmdHlp     Pointer to command helper functions.
    953  * @param   pVM         Pointer to the current VM (if any).
    954  * @param   paArgs      Pointer to (readonly) array of arguments.
    955  * @param   cArgs       Number of arguments in the array.
    956  */
    957 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    958 {
    959     int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
    960     if (VBOX_SUCCESS(rc))
    961         return VINF_SUCCESS;
    962     NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
    963     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
    964 }
    965 
    966 
    967 /**
    968  * The 'format' command.
    969  *
    970  * @returns VBox status.
    971  * @param   pCmd        Pointer to the command descriptor (as registered).
    972  * @param   pCmdHlp     Pointer to command helper functions.
    973  * @param   pVM         Pointer to the current VM (if any).
    974  * @param   paArgs      Pointer to (readonly) array of arguments.
    975  * @param   cArgs       Number of arguments in the array.
    976  */
    977 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    978 {
    979     LogFlow(("dbgcCmdFormat\n"));
    980     static const char *apszRangeDesc[] =
    981     {
    982         "none", "bytes", "elements"
    983     };
    984     int rc;
    985 
    986     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    987     {
    988         switch (paArgs[iArg].enmType)
    989         {
    990             case DBGCVAR_TYPE_UNKNOWN:
    991                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    992                     "Unknown variable type!\n");
    993                 break;
    994             case DBGCVAR_TYPE_GC_FLAT:
    995                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    996                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    997                         "Guest flat address: %%%08x range %lld %s\n",
    998                         paArgs[iArg].u.GCFlat,
    999                         paArgs[iArg].u64Range,
    1000                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1001                 else
    1002                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1003                         "Guest flat address: %%%08x\n",
    1004                         paArgs[iArg].u.GCFlat);
    1005                 break;
    1006             case DBGCVAR_TYPE_GC_FAR:
    1007                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1008                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1009                         "Guest far address: %04x:%08x range %lld %s\n",
    1010                         paArgs[iArg].u.GCFar.sel,
    1011                         paArgs[iArg].u.GCFar.off,
    1012                         paArgs[iArg].u64Range,
    1013                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1014                 else
    1015                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1016                         "Guest far address: %04x:%08x\n",
    1017                         paArgs[iArg].u.GCFar.sel,
    1018                         paArgs[iArg].u.GCFar.off);
    1019                 break;
    1020             case DBGCVAR_TYPE_GC_PHYS:
    1021                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1022                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1023                         "Guest physical address: %%%%%08x range %lld %s\n",
    1024                         paArgs[iArg].u.GCPhys,
    1025                         paArgs[iArg].u64Range,
    1026                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1027                 else
    1028                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1029                         "Guest physical address: %%%%%08x\n",
    1030                         paArgs[iArg].u.GCPhys);
    1031                 break;
    1032             case DBGCVAR_TYPE_HC_FLAT:
    1033                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1034                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1035                         "Host flat address: %%%08x range %lld %s\n",
    1036                         paArgs[iArg].u.pvHCFlat,
    1037                         paArgs[iArg].u64Range,
    1038                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1039                 else
    1040                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1041                         "Host flat address: %%%08x\n",
    1042                         paArgs[iArg].u.pvHCFlat);
    1043                 break;
    1044             case DBGCVAR_TYPE_HC_FAR:
    1045                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1046                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1047                         "Host far address: %04x:%08x range %lld %s\n",
    1048                         paArgs[iArg].u.HCFar.sel,
    1049                         paArgs[iArg].u.HCFar.off,
    1050                         paArgs[iArg].u64Range,
    1051                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1052                 else
    1053                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1054                         "Host far address: %04x:%08x\n",
    1055                         paArgs[iArg].u.HCFar.sel,
    1056                         paArgs[iArg].u.HCFar.off);
    1057                 break;
    1058             case DBGCVAR_TYPE_HC_PHYS:
    1059                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1060                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1061                         "Host physical address: %VHp range %lld %s\n",
    1062                         paArgs[iArg].u.HCPhys,
    1063                         paArgs[iArg].u64Range,
    1064                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1065                 else
    1066                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1067                         "Host physical address: %VHp\n",
    1068                         paArgs[iArg].u.HCPhys);
    1069                 break;
    1070 
    1071             case DBGCVAR_TYPE_STRING:
    1072                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1073                     "String, %lld bytes long: %s\n",
    1074                     paArgs[iArg].u64Range,
    1075                     paArgs[iArg].u.pszString);
    1076                 break;
    1077 
    1078             case DBGCVAR_TYPE_NUMBER:
    1079                 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
    1080                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1081                         "Number: hex %llx  dec 0i%lld  oct 0t%llo  range %lld %s\n",
    1082                         paArgs[iArg].u.u64Number,
    1083                         paArgs[iArg].u.u64Number,
    1084                         paArgs[iArg].u.u64Number,
    1085                         paArgs[iArg].u64Range,
    1086                         apszRangeDesc[paArgs[iArg].enmRangeType]);
    1087                 else
    1088                     rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1089                         "Number: hex %llx  dec 0i%lld  oct 0t%llo\n",
    1090                         paArgs[iArg].u.u64Number,
    1091                         paArgs[iArg].u.u64Number,
    1092                         paArgs[iArg].u.u64Number);
    1093                 break;
    1094 
    1095             default:
    1096                 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1097                     "Invalid argument type %d\n",
    1098                     paArgs[iArg].enmType);
    1099                 break;
    1100         }
    1101     } /* arg loop */
    1102 
    1103     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1104     return 0;
    1105 }
    1106 
    1107 
    1108 /**
    1109  * The 'loadsyms' command.
    1110  *
    1111  * @returns VBox status.
    1112  * @param   pCmd        Pointer to the command descriptor (as registered).
    1113  * @param   pCmdHlp     Pointer to command helper functions.
    1114  * @param   pVM         Pointer to the current VM (if any).
    1115  * @param   paArgs      Pointer to (readonly) array of arguments.
    1116  * @param   cArgs       Number of arguments in the array.
    1117  */
    1118 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1119 {
    1120     /*
    1121      * Validate the parsing and make sense of the input.
    1122      * This is a mess as usual because we don't trust the parser yet.
    1123      */
    1124     if (    cArgs < 1
    1125         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1126     {
    1127         AssertMsgFailed(("Parse error, first argument required to be string!\n"));
    1128         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1129     }
    1130     DBGCVAR     AddrVar;
    1131     RTGCUINTPTR Delta = 0;
    1132     const char *pszModule = NULL;
    1133     RTGCUINTPTR ModuleAddress = 0;
    1134     unsigned    cbModule = 0;
    1135     if (cArgs > 1)
    1136     {
    1137         unsigned iArg = 1;
    1138         if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
    1139         {
    1140             Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
    1141             iArg++;
    1142         }
    1143         if (iArg < cArgs)
    1144         {
    1145             if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
    1146             {
    1147                 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
    1148                 return VERR_PARSE_INCORRECT_ARG_TYPE;
    1149             }
    1150             pszModule = paArgs[iArg].u.pszString;
    1151             iArg++;
    1152             if (iArg < cArgs)
    1153             {
    1154                 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
    1155                 {
    1156                     AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
    1157                     return VERR_PARSE_INCORRECT_ARG_TYPE;
    1158                 }
    1159                 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
    1160                 if (VBOX_FAILURE(rc))
    1161                     return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
    1162                 ModuleAddress = paArgs[iArg].u.GCFlat;
    1163                 iArg++;
    1164                 if (iArg < cArgs)
    1165                 {
    1166                     if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
    1167                     {
    1168                         AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
    1169                         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1170                     }
    1171                     cbModule = (unsigned)paArgs[iArg].u.u64Number;
    1172                     iArg++;
    1173                     if (iArg < cArgs)
    1174                     {
    1175                         AssertMsgFailed(("Parse error, too many arguments!\n"));
    1176                         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1177                     }
    1178                 }
    1179             }
    1180         }
    1181     }
    1182 
    1183     /*
    1184      * Call the debug info manager about this loading...
    1185      */
    1186     int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
    1187     if (VBOX_FAILURE(rc))
    1188         return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",
    1189                                      paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
    1190 
    1191     NOREF(pCmd); NOREF(pResult);
    1192     return VINF_SUCCESS;
    1193 }
    1194 
    1195 
    1196 /**
    1197  * The 'set' command.
    1198  *
    1199  * @returns VBox status.
    1200  * @param   pCmd        Pointer to the command descriptor (as registered).
    1201  * @param   pCmdHlp     Pointer to command helper functions.
    1202  * @param   pVM         Pointer to the current VM (if any).
    1203  * @param   paArgs      Pointer to (readonly) array of arguments.
    1204  * @param   cArgs       Number of arguments in the array.
    1205  */
    1206 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1207 {
    1208     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1209 
    1210     /* parse sanity check. */
    1211     AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
    1212     if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1213         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1214 
    1215 
    1216     /*
    1217      * A variable must start with an alpha chars and only contain alpha numerical chars.
    1218      */
    1219     const char *pszVar = paArgs[0].u.pszString;
    1220     if (!isalpha(*pszVar) || *pszVar == '_')
    1221         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1222             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
    1223 
    1224     while (isalnum(*pszVar) || *pszVar == '_')
    1225         *pszVar++;
    1226     if (*pszVar)
    1227         return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
    1228             "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
    1229 
    1230 
    1231     /*
    1232      * Calc variable size.
    1233      */
    1234     size_t  cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
    1235     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1236         cbVar += 1 + (size_t)paArgs[1].u64Range;
    1237 
    1238     /*
    1239      * Look for existing one.
    1240      */
    1241     pszVar = paArgs[0].u.pszString;
    1242     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1243     {
    1244         if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    1245         {
    1246             /*
    1247              * Update existing variable.
    1248              */
    1249             void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
    1250             if (!pv)
    1251                 return VERR_PARSE_NO_MEMORY;
    1252             PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
    1253 
    1254             pVar->Var = paArgs[1];
    1255             memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
    1256             if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1257                 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    1258             return 0;
    1259         }
    1260     }
    1261 
    1262     /*
    1263      * Allocate another.
    1264      */
    1265     PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
    1266 
    1267     pVar->Var = paArgs[1];
    1268     memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
    1269     if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
    1270         pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
    1271 
    1272     /* need to reallocate the pointer array too? */
    1273     if (!(pDbgc->cVars % 0x20))
    1274     {
    1275         void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
    1276         if (!pv)
    1277         {
    1278             RTMemFree(pVar);
    1279             return VERR_PARSE_NO_MEMORY;
    1280         }
    1281         pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
    1282     }
    1283     pDbgc->papVars[pDbgc->cVars++] = pVar;
    1284 
    1285     NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
    1286     return 0;
    1287 }
    1288 
    1289 
    1290 /**
    1291  * The 'unset' command.
    1292  *
    1293  * @returns VBox status.
    1294  * @param   pCmd        Pointer to the command descriptor (as registered).
    1295  * @param   pCmdHlp     Pointer to command helper functions.
    1296  * @param   pVM         Pointer to the current VM (if any).
    1297  * @param   paArgs      Pointer to (readonly) array of arguments.
    1298  * @param   cArgs       Number of arguments in the array.
    1299  */
    1300 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1301 {
    1302     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1303 
    1304     /*
    1305      * Don't trust the parser.
    1306      */
    1307     for (unsigned  i = 0; i < cArgs; i++)
    1308         if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
    1309         {
    1310             AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
    1311             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1312         }
    1313 
    1314     /*
    1315      * Iterate the variables and unset them.
    1316      */
    1317     for (unsigned iArg = 0; iArg < cArgs; iArg++)
    1318     {
    1319         const char *pszVar = paArgs[iArg].u.pszString;
    1320 
    1321         /*
    1322          * Look up the variable.
    1323          */
    1324         for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1325         {
    1326             if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
    1327             {
    1328                 /*
    1329                  * Shuffle the array removing this entry.
    1330                  */
    1331                 void *pvFree = pDbgc->papVars[iVar];
    1332                 if (iVar + 1 < pDbgc->cVars)
    1333                     memmove(&pDbgc->papVars[iVar],
    1334                             &pDbgc->papVars[iVar + 1],
    1335                             (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
    1336                 pDbgc->papVars[--pDbgc->cVars] = NULL;
    1337 
    1338                 RTMemFree(pvFree);
    1339             }
    1340         } /* lookup */
    1341     } /* arg loop */
    1342 
    1343     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1344     return 0;
    1345 }
    1346 
    1347 
    1348 /**
    1349  * The 'loadvars' command.
    1350  *
    1351  * @returns VBox status.
    1352  * @param   pCmd        Pointer to the command descriptor (as registered).
    1353  * @param   pCmdHlp     Pointer to command helper functions.
    1354  * @param   pVM         Pointer to the current VM (if any).
    1355  * @param   paArgs      Pointer to (readonly) array of arguments.
    1356  * @param   cArgs       Number of arguments in the array.
    1357  */
    1358 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1359 {
    1360     /*
    1361      * Don't trust the parser.
    1362      */
    1363     if (    cArgs != 1
    1364         ||  paArgs[0].enmType != DBGCVAR_TYPE_STRING)
    1365     {
    1366         AssertMsgFailed(("Expected one string exactly!\n"));
    1367         return VERR_PARSE_INCORRECT_ARG_TYPE;
    1368     }
    1369 
    1370     /*
    1371      * Iterate the variables and unset them.
    1372      */
    1373     FILE *pFile = fopen(paArgs[0].u.pszString, "r");
    1374     if (pFile)
    1375     {
    1376         char szLine[4096];
    1377         while (fgets(szLine, sizeof(szLine), pFile))
    1378         {
    1379             /* Strip it. */
    1380             char *psz = szLine;
    1381             while (isblank(*psz))
    1382                 psz++;
    1383             int i = (int)strlen(psz) - 1;
    1384             while (i >= 0 && isspace(psz[i]))
    1385                 psz[i--] ='\0';
    1386             /* Execute it if not comment or empty line. */
    1387             if (    *psz != '\0'
    1388                 &&  *psz != '#'
    1389                 &&  *psz != ';')
    1390             {
    1391                 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
    1392                 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
    1393             }
    1394         }
    1395         fclose(pFile);
    1396     }
    1397     else
    1398         return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
    1399 
    1400     NOREF(pCmd); NOREF(pVM); NOREF(pResult);
    1401     return 0;
    1402 }
    1403 
    1404 
    1405 /**
    1406  * The 'showvars' command.
    1407  *
    1408  * @returns VBox status.
    1409  * @param   pCmd        Pointer to the command descriptor (as registered).
    1410  * @param   pCmdHlp     Pointer to command helper functions.
    1411  * @param   pVM         Pointer to the current VM (if any).
    1412  * @param   paArgs      Pointer to (readonly) array of arguments.
    1413  * @param   cArgs       Number of arguments in the array.
    1414  */
    1415 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1416 {
    1417     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1418 
    1419     for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
    1420     {
    1421         int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
    1422         if (!rc)
    1423             rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
    1424         if (rc)
    1425             return rc;
    1426     }
    1427 
    1428     NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    1429     return 0;
    1430 }
    1431 
    1432 
    1433 /**
    1434  * The 'harakiri' command.
    1435  *
    1436  * @returns VBox status.
    1437  * @param   pCmd        Pointer to the command descriptor (as registered).
    1438  * @param   pCmdHlp     Pointer to command helper functions.
    1439  * @param   pVM         Pointer to the current VM (if any).
    1440  * @param   paArgs      Pointer to (readonly) array of arguments.
    1441  * @param   cArgs       Number of arguments in the array.
    1442  */
    1443 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
    1444 {
    1445     Log(("dbgcCmdHarakiri\n"));
    1446     for (;;)
    1447         exit(126);
    1448     NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
    1449 }
    1450 
    1451 
    1452 
    1453 
    1454 
    1455 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1456 //
    1457 //
    1458 //      B u l t i n   S y m b o l s
    1459 //
    1460 //
    1461 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1462 
    1463 
    1464223
    1465224/**
     
    1694453
    1695454
    1696 
    1697 
    1698 
    1699 
    1700 
    1701 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1702 //
    1703 //
    1704 //      C a l l b a c k   H e l p e r s
    1705 //
    1706 //
    1707 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1708 
    1709 
    1710 
    1711 /**
    1712  * Command helper for writing text to the debug console.
    1713  *
    1714  * @returns VBox status.
    1715  * @param   pCmdHlp     Pointer to the command callback structure.
    1716  * @param   pvBuf       What to write.
    1717  * @param   cbBuf       Number of bytes to write.
    1718  * @param   pcbWritten  Where to store the number of bytes actually written.
    1719  *                      If NULL the entire buffer must be successfully written.
    1720  */
    1721 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    1722 {
    1723     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1724     return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
    1725 }
    1726 
    1727 
    1728 /**
    1729  * Command helper for writing formatted text to the debug console.
    1730  *
    1731  * @returns VBox status.
    1732  * @param   pCmdHlp     Pointer to the command callback structure.
    1733  * @param   pcb         Where to store the number of bytes written.
    1734  * @param   pszFormat   The format string.
    1735  *                      This is using the log formatter, so it's format extensions can be used.
    1736  * @param   ...         Arguments specified in the format string.
    1737  */
    1738 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
    1739 {
    1740     /*
    1741      * Do the formatting and output.
    1742      */
    1743     va_list args;
    1744     va_start(args, pszFormat);
    1745     int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
    1746     va_end(args);
    1747 
    1748     return rc;
    1749 }
    1750 
    1751 /**
    1752  * Callback to format non-standard format specifiers.
    1753  *
    1754  * @returns The number of bytes formatted.
    1755  * @param   pvArg           Formatter argument.
    1756  * @param   pfnOutput       Pointer to output function.
    1757  * @param   pvArgOutput     Argument for the output function.
    1758  * @param   ppszFormat      Pointer to the format string pointer. Advance this till the char
    1759  *                          after the format specifier.
    1760  * @param   pArgs           Pointer to the argument list. Use this to fetch the arguments.
    1761  * @param   cchWidth        Format Width. -1 if not specified.
    1762  * @param   cchPrecision    Format Precision. -1 if not specified.
    1763  * @param   fFlags          Flags (RTSTR_NTFS_*).
    1764  * @param   chArgSize       The argument size specifier, 'l' or 'L'.
    1765  */
    1766 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
    1767                                                 const char **ppszFormat, va_list *pArgs, int cchWidth,
    1768                                                 int cchPrecision, unsigned fFlags, char chArgSize)
    1769 {
    1770     NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
    1771     if (**ppszFormat != 'D')
    1772     {
    1773         (*ppszFormat)++;
    1774         return 0;
    1775     }
    1776 
    1777     (*ppszFormat)++;
    1778     switch (**ppszFormat)
    1779     {
    1780         /*
    1781          * Print variable without range.
    1782          * The argument is a const pointer to the variable.
    1783          */
    1784         case 'V':
    1785         {
    1786             (*ppszFormat)++;
    1787             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    1788             switch (pVar->enmType)
    1789             {
    1790                 case DBGCVAR_TYPE_GC_FLAT:
    1791                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
    1792                 case DBGCVAR_TYPE_GC_FAR:
    1793                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
    1794                 case DBGCVAR_TYPE_GC_PHYS:
    1795                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
    1796                 case DBGCVAR_TYPE_HC_FLAT:
    1797                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
    1798                 case DBGCVAR_TYPE_HC_FAR:
    1799                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
    1800                 case DBGCVAR_TYPE_HC_PHYS:
    1801                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
    1802                 case DBGCVAR_TYPE_STRING:
    1803                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    1804                 case DBGCVAR_TYPE_NUMBER:
    1805                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
    1806 
    1807                 case DBGCVAR_TYPE_UNKNOWN:
    1808                 default:
    1809                     return pfnOutput(pvArgOutput, "??", 2);
    1810             }
    1811         }
    1812 
    1813         /*
    1814          * Print variable with range.
    1815          * The argument is a const pointer to the variable.
    1816          */
    1817         case 'v':
    1818         {
    1819             (*ppszFormat)++;
    1820             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    1821 
    1822             char szRange[32];
    1823             switch (pVar->enmRangeType)
    1824             {
    1825                 case DBGCVAR_RANGE_NONE:
    1826                     szRange[0] = '\0';
    1827                     break;
    1828                 case DBGCVAR_RANGE_ELEMENTS:
    1829                     RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
    1830                     break;
    1831                 case DBGCVAR_RANGE_BYTES:
    1832                     RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
    1833                     break;
    1834             }
    1835 
    1836             switch (pVar->enmType)
    1837             {
    1838                 case DBGCVAR_TYPE_GC_FLAT:
    1839                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
    1840                 case DBGCVAR_TYPE_GC_FAR:
    1841                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
    1842                 case DBGCVAR_TYPE_GC_PHYS:
    1843                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
    1844                 case DBGCVAR_TYPE_HC_FLAT:
    1845                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
    1846                 case DBGCVAR_TYPE_HC_FAR:
    1847                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
    1848                 case DBGCVAR_TYPE_HC_PHYS:
    1849                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
    1850                 case DBGCVAR_TYPE_STRING:
    1851                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    1852                 case DBGCVAR_TYPE_NUMBER:
    1853                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
    1854 
    1855                 case DBGCVAR_TYPE_UNKNOWN:
    1856                 default:
    1857                     return pfnOutput(pvArgOutput, "??", 2);
    1858             }
    1859         }
    1860 
    1861         default:
    1862             AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
    1863             return 0;
    1864     }
    1865 }
    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  */
    1876 static 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 
    1892 
    1893 
    1894 /**
    1895  * Command helper for writing formatted text to the debug console.
    1896  *
    1897  * @returns VBox status.
    1898  * @param   pCmdHlp     Pointer to the command callback structure.
    1899  * @param   pcb         Where to store the number of bytes written.
    1900  * @param   pszFormat   The format string.
    1901  *                      This is using the log formatter, so it's format extensions can be used.
    1902  * @param   args        Arguments specified in the format string.
    1903  */
    1904 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
    1905 {
    1906     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1907 
    1908     /*
    1909      * Do the formatting and output.
    1910      */
    1911     pDbgc->rcOutput = 0;
    1912     size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
    1913 
    1914     if (pcbWritten)
    1915         *pcbWritten = cb;
    1916 
    1917     return pDbgc->rcOutput;
    1918 }
    1919 
    1920 
    1921 /**
    1922  * Reports an error from a DBGF call.
    1923  *
    1924  * @returns VBox status code appropriate to return from a command.
    1925  * @param   pCmdHlp     Pointer to command helpers.
    1926  * @param   rc          The VBox status code returned by a DBGF call.
    1927  * @param   pszFormat   Format string for additional messages. Can be NULL.
    1928  * @param   ...         Format arguments, optional.
    1929  */
    1930 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
    1931 {
    1932     switch (rc)
    1933     {
    1934         case VINF_SUCCESS:
    1935             break;
    1936 
    1937         default:
    1938             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
    1939             if (VBOX_SUCCESS(rc) && pszFormat)
    1940                 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    1941             break;
    1942     }
    1943     return rc;
    1944 }
    1945 
    1946 
    1947 /**
    1948  * Reports an error from a DBGF call.
    1949  *
    1950  * @returns VBox status code appropriate to return from a command.
    1951  * @param   pCmdHlp     Pointer to command helpers.
    1952  * @param   rc          The VBox status code returned by a DBGF call.
    1953  * @param   pszFormat   Format string for additional messages. Can be NULL.
    1954  * @param   ...         Format arguments, optional.
    1955  */
    1956 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
    1957 {
    1958     va_list args;
    1959     va_start(args, pszFormat);
    1960     int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
    1961     va_end(args);
    1962     return rcRet;
    1963 }
    1964 
    1965 
    1966 /**
    1967  * Command helper for reading memory specified by a DBGC variable.
    1968  *
    1969  * @returns VBox status code appropriate to return from a command.
    1970  * @param   pCmdHlp     Pointer to the command callback structure.
    1971  * @param   pVM         VM handle if GC or physical HC address.
    1972  * @param   pvBuffer    Where to store the read data.
    1973  * @param   cbRead      Number of bytes to read.
    1974  * @param   pVarPointer DBGC variable specifying where to start reading.
    1975  * @param   pcbRead     Where to store the number of bytes actually read.
    1976  *                      This optional, but it's useful when read GC virtual memory where a
    1977  *                      page in the requested range might not be present.
    1978  *                      If not specified not-present failure or end of a HC physical page
    1979  *                      will cause failure.
    1980  */
    1981 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
    1982 {
    1983     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1984 
    1985     /*
    1986      * Dummy check.
    1987      */
    1988     if (cbRead == 0)
    1989     {
    1990         if (*pcbRead)
    1991             *pcbRead = 0;
    1992         return VINF_SUCCESS;
    1993     }
    1994 
    1995     /*
    1996      * Convert Far addresses getting size and the correct base address.
    1997      * Getting and checking the size is what makes this messy and slow.
    1998      */
    1999     DBGCVAR Var = *pVarPointer;
    2000     switch (pVarPointer->enmType)
    2001     {
    2002         case DBGCVAR_TYPE_GC_FAR:
    2003         {
    2004             /* Use DBGFR3AddrFromSelOff for the conversion. */
    2005             Assert(pDbgc->pVM);
    2006             DBGFADDRESS Address;
    2007             int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
    2008             if (VBOX_FAILURE(rc))
    2009                 return rc;
    2010 
    2011             /* don't bother with flat selectors (for now). */
    2012             if (!DBGFADDRESS_IS_FLAT(&Address))
    2013             {
    2014                 SELMSELINFO SelInfo;
    2015                 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
    2016                 if (VBOX_SUCCESS(rc))
    2017                 {
    2018                     RTGCUINTPTR cb; /* -1 byte */
    2019                     if (SELMSelInfoIsExpandDown(&SelInfo))
    2020                     {
    2021                         if (    !SelInfo.Raw.Gen.u1Granularity
    2022                             &&  Address.off > UINT16_C(0xffff))
    2023                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    2024                         if (Address.off <= SelInfo.cbLimit)
    2025                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    2026                         cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
    2027                     }
    2028                     else
    2029                     {
    2030                         if (Address.off > SelInfo.cbLimit)
    2031                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    2032                         cb = SelInfo.cbLimit - Address.off;
    2033                     }
    2034                     if (cbRead - 1 > cb)
    2035                     {
    2036                         if (!pcbRead)
    2037                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    2038                         cbRead = cb + 1;
    2039                     }
    2040                 }
    2041 
    2042                 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
    2043                 Var.u.GCFlat = Address.FlatPtr;
    2044             }
    2045             break;
    2046         }
    2047 
    2048         case DBGCVAR_TYPE_GC_FLAT:
    2049         case DBGCVAR_TYPE_GC_PHYS:
    2050         case DBGCVAR_TYPE_HC_FLAT:
    2051         case DBGCVAR_TYPE_HC_PHYS:
    2052             break;
    2053 
    2054         case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
    2055         default:
    2056             return VERR_NOT_IMPLEMENTED;
    2057     }
    2058 
    2059 
    2060 
    2061     /*
    2062      * Copy page by page.
    2063      */
    2064     size_t cbLeft = cbRead;
    2065     for (;;)
    2066     {
    2067         /*
    2068          * Calc read size.
    2069          */
    2070         size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
    2071         switch (pVarPointer->enmType)
    2072         {
    2073             case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
    2074             case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
    2075             case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
    2076             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! */
    2077             default: break;
    2078         }
    2079 
    2080         /*
    2081          * Perform read.
    2082          */
    2083         int rc;
    2084         switch (Var.enmType)
    2085         {
    2086             case DBGCVAR_TYPE_GC_FLAT:
    2087                 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
    2088                 break;
    2089             case DBGCVAR_TYPE_GC_PHYS:
    2090                 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
    2091                 break;
    2092 
    2093             case DBGCVAR_TYPE_HC_PHYS:
    2094             case DBGCVAR_TYPE_HC_FLAT:
    2095             case DBGCVAR_TYPE_HC_FAR:
    2096             {
    2097                 DBGCVAR Var2;
    2098                 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
    2099                 if (VBOX_SUCCESS(rc))
    2100                 {
    2101                     /** @todo protect this!!! */
    2102                     memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
    2103                     rc = 0;
    2104                 }
    2105                 else
    2106                     rc = VERR_INVALID_POINTER;
    2107                 break;
    2108             }
    2109 
    2110             default:
    2111                 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
    2112         }
    2113 
    2114         /*
    2115          * Check for failure.
    2116          */
    2117         if (VBOX_FAILURE(rc))
    2118         {
    2119             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    2120                 return VINF_SUCCESS;
    2121             return rc;
    2122         }
    2123 
    2124         /*
    2125          * Next.
    2126          */
    2127         cbLeft -= cb;
    2128         if (!cbLeft)
    2129             break;
    2130         pvBuffer = (char *)pvBuffer + cb;
    2131         rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
    2132         if (VBOX_FAILURE(rc))
    2133         {
    2134             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    2135                 return VINF_SUCCESS;
    2136             return rc;
    2137         }
    2138     }
    2139 
    2140     /*
    2141      * Done
    2142      */
    2143     if (pcbRead)
    2144         *pcbRead = cbRead;
    2145     return 0;
    2146 }
    2147 
    2148 /**
    2149  * Command helper for writing memory specified by a DBGC variable.
    2150  *
    2151  * @returns VBox status code appropriate to return from a command.
    2152  * @param   pCmdHlp     Pointer to the command callback structure.
    2153  * @param   pVM         VM handle if GC or physical HC address.
    2154  * @param   pvBuffer    What to write.
    2155  * @param   cbWrite     Number of bytes to write.
    2156  * @param   pVarPointer DBGC variable specifying where to start reading.
    2157  * @param   pcbWritten  Where to store the number of bytes written.
    2158  *                      This is optional. If NULL be aware that some of the buffer
    2159  *                      might have been written to the specified address.
    2160  */
    2161 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
    2162 {
    2163     NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
    2164     return VERR_NOT_IMPLEMENTED;
    2165 }
    2166 
    2167 
    2168 /**
    2169  * Evaluates an expression.
    2170  * (Hopefully the parser and functions are fully reentrant.)
    2171  *
    2172  * @returns VBox status code appropriate to return from a command.
    2173  * @param   pCmdHlp     Pointer to the command callback structure.
    2174  * @param   pResult     Where to store the result.
    2175  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    2176  * @param   ...         Format arguments.
    2177  */
    2178 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
    2179 {
    2180     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2181 
    2182     /*
    2183      * Format the expression.
    2184      */
    2185     char szExprFormatted[2048];
    2186     va_list args;
    2187     va_start(args, pszExpr);
    2188     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
    2189     va_end(args);
    2190     /* ignore overflows. */
    2191 
    2192     return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
    2193 }
    2194 
    2195 
    2196 /**
    2197  * Executes one command expression.
    2198  * (Hopefully the parser and functions are fully reentrant.)
    2199  *
    2200  * @returns VBox status code appropriate to return from a command.
    2201  * @param   pCmdHlp     Pointer to the command callback structure.
    2202  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    2203  * @param   ...         Format arguments.
    2204  */
    2205 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
    2206 {
    2207     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2208     /* Save the scratch state. */
    2209     char       *pszScratch  = pDbgc->pszScratch;
    2210     unsigned    iArg        = pDbgc->iArg;
    2211 
    2212     /*
    2213      * Format the expression.
    2214      */
    2215     va_list args;
    2216     va_start(args, pszExpr);
    2217     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    2218     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
    2219     va_end(args);
    2220     if (cb >= cbScratch)
    2221         return VERR_BUFFER_OVERFLOW;
    2222 
    2223     /*
    2224      * Execute the command.
    2225      * We save and restore the arg index and scratch buffer pointer.
    2226      */
    2227     pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
    2228     int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
    2229 
    2230     /* Restore the scratch state. */
    2231     pDbgc->iArg         = iArg;
    2232     pDbgc->pszScratch   = pszScratch;
    2233 
    2234     return rc;
    2235 }
    2236 
    2237 
    2238 /**
    2239  * Converts a DBGC variable to a DBGF address structure.
    2240  *
    2241  * @returns VBox status code.
    2242  * @param   pCmdHlp     Pointer to the command callback structure.
    2243  * @param   pVar        The variable to convert.
    2244  * @param   pAddress    The target address.
    2245  */
    2246 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    2247 {
    2248     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2249     return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
    2250 }
    2251 
    2252 
    2253 /**
    2254  * Converts a DBGC variable to a boolean.
    2255  *
    2256  * @returns VBox status code.
    2257  * @param   pCmdHlp     Pointer to the command callback structure.
    2258  * @param   pVar        The variable to convert.
    2259  * @param   pf          Where to store the boolean.
    2260  */
    2261 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
    2262 {
    2263     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    2264     NOREF(pDbgc);
    2265 
    2266     switch (pVar->enmType)
    2267     {
    2268         case DBGCVAR_TYPE_STRING:
    2269             /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
    2270             if (    !strcmp(pVar->u.pszString, "true")
    2271                 ||  !strcmp(pVar->u.pszString, "True")
    2272                 ||  !strcmp(pVar->u.pszString, "TRUE")
    2273                 ||  !strcmp(pVar->u.pszString, "on")
    2274                 ||  !strcmp(pVar->u.pszString, "On")
    2275                 ||  !strcmp(pVar->u.pszString, "oN")
    2276                 ||  !strcmp(pVar->u.pszString, "ON")
    2277                 ||  !strcmp(pVar->u.pszString, "enabled")
    2278                 ||  !strcmp(pVar->u.pszString, "Enabled")
    2279                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    2280             {
    2281                 *pf = true;
    2282                 return VINF_SUCCESS;
    2283             }
    2284             if (    !strcmp(pVar->u.pszString, "false")
    2285                 ||  !strcmp(pVar->u.pszString, "False")
    2286                 ||  !strcmp(pVar->u.pszString, "FALSE")
    2287                 ||  !strcmp(pVar->u.pszString, "off")
    2288                 ||  !strcmp(pVar->u.pszString, "Off")
    2289                 ||  !strcmp(pVar->u.pszString, "OFF")
    2290                 ||  !strcmp(pVar->u.pszString, "disabled")
    2291                 ||  !strcmp(pVar->u.pszString, "Disabled")
    2292                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    2293             {
    2294                 *pf = false;
    2295                 return VINF_SUCCESS;
    2296             }
    2297             return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
    2298 
    2299         case DBGCVAR_TYPE_GC_FLAT:
    2300         case DBGCVAR_TYPE_GC_PHYS:
    2301         case DBGCVAR_TYPE_HC_FLAT:
    2302         case DBGCVAR_TYPE_HC_PHYS:
    2303         case DBGCVAR_TYPE_NUMBER:
    2304             *pf = pVar->u.u64Number != 0;
    2305             return VINF_SUCCESS;
    2306 
    2307         case DBGCVAR_TYPE_HC_FAR:
    2308         case DBGCVAR_TYPE_GC_FAR:
    2309         case DBGCVAR_TYPE_SYMBOL:
    2310         default:
    2311             return VERR_PARSE_INCORRECT_ARG_TYPE;
    2312     }
    2313 }
    2314 
    2315 
    2316 
    2317 
    2318 
    2319 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2320 //
    2321 //
    2322 //      V a r i a b l e   M a n i p u l a t i o n
    2323 //
    2324 //
    2325 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2326 
    2327 
    2328 
    2329 /** @todo move me!*/
    2330 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
    2331 {
    2332     if (pVar)
    2333     {
    2334         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    2335         pVar->u.GCFlat = GCFlat;
    2336         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    2337         pVar->u64Range  = 0;
    2338     }
    2339 }
    2340 
    2341 
    2342 /** @todo move me!*/
    2343 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
    2344 {
    2345     if (pVar)
    2346     {
    2347         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    2348         pVar->u.GCFlat = GCFlat;
    2349         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    2350         pVar->u64Range  = cb;
    2351     }
    2352 }
    2353 
    2354 
    2355 /** @todo move me!*/
    2356 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    2357 {
    2358     if (pVar)
    2359     {
    2360         if (pVar2)
    2361             *pVar = *pVar2;
    2362         else
    2363         {
    2364             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    2365             memset(&pVar->u, 0, sizeof(pVar->u));
    2366             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    2367             pVar->u64Range  = 0;
    2368         }
    2369     }
    2370 }
    2371 
    2372 
    2373 /** @todo move me!*/
    2374 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    2375 {
    2376     if (pVar)
    2377     {
    2378         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    2379         pVar->u64Range  = cb;
    2380     }
    2381 }
    2382 
    2383 
    2384 /** @todo move me!*/
    2385 void dbgcVarSetNoRange(PDBGCVAR pVar)
    2386 {
    2387     if (pVar)
    2388     {
    2389         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    2390         pVar->u64Range  = 0;
    2391     }
    2392 }
    2393 
    2394 
    2395 /**
    2396  * Converts a DBGC variable to a DBGF address.
    2397  *
    2398  * @returns VBox status code.
    2399  * @param   pDbgc       The DBGC instance.
    2400  * @param   pVar        The variable.
    2401  * @param   pAddress    Where to store the address.
    2402  */
    2403 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    2404 {
    2405     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    2406     switch (pVar->enmType)
    2407     {
    2408         case DBGCVAR_TYPE_GC_FLAT:
    2409             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    2410             return VINF_SUCCESS;
    2411 
    2412         case DBGCVAR_TYPE_NUMBER:
    2413             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    2414             return VINF_SUCCESS;
    2415 
    2416         case DBGCVAR_TYPE_GC_FAR:
    2417             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    2418 
    2419         case DBGCVAR_TYPE_STRING:
    2420         case DBGCVAR_TYPE_SYMBOL:
    2421         {
    2422             DBGCVAR Var;
    2423             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    2424             if (VBOX_FAILURE(rc))
    2425                 return rc;
    2426             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    2427         }
    2428 
    2429         case DBGCVAR_TYPE_GC_PHYS:
    2430         case DBGCVAR_TYPE_HC_FLAT:
    2431         case DBGCVAR_TYPE_HC_FAR:
    2432         case DBGCVAR_TYPE_HC_PHYS:
    2433         default:
    2434             return VERR_PARSE_CONVERSION_FAILED;
    2435     }
    2436 }
    2437 
    2438 
    2439 
    2440 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2441 //
    2442 //
    2443 //      B r e a k p o i n t   M a n a g e m e n t
    2444 //
    2445 //
    2446 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2447 
    2448 
    2449 /**
    2450  * Adds a breakpoint to the DBGC breakpoint list.
    2451  */
    2452 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    2453 {
    2454     /*
    2455      * Check if it already exists.
    2456      */
    2457     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2458     if (pBp)
    2459         return VERR_DBGC_BP_EXISTS;
    2460 
    2461     /*
    2462      * Add the breakpoint.
    2463      */
    2464     if (pszCmd)
    2465         pszCmd = RTStrStripL(pszCmd);
    2466     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    2467     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    2468     if (!pBp)
    2469         return VERR_NO_MEMORY;
    2470     if (cchCmd)
    2471         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    2472     else
    2473         pBp->szCmd[0] = '\0';
    2474     pBp->cchCmd = cchCmd;
    2475     pBp->iBp    = iBp;
    2476     pBp->pNext  = pDbgc->pFirstBp;
    2477     pDbgc->pFirstBp = pBp;
    2478 
    2479     return VINF_SUCCESS;
    2480 }
    2481 
    2482 /**
    2483  * Updates the a breakpoint.
    2484  *
    2485  * @returns VBox status code.
    2486  * @param   pDbgc       The DBGC instance.
    2487  * @param   iBp         The breakpoint to update.
    2488  * @param   pszCmd      The new command.
    2489  */
    2490 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    2491 {
    2492     /*
    2493      * Find the breakpoint.
    2494      */
    2495     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2496     if (!pBp)
    2497         return VERR_DBGC_BP_NOT_FOUND;
    2498 
    2499     /*
    2500      * Do we need to reallocate?
    2501      */
    2502     if (pszCmd)
    2503         pszCmd = RTStrStripL(pszCmd);
    2504     if (!pszCmd || !*pszCmd)
    2505         pBp->szCmd[0] = '\0';
    2506     else
    2507     {
    2508         size_t cchCmd = strlen(pszCmd);
    2509         if (strlen(pBp->szCmd) >= cchCmd)
    2510         {
    2511             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    2512             pBp->cchCmd = cchCmd;
    2513         }
    2514         else
    2515         {
    2516             /*
    2517              * Yes, let's do it the simple way...
    2518              */
    2519             int rc = dbgcBpDelete(pDbgc, iBp);
    2520             AssertRC(rc);
    2521             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    2522         }
    2523     }
    2524     return VINF_SUCCESS;
    2525 }
    2526 
    2527 
    2528 /**
    2529  * Deletes a breakpoint.
    2530  *
    2531  * @returns VBox status code.
    2532  * @param   pDbgc       The DBGC instance.
    2533  * @param   iBp         The breakpoint to delete.
    2534  */
    2535 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    2536 {
    2537     /*
    2538      * Search thru the list, when found unlink and free it.
    2539      */
    2540     PDBGCBP pBpPrev = NULL;
    2541     PDBGCBP pBp = pDbgc->pFirstBp;
    2542     for (; pBp; pBp = pBp->pNext)
    2543     {
    2544         if (pBp->iBp == iBp)
    2545         {
    2546             if (pBpPrev)
    2547                 pBpPrev->pNext = pBp->pNext;
    2548             else
    2549                 pDbgc->pFirstBp = pBp->pNext;
    2550             RTMemFree(pBp);
    2551             return VINF_SUCCESS;
    2552         }
    2553         pBpPrev = pBp;
    2554     }
    2555 
    2556     return VERR_DBGC_BP_NOT_FOUND;
    2557 }
    2558 
    2559 
    2560 /**
    2561  * Get a breakpoint.
    2562  *
    2563  * @returns Pointer to the breakpoint.
    2564  * @returns NULL if the breakpoint wasn't found.
    2565  * @param   pDbgc       The DBGC instance.
    2566  * @param   iBp         The breakpoint to get.
    2567  */
    2568 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    2569 {
    2570     /*
    2571      * Enumerate the list.
    2572      */
    2573     PDBGCBP pBp = pDbgc->pFirstBp;
    2574     for (; pBp; pBp = pBp->pNext)
    2575         if (pBp->iBp == iBp)
    2576             return pBp;
    2577     return NULL;
    2578 }
    2579 
    2580 
    2581 /**
    2582  * Executes the command of a breakpoint.
    2583  *
    2584  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    2585  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    2586  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    2587  * @returns VBox status code from dbgcProcessCommand() other wise.
    2588  * @param   pDbgc       The DBGC instance.
    2589  * @param   iBp         The breakpoint to execute.
    2590  */
    2591 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    2592 {
    2593     /*
    2594      * Find the breakpoint.
    2595      */
    2596     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2597     if (!pBp)
    2598         return VERR_DBGC_BP_NOT_FOUND;
    2599 
    2600     /*
    2601      * Anything to do?
    2602      */
    2603     if (!pBp->cchCmd)
    2604         return VINF_DBGC_BP_NO_COMMAND;
    2605 
    2606     /*
    2607      * Execute the command.
    2608      * This means copying it to the scratch buffer and process it as if it
    2609      * were user input. We must save and restore the state of the scratch buffer.
    2610      */
    2611     /* Save the scratch state. */
    2612     char       *pszScratch  = pDbgc->pszScratch;
    2613     unsigned    iArg        = pDbgc->iArg;
    2614 
    2615     /* Copy the command to the scratch buffer. */
    2616     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    2617     if (pBp->cchCmd >= cbScratch)
    2618         return VERR_BUFFER_OVERFLOW;
    2619     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    2620 
    2621     /* Execute the command. */
    2622     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    2623     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    2624 
    2625     /* Restore the scratch state. */
    2626     pDbgc->iArg         = iArg;
    2627     pDbgc->pszScratch   = pszScratch;
    2628 
    2629     return rc;
    2630 }
    2631 
    2632 
    2633 
    2634 
    2635 
    2636 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2637 //
    2638 //
    2639 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    2640 //
    2641 //
    2642 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2643 
    2644 
    2645 
    2646 /**
    2647  * Prints any log lines from the log buffer.
    2648  *
    2649  * The caller must not call function this unless pDbgc->fLog is set.
    2650  *
    2651  * @returns VBox status. (output related)
    2652  * @param   pDbgc   Debugger console instance data.
    2653  */
    2654 static int dbgcProcessLog(PDBGC pDbgc)
    2655 {
    2656     /** @todo */
    2657     NOREF(pDbgc);
    2658     return 0;
    2659 }
    2660 
    2661 
    2662 
    2663 /**
    2664  * Handle input buffer overflow.
    2665  *
    2666  * Will read any available input looking for a '\n' to reset the buffer on.
    2667  *
    2668  * @returns VBox status.
    2669  * @param   pDbgc   Debugger console instance data.
    2670  */
    2671 static int dbgcInputOverflow(PDBGC pDbgc)
    2672 {
    2673     /*
    2674      * Assert overflow status and reset the input buffer.
    2675      */
    2676     if (!pDbgc->fInputOverflow)
    2677     {
    2678         pDbgc->fInputOverflow = true;
    2679         pDbgc->iRead = pDbgc->iWrite = 0;
    2680         pDbgc->cInputLines = 0;
    2681         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    2682     }
    2683 
    2684     /*
    2685      * Eat input till no more or there is a '\n'.
    2686      * When finding a '\n' we'll continue normal processing.
    2687      */
    2688     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    2689     {
    2690         size_t cbRead;
    2691         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    2692         if (VBOX_FAILURE(rc))
    2693             return rc;
    2694         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    2695         if (psz)
    2696         {
    2697             pDbgc->fInputOverflow = false;
    2698             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    2699             pDbgc->iWrite = (unsigned)cbRead;
    2700             pDbgc->cInputLines = 0;
    2701             break;
    2702         }
    2703     }
    2704 
    2705     return 0;
    2706 }
    2707 
    2708 
    2709 
    2710 /**
    2711  * Read input and do some preprocessing.
    2712  *
    2713  * @returns VBox status.
    2714  *          In addition to the iWrite and achInput, cInputLines is maintained.
    2715  *          In case of an input overflow the fInputOverflow flag will be set.
    2716  * @param   pDbgc   Debugger console instance data.
    2717  */
    2718 static int dbgcInputRead(PDBGC pDbgc)
    2719 {
    2720     /*
    2721      * We have ready input.
    2722      * Read it till we don't have any or we have a full input buffer.
    2723      */
    2724     int     rc = 0;
    2725     do
    2726     {
    2727         /*
    2728          * More available buffer space?
    2729          */
    2730         size_t cbLeft;
    2731         if (pDbgc->iWrite > pDbgc->iRead)
    2732             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    2733         else
    2734             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    2735         if (!cbLeft)
    2736         {
    2737             /* overflow? */
    2738             if (!pDbgc->cInputLines)
    2739                 rc = dbgcInputOverflow(pDbgc);
    2740             break;
    2741         }
    2742 
    2743         /*
    2744          * Read one char and interpret it.
    2745          */
    2746         char    achRead[128];
    2747         size_t  cbRead;
    2748         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    2749         if (VBOX_FAILURE(rc))
    2750             return rc;
    2751         char *psz = &achRead[0];
    2752         while (cbRead-- > 0)
    2753         {
    2754             char ch = *psz++;
    2755             switch (ch)
    2756             {
    2757                 /*
    2758                  * Ignore.
    2759                  */
    2760                 case '\0':
    2761                 case '\r':
    2762                 case '\a':
    2763                     break;
    2764 
    2765                 /*
    2766                  * Backspace.
    2767                  */
    2768                 case '\b':
    2769                     Log2(("DBGC: backspace\n"));
    2770                     if (pDbgc->iRead != pDbgc->iWrite)
    2771                     {
    2772                         unsigned iWriteUndo = pDbgc->iWrite;
    2773                         if (pDbgc->iWrite)
    2774                             pDbgc->iWrite--;
    2775                         else
    2776                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    2777 
    2778                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    2779                             pDbgc->iWrite = iWriteUndo;
    2780                     }
    2781                     break;
    2782 
    2783                 /*
    2784                  * Add char to buffer.
    2785                  */
    2786                 case '\t':
    2787                 case '\n':
    2788                 case ';':
    2789                     switch (ch)
    2790                     {
    2791                         case '\t': ch = ' '; break;
    2792                         case '\n': pDbgc->cInputLines++; break;
    2793                     }
    2794                 default:
    2795                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    2796                     pDbgc->achInput[pDbgc->iWrite] = ch;
    2797                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    2798                         pDbgc->iWrite = 0;
    2799                     break;
    2800             }
    2801         }
    2802 
    2803         /* Terminate it to make it easier to read in the debugger. */
    2804         pDbgc->achInput[pDbgc->iWrite] = '\0';
    2805     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    2806 
    2807     return rc;
    2808 }
    2809 
    2810 
    2811455/**
    2812456 * Finds a builtin symbol.
     
    2827471}
    2828472
    2829 
    2830 /**
    2831  * Resolves a symbol (or tries to do so at least).
    2832  *
    2833  * @returns 0 on success.
    2834  * @returns VBox status on failure.
    2835  * @param   pDbgc       The debug console instance.
    2836  * @param   pszSymbol   The symbol name.
    2837  * @param   enmType     The result type.
    2838  * @param   pResult     Where to store the result.
    2839  */
    2840 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    2841 {
    2842     /*
    2843      * Builtin?
    2844      */
    2845     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    2846     if (pSymDesc)
    2847     {
    2848         if (!pSymDesc->pfnGet)
    2849             return VERR_PARSE_WRITEONLY_SYMBOL;
    2850         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    2851     }
    2852 
    2853 
    2854     /*
    2855      * Ask PDM.
    2856      */
    2857     /** @todo resolve symbols using PDM. */
    2858 
    2859 
    2860     /*
    2861      * Ask the debug info manager.
    2862      */
    2863     DBGFSYMBOL Symbol;
    2864     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    2865     if (VBOX_SUCCESS(rc))
    2866     {
    2867         /*
    2868          * Default return is a flat gc address.
    2869          */
    2870         memset(pResult, 0,  sizeof(*pResult));
    2871         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    2872         pResult->u64Range     = Symbol.cb;
    2873         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    2874         pResult->u.GCFlat     = Symbol.Value;
    2875         DBGCVAR VarTmp;
    2876         switch (enmType)
    2877         {
    2878             /* nothing to do. */
    2879             case DBGCVAR_TYPE_GC_FLAT:
    2880             case DBGCVAR_TYPE_GC_FAR:
    2881             case DBGCVAR_TYPE_ANY:
    2882                 return VINF_SUCCESS;
    2883 
    2884             /* simply make it numeric. */
    2885             case DBGCVAR_TYPE_NUMBER:
    2886                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    2887                 pResult->u.u64Number = Symbol.Value;
    2888                 return VINF_SUCCESS;
    2889 
    2890             /* cast it. */
    2891 
    2892             case DBGCVAR_TYPE_GC_PHYS:
    2893                 VarTmp = *pResult;
    2894                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    2895 
    2896             case DBGCVAR_TYPE_HC_FAR:
    2897             case DBGCVAR_TYPE_HC_FLAT:
    2898                 VarTmp = *pResult;
    2899                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    2900 
    2901             case DBGCVAR_TYPE_HC_PHYS:
    2902                 VarTmp = *pResult;
    2903                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    2904 
    2905             default:
    2906                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    2907                 return VERR_INVALID_PARAMETER;
    2908         }
    2909     }
    2910 
    2911     return VERR_PARSE_NOT_IMPLEMENTED;
    2912 }
    2913 
    2914 
    2915 
    2916 /**
    2917  * Finds a routine.
    2918  *
    2919  * @returns Pointer to the command descriptor.
    2920  *          If the request was for an external command, the caller is responsible for
    2921  *          unlocking the external command list.
    2922  * @returns NULL if not found.
    2923  * @param   pDbgc       The debug console instance.
    2924  * @param   pachName    Pointer to the routine string (not terminated).
    2925  * @param   cchName     Length of the routine name.
    2926  * @param   fExternal   Whether or not the routine is external.
    2927  */
    2928 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
    2929 {
    2930     if (!fExternal)
    2931     {
    2932         /* emulation first, so commands can be overloaded (info ++). */
    2933         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    2934         unsigned cLeft = pDbgc->cEmulationCmds;
    2935         while (cLeft-- > 0)
    2936         {
    2937             if (    !strncmp(pachName, pCmd->pszCmd, cchName)
    2938                 &&  !pCmd->pszCmd[cchName])
    2939                 return pCmd;
    2940             pCmd++;
    2941         }
    2942 
    2943         for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
    2944         {
    2945             if (    !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
    2946                 &&  !g_aCmds[iCmd].pszCmd[cchName])
    2947                 return &g_aCmds[iCmd];
    2948         }
    2949     }
    2950     else
    2951     {
    2952         DBGCEXTCMDS_LOCK_RD();
    2953         for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
    2954         {
    2955             for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
    2956             {
    2957                 if (    !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
    2958                     &&  !pExtCmds->paCmds[iCmd].pszCmd[cchName])
    2959                     return &pExtCmds->paCmds[iCmd];
    2960             }
    2961         }
    2962         DBGCEXTCMDS_UNLOCK_RD();
    2963     }
    2964 
    2965     NOREF(pDbgc);
    2966     return NULL;
    2967 }
    2968 
    2969 
    2970 /**
    2971  * Initalizes g_bmOperatorChars.
    2972  */
    2973 static void dbgcInitOpCharBitMap(void)
    2974 {
    2975     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    2976     for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    2977         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    2978 }
    2979 
    2980 
    2981 /**
    2982  * Checks whether the character may be the start of an operator.
    2983  *
    2984  * @returns true/false.
    2985  * @param   ch      The character.
    2986  */
    2987 DECLINLINE(bool) dbgcIsOpChar(char ch)
    2988 {
    2989     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    2990 }
    2991 
    2992 
    2993 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    2994 {
    2995     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    2996 
    2997     /*
    2998      * Removing any quoting and escapings.
    2999      */
    3000     char ch = *pszExpr;
    3001     if (ch == '"' || ch == '\'' || ch == '`')
    3002     {
    3003         if (pszExpr[--cchExpr] != ch)
    3004             return VERR_PARSE_UNBALANCED_QUOTE;
    3005         cchExpr--;
    3006         pszExpr++;
    3007 
    3008         /** @todo string unescaping. */
    3009     }
    3010     pszExpr[cchExpr] = '\0';
    3011 
    3012     /*
    3013      * Make the argument.
    3014      */
    3015     pArg->pDesc         = NULL;
    3016     pArg->pNext         = NULL;
    3017     pArg->enmType       = DBGCVAR_TYPE_STRING;
    3018     pArg->u.pszString   = pszExpr;
    3019     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    3020     pArg->u64Range      = cchExpr;
    3021 
    3022     NOREF(pDbgc);
    3023     return 0;
    3024 }
    3025 
    3026 
    3027 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    3028 {
    3029     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    3030     /*
    3031      * Convert to number.
    3032      */
    3033     uint64_t    u64 = 0;
    3034     char        ch;
    3035     while ((ch = *pszExpr) != '\0')
    3036     {
    3037         uint64_t    u64Prev = u64;
    3038         unsigned    u = ch - '0';
    3039         if (u < 10 && u < uBase)
    3040             u64 = u64 * uBase + u;
    3041         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    3042             u64 = u64 * uBase + u;
    3043         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    3044             u64 = u64 * uBase + u;
    3045         else
    3046             return VERR_PARSE_INVALID_NUMBER;
    3047 
    3048         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    3049         if (u64Prev != u64 / uBase)
    3050             return VERR_PARSE_NUMBER_TOO_BIG;
    3051 
    3052         /* next */
    3053         pszExpr++;
    3054     }
    3055 
    3056     /*
    3057      * Initialize the argument.
    3058      */
    3059     pArg->pDesc         = NULL;
    3060     pArg->pNext         = NULL;
    3061     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    3062     pArg->u.u64Number   = u64;
    3063     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    3064     pArg->u64Range      = 0;
    3065 
    3066     return 0;
    3067 }
    3068 
    3069 
    3070 /**
    3071  * Match variable and variable descriptor, promoting the variable if necessary.
    3072  *
    3073  * @returns VBox status code.
    3074  * @param   pDbgc       Debug console instanace.
    3075  * @param   pVar        Variable.
    3076  * @param   pVarDesc    Variable descriptor.
    3077  */
    3078 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    3079 {
    3080     /*
    3081      * (If match or promoted to match, return, else break.)
    3082      */
    3083     switch (pVarDesc->enmCategory)
    3084     {
    3085         /*
    3086          * Anything goes
    3087          */
    3088         case DBGCVAR_CAT_ANY:
    3089             return VINF_SUCCESS;
    3090 
    3091         /*
    3092          * Pointer with and without range.
    3093          * We can try resolve strings and symbols as symbols and
    3094          * promote numbers to flat GC pointers.
    3095          */
    3096         case DBGCVAR_CAT_POINTER_NO_RANGE:
    3097             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    3098                 return VERR_PARSE_NO_RANGE_ALLOWED;
    3099             /* fallthru */
    3100         case DBGCVAR_CAT_POINTER:
    3101             switch (pVar->enmType)
    3102             {
    3103                 case DBGCVAR_TYPE_GC_FLAT:
    3104                 case DBGCVAR_TYPE_GC_FAR:
    3105                 case DBGCVAR_TYPE_GC_PHYS:
    3106                 case DBGCVAR_TYPE_HC_FLAT:
    3107                 case DBGCVAR_TYPE_HC_FAR:
    3108                 case DBGCVAR_TYPE_HC_PHYS:
    3109                     return VINF_SUCCESS;
    3110 
    3111                 case DBGCVAR_TYPE_SYMBOL:
    3112                 case DBGCVAR_TYPE_STRING:
    3113                 {
    3114                     DBGCVAR Var;
    3115                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    3116                     if (VBOX_SUCCESS(rc))
    3117                     {
    3118                         /* deal with range */
    3119                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    3120                         {
    3121                             Var.enmRangeType = pVar->enmRangeType;
    3122                             Var.u64Range = pVar->u64Range;
    3123                         }
    3124                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    3125                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    3126                         *pVar = Var;
    3127                         return rc;
    3128                     }
    3129                     break;
    3130                 }
    3131 
    3132                 case DBGCVAR_TYPE_NUMBER:
    3133                 {
    3134                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    3135                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    3136                     pVar->u.GCFlat = GCPtr;
    3137                     return VINF_SUCCESS;
    3138                 }
    3139 
    3140                 default:
    3141                     break;
    3142             }
    3143             break;
    3144 
    3145         /*
    3146          * GC pointer with and without range.
    3147          * We can try resolve strings and symbols as symbols and
    3148          * promote numbers to flat GC pointers.
    3149          */
    3150         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    3151             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    3152                 return VERR_PARSE_NO_RANGE_ALLOWED;
    3153             /* fallthru */
    3154         case DBGCVAR_CAT_GC_POINTER:
    3155             switch (pVar->enmType)
    3156             {
    3157                 case DBGCVAR_TYPE_GC_FLAT:
    3158                 case DBGCVAR_TYPE_GC_FAR:
    3159                 case DBGCVAR_TYPE_GC_PHYS:
    3160                     return VINF_SUCCESS;
    3161 
    3162                 case DBGCVAR_TYPE_HC_FLAT:
    3163                 case DBGCVAR_TYPE_HC_FAR:
    3164                 case DBGCVAR_TYPE_HC_PHYS:
    3165                     return VERR_PARSE_CONVERSION_FAILED;
    3166 
    3167                 case DBGCVAR_TYPE_SYMBOL:
    3168                 case DBGCVAR_TYPE_STRING:
    3169                 {
    3170                     DBGCVAR Var;
    3171                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    3172                     if (VBOX_SUCCESS(rc))
    3173                     {
    3174                         /* deal with range */
    3175                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    3176                         {
    3177                             Var.enmRangeType = pVar->enmRangeType;
    3178                             Var.u64Range = pVar->u64Range;
    3179                         }
    3180                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    3181                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    3182                         *pVar = Var;
    3183                         return rc;
    3184                     }
    3185                     break;
    3186                 }
    3187 
    3188                 case DBGCVAR_TYPE_NUMBER:
    3189                 {
    3190                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    3191                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    3192                     pVar->u.GCFlat = GCPtr;
    3193                     return VINF_SUCCESS;
    3194                 }
    3195 
    3196                 default:
    3197                     break;
    3198             }
    3199             break;
    3200 
    3201         /*
    3202          * Number with or without a range.
    3203          * Numbers can be resolved from symbols, but we cannot demote a pointer
    3204          * to a number.
    3205          */
    3206         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    3207             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    3208                 return VERR_PARSE_NO_RANGE_ALLOWED;
    3209             /* fallthru */
    3210         case DBGCVAR_CAT_NUMBER:
    3211             switch (pVar->enmType)
    3212             {
    3213                 case DBGCVAR_TYPE_NUMBER:
    3214                     return VINF_SUCCESS;
    3215 
    3216                 case DBGCVAR_TYPE_SYMBOL:
    3217                 case DBGCVAR_TYPE_STRING:
    3218                 {
    3219                     DBGCVAR Var;
    3220                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    3221                     if (VBOX_SUCCESS(rc))
    3222                     {
    3223                         *pVar = Var;
    3224                         return rc;
    3225                     }
    3226                     break;
    3227                 }
    3228                 default:
    3229                     break;
    3230             }
    3231             break;
    3232 
    3233         /*
    3234          * Strings can easily be made from symbols (and of course strings).
    3235          * We could consider reformatting the addresses and numbers into strings later...
    3236          */
    3237         case DBGCVAR_CAT_STRING:
    3238             switch (pVar->enmType)
    3239             {
    3240                 case DBGCVAR_TYPE_SYMBOL:
    3241                     pVar->enmType = DBGCVAR_TYPE_STRING;
    3242                     /* fallthru */
    3243                 case DBGCVAR_TYPE_STRING:
    3244                     return VINF_SUCCESS;
    3245                 default:
    3246                     break;
    3247             }
    3248             break;
    3249 
    3250         /*
    3251          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    3252          */
    3253         case DBGCVAR_CAT_SYMBOL:
    3254             switch (pVar->enmType)
    3255             {
    3256                 case DBGCVAR_TYPE_STRING:
    3257                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    3258                     /* fallthru */
    3259                 case DBGCVAR_TYPE_SYMBOL:
    3260                     return VINF_SUCCESS;
    3261                 default:
    3262                     break;
    3263             }
    3264             break;
    3265 
    3266         /*
    3267          * Anything else is illegal.
    3268          */
    3269         default:
    3270             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    3271             break;
    3272     }
    3273 
    3274     return VERR_PARSE_NO_ARGUMENT_MATCH;
    3275 }
    3276 
    3277 
    3278 /**
    3279  * Matches a set of variables with a description set.
    3280  *
    3281  * This is typically used for routine arguments before a call. The effects in
    3282  * addition to the validation, is that some variables might be propagated to
    3283  * other types in order to match the description. The following transformations
    3284  * are supported:
    3285  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    3286  *      - Number to a pointer.
    3287  *      - Pointer to a number.
    3288  * @returns 0 on success with paVars.
    3289  * @returns VBox error code for match errors.
    3290  */
    3291 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    3292                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    3293                                 PDBGCVAR paVars, unsigned cVars)
    3294 {
    3295     /*
    3296      * Just do basic min / max checks first.
    3297      */
    3298     if (cVars < cVarsMin)
    3299         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    3300     if (cVars > cVarsMax)
    3301         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3302 
    3303     /*
    3304      * Match the descriptors and actual variables.
    3305      */
    3306     PCDBGCVARDESC   pPrevDesc = NULL;
    3307     unsigned        cCurDesc = 0;
    3308     unsigned        iVar = 0;
    3309     unsigned        iVarDesc = 0;
    3310     while (iVar < cVars)
    3311     {
    3312         /* walk the descriptors */
    3313         if (iVarDesc >= cVarDescs)
    3314             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3315         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    3316                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    3317             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    3318         {
    3319             iVarDesc++;
    3320             if (iVarDesc >= cVarDescs)
    3321                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3322             cCurDesc = 0;
    3323         }
    3324 
    3325         /*
    3326          * Skip thru optional arguments until we find something which matches
    3327          * or can easily be promoted to what the descriptor want.
    3328          */
    3329         for (;;)
    3330         {
    3331             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    3332             if (VBOX_SUCCESS(rc))
    3333             {
    3334                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    3335                 cCurDesc++;
    3336                 break;
    3337             }
    3338 
    3339             /* can we advance? */
    3340             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    3341                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    3342             if (++iVarDesc >= cVarDescs)
    3343                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    3344             cCurDesc = 0;
    3345         }
    3346 
    3347         /* next var */
    3348         iVar++;
    3349     }
    3350 
    3351     /*
    3352      * Check that the rest of the descriptors are optional.
    3353      */
    3354     while (iVarDesc < cVarDescs)
    3355     {
    3356         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    3357             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    3358         cCurDesc = 0;
    3359 
    3360         /* next */
    3361         iVarDesc++;
    3362     }
    3363 
    3364     return 0;
    3365 }
    3366 
    3367 
    3368 /**
    3369  * Evaluates one argument with respect to unary operators.
    3370  *
    3371  * @returns 0 on success. pResult contains the result.
    3372  * @returns VBox error code on parse or other evaluation error.
    3373  *
    3374  * @param   pDbgc       Debugger console instance data.
    3375  * @param   pszExpr     The expression string.
    3376  * @param   pResult     Where to store the result of the expression evaluation.
    3377  */
    3378 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    3379 {
    3380     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    3381 
    3382     /*
    3383      * The state of the expression is now such that it will start by zero or more
    3384      * unary operators and being followed by an expression of some kind.
    3385      * The expression is either plain or in parenthesis.
    3386      *
    3387      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    3388      * ASSUME: unary operators are all of equal precedence.
    3389      */
    3390     int         rc = 0;
    3391     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    3392     if (pOp)
    3393     {
    3394         /* binary operators means syntax error. */
    3395         if (pOp->fBinary)
    3396             return VERR_PARSE_UNEXPECTED_OPERATOR;
    3397 
    3398         /*
    3399          * If the next expression (the one following the unary operator) is in a
    3400          * parenthesis a full eval is needed. If not the unary eval will suffice.
    3401          */
    3402         /* calc and strip next expr. */
    3403         char *pszExpr2 = pszExpr + pOp->cchName;
    3404         while (isblank(*pszExpr2))
    3405             pszExpr2++;
    3406 
    3407         if (!*pszExpr2)
    3408             rc = VERR_PARSE_EMPTY_ARGUMENT;
    3409         else
    3410         {
    3411             DBGCVAR Arg;
    3412             if (*pszExpr2 == '(')
    3413                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    3414             else
    3415                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    3416             if (VBOX_SUCCESS(rc))
    3417                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    3418         }
    3419     }
    3420     else
    3421     {
    3422         /*
    3423          * Didn't find any operators, so it we have to check if this can be an
    3424          * function call before assuming numeric or string expression.
    3425          *
    3426          * (ASSUMPTIONS:)
    3427          * A function name only contains alphanumerical chars and it can not start
    3428          * with a numerical character.
    3429          * Immediately following the name is a parenthesis which must over
    3430          * the remaining part of the expression.
    3431          */
    3432         bool    fExternal = *pszExpr == '.';
    3433         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    3434         char   *pszFunEnd = NULL;
    3435         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    3436         {
    3437             pszFunEnd = pszExpr + 1;
    3438             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    3439                 pszFunEnd++;
    3440             if (*pszFunEnd != '(')
    3441                 pszFunEnd = NULL;
    3442         }
    3443 
    3444         if (pszFunEnd)
    3445         {
    3446             /*
    3447              * Ok, it's a function call.
    3448              */
    3449             if (fExternal)
    3450                 pszExpr++, cchExpr--;
    3451             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    3452             if (!pFun)
    3453                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    3454             if (!pFun->pResultDesc)
    3455                 return VERR_PARSE_NOT_A_FUNCTION;
    3456 
    3457             /*
    3458              * Parse the expression in parenthesis.
    3459              */
    3460             cchExpr -= pszFunEnd - pszExpr;
    3461             pszExpr = pszFunEnd;
    3462             /** @todo implement multiple arguments. */
    3463             DBGCVAR     Arg;
    3464             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    3465             if (!rc)
    3466             {
    3467                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    3468                 if (!rc)
    3469                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    3470             }
    3471             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    3472                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    3473         }
    3474         else
    3475         {
    3476             /*
    3477              * Didn't find any operators, so it must be a plain expression.
    3478              * This might be numeric or a string expression.
    3479              */
    3480             char ch  = pszExpr[0];
    3481             char ch2 = pszExpr[1];
    3482             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    3483                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    3484             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    3485                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    3486             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    3487                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    3488             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    3489             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    3490             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    3491             else
    3492             {
    3493                 /*
    3494                  * Hexadecimal number or a string?
    3495                  */
    3496                 char *psz = pszExpr;
    3497                 while (isxdigit(*psz))
    3498                     psz++;
    3499                 if (!*psz)
    3500                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    3501                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    3502                 {
    3503                     *psz = '\0';
    3504                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    3505                 }
    3506                 else
    3507                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    3508             }
    3509         }
    3510     }
    3511 
    3512     return rc;
    3513 }
    3514 
    3515 
    3516 /**
    3517  * Evaluates one argument.
    3518  *
    3519  * @returns 0 on success. pResult contains the result.
    3520  * @returns VBox error code on parse or other evaluation error.
    3521  *
    3522  * @param   pDbgc       Debugger console instance data.
    3523  * @param   pszExpr     The expression string.
    3524  * @param   pResult     Where to store the result of the expression evaluation.
    3525  */
    3526 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    3527 {
    3528     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    3529     /*
    3530      * First we need to remove blanks in both ends.
    3531      * ASSUMES: There is no quoting unless the entire expression is a string.
    3532      */
    3533 
    3534     /* stripping. */
    3535     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    3536         pszExpr[--cchExpr] = '\0';
    3537     while (isblank(*pszExpr))
    3538         pszExpr++, cchExpr--;
    3539     if (!*pszExpr)
    3540         return VERR_PARSE_EMPTY_ARGUMENT;
    3541 
    3542     /* it there is any kind of quoting in the expression, it's string meat. */
    3543     if (strpbrk(pszExpr, "\"'`"))
    3544         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    3545 
    3546     /*
    3547      * Check if there are any parenthesis which needs removing.
    3548      */
    3549     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    3550     {
    3551         do
    3552         {
    3553             unsigned cPar = 1;
    3554             char    *psz = pszExpr + 1;
    3555             char     ch;
    3556             while ((ch = *psz) != '\0')
    3557             {
    3558                 if (ch == '(')
    3559                     cPar++;
    3560                 else if (ch == ')')
    3561                 {
    3562                     if (cPar <= 0)
    3563                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3564                     cPar--;
    3565                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    3566                         break;
    3567                 }
    3568                 /* next */
    3569                 psz++;
    3570             }
    3571             if (ch)
    3572                 break;
    3573 
    3574             /* remove the parenthesis. */
    3575             pszExpr++;
    3576             cchExpr -= 2;
    3577             pszExpr[cchExpr] = '\0';
    3578 
    3579             /* strip blanks. */
    3580             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    3581                 pszExpr[--cchExpr] = '\0';
    3582             while (isblank(*pszExpr))
    3583                 pszExpr++, cchExpr--;
    3584             if (!*pszExpr)
    3585                 return VERR_PARSE_EMPTY_ARGUMENT;
    3586         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    3587     }
    3588 
    3589     /* tabs to spaces. */
    3590     char *psz = pszExpr;
    3591     while ((psz = strchr(psz, '\t')) != NULL)
    3592         *psz = ' ';
    3593 
    3594     /*
    3595      * Now, we need to look for the binary operator with the lowest precedence.
    3596      *
    3597      * If there are no operators we're left with a simple expression which we
    3598      * evaluate with respect to unary operators
    3599      */
    3600     char       *pszOpSplit = NULL;
    3601     PCDBGCOP    pOpSplit = NULL;
    3602     unsigned    cBinaryOps = 0;
    3603     unsigned    cPar = 0;
    3604     char        ch;
    3605     char        chPrev = ' ';
    3606     bool        fBinary = false;
    3607     psz = pszExpr;
    3608 
    3609     while ((ch = *psz) != '\0')
    3610     {
    3611         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    3612         /*
    3613          * Parenthesis.
    3614          */
    3615         if (ch == '(')
    3616         {
    3617             cPar++;
    3618             fBinary = false;
    3619         }
    3620         else if (ch == ')')
    3621         {
    3622             if (cPar <= 0)
    3623                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3624             cPar--;
    3625             fBinary = true;
    3626         }
    3627         /*
    3628          * Potential operator.
    3629          */
    3630         else if (cPar == 0 && !isblank(ch))
    3631         {
    3632             PCDBGCOP pOp = dbgcIsOpChar(ch)
    3633                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    3634                          : NULL;
    3635             if (pOp)
    3636             {
    3637                 /* If not the right kind of operator we've got a syntax error. */
    3638                 if (pOp->fBinary != fBinary)
    3639                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    3640 
    3641                 /*
    3642                  * Update the parse state and skip the operator.
    3643                  */
    3644                 if (!pOpSplit)
    3645                 {
    3646                     pOpSplit = pOp;
    3647                     pszOpSplit = psz;
    3648                     cBinaryOps = fBinary;
    3649                 }
    3650                 else if (fBinary)
    3651                 {
    3652                     cBinaryOps++;
    3653                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    3654                     {
    3655                         pOpSplit = pOp;
    3656                         pszOpSplit = psz;
    3657                     }
    3658                 }
    3659 
    3660                 psz += pOp->cchName - 1;
    3661                 fBinary = false;
    3662             }
    3663             else
    3664                 fBinary = true;
    3665         }
    3666 
    3667         /* next */
    3668         psz++;
    3669         chPrev = ch;
    3670     } /* parse loop. */
    3671 
    3672 
    3673     /*
    3674      * Either we found an operator to divide the expression by
    3675      * or we didn't find any. In the first case it's divide and
    3676      * conquer. In the latter it's a single expression which
    3677      * needs dealing with its unary operators if any.
    3678      */
    3679     int rc;
    3680     if (    cBinaryOps
    3681         &&  pOpSplit->fBinary)
    3682     {
    3683         /* process 1st sub expression. */
    3684         *pszOpSplit = '\0';
    3685         DBGCVAR     Arg1;
    3686         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    3687         if (VBOX_SUCCESS(rc))
    3688         {
    3689             /* process 2nd sub expression. */
    3690             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    3691             DBGCVAR     Arg2;
    3692             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    3693             if (VBOX_SUCCESS(rc))
    3694                 /* apply the operator. */
    3695                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    3696         }
    3697     }
    3698     else if (cBinaryOps)
    3699     {
    3700         /* process sub expression. */
    3701         pszOpSplit += pOpSplit->cchName;
    3702         DBGCVAR     Arg;
    3703         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    3704         if (VBOX_SUCCESS(rc))
    3705             /* apply the operator. */
    3706             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    3707     }
    3708     else
    3709         /* plain expression or using unary operators perhaps with paratheses. */
    3710         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    3711 
    3712     return rc;
    3713 }
    3714 
    3715 
    3716 /**
    3717  * Parses the arguments of one command.
    3718  *
    3719  * @returns 0 on success.
    3720  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    3721  * @param   pDbgc       Debugger console instance data.
    3722  * @param   pCmd        Pointer to the command descriptor.
    3723  * @param   pszArg      Pointer to the arguments to parse.
    3724  * @param   paArgs      Where to store the parsed arguments.
    3725  * @param   cArgs       Size of the paArgs array.
    3726  * @param   pcArgs      Where to store the number of arguments.
    3727  *                      In the event of an error this is used to store the index of the offending argument.
    3728  */
    3729 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    3730 {
    3731     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    3732     /*
    3733      * Check if we have any argument and if the command takes any.
    3734      */
    3735     *pcArgs = 0;
    3736     /* strip leading blanks. */
    3737     while (*pszArgs && isblank(*pszArgs))
    3738         pszArgs++;
    3739     if (!*pszArgs)
    3740     {
    3741         if (!pCmd->cArgsMin)
    3742             return 0;
    3743         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    3744     }
    3745     /** @todo fixme - foo() doesn't work. */
    3746     if (!pCmd->cArgsMax)
    3747         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3748 
    3749     /*
    3750      * This is a hack, it's "temporary" and should go away "when" the parser is
    3751      * modified to match arguments while parsing.
    3752      */
    3753     if (    pCmd->cArgsMax == 1
    3754         &&  pCmd->cArgsMin == 1
    3755         &&  pCmd->cArgDescs == 1
    3756         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    3757         &&  cArgs >= 1)
    3758     {
    3759         *pcArgs = 1;
    3760         RTStrStripR(pszArgs);
    3761         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    3762     }
    3763 
    3764 
    3765     /*
    3766      * The parse loop.
    3767      */
    3768     PDBGCVAR        pArg0 = &paArgs[0];
    3769     PDBGCVAR        pArg = pArg0;
    3770     *pcArgs = 0;
    3771     do
    3772     {
    3773         /*
    3774          * Can we have another argument?
    3775          */
    3776         if (*pcArgs >= pCmd->cArgsMax)
    3777             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3778         if (pArg >= &paArgs[cArgs])
    3779             return VERR_PARSE_ARGUMENT_OVERFLOW;
    3780 
    3781         /*
    3782          * Find the end of the argument.
    3783          */
    3784         int     cPar    = 0;
    3785         char    chQuote = '\0';
    3786         char   *pszEnd  = NULL;
    3787         char   *psz     = pszArgs;
    3788         char    ch;
    3789         bool    fBinary = false;
    3790         for (;;)
    3791         {
    3792             /*
    3793              * Check for the end.
    3794              */
    3795             if ((ch = *psz) == '\0')
    3796             {
    3797                 if (chQuote)
    3798                     return VERR_PARSE_UNBALANCED_QUOTE;
    3799                 if (cPar)
    3800                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3801                 pszEnd = psz;
    3802                 break;
    3803             }
    3804             /*
    3805              * When quoted we ignore everything but the quotation char.
    3806              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    3807              */
    3808             else if (ch == '\'' || ch == '"' || ch == '`')
    3809             {
    3810                 if (chQuote)
    3811                 {
    3812                     /* end quote? */
    3813                     if (ch == chQuote)
    3814                     {
    3815                         if (psz[1] == ch)
    3816                             psz++;          /* skip the escaped quote char */
    3817                         else
    3818                             chQuote = '\0'; /* end of quoted string. */
    3819                     }
    3820                 }
    3821                 else
    3822                     chQuote = ch;           /* open new quote */
    3823             }
    3824             /*
    3825              * Parenthesis can of course be nested.
    3826              */
    3827             else if (ch == '(')
    3828             {
    3829                 cPar++;
    3830                 fBinary = false;
    3831             }
    3832             else if (ch == ')')
    3833             {
    3834                 if (!cPar)
    3835                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3836                 cPar--;
    3837                 fBinary = true;
    3838             }
    3839             else if (!chQuote && !cPar)
    3840             {
    3841                 /*
    3842                  * Encountering blanks may mean the end of it all. A binary operator
    3843                  * will force continued parsing.
    3844                  */
    3845                 if (isblank(*psz))
    3846                 {
    3847                     pszEnd = psz++;         /* just in case. */
    3848                     while (isblank(*psz))
    3849                         psz++;
    3850                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    3851                     if (!pOp || pOp->fBinary != fBinary)
    3852                         break;              /* the end. */
    3853                     psz += pOp->cchName;
    3854                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    3855                         psz++;
    3856                     fBinary = false;
    3857                     continue;
    3858                 }
    3859 
    3860                 /*
    3861                  * Look for operators without a space up front.
    3862                  */
    3863                 if (dbgcIsOpChar(*psz))
    3864                 {
    3865                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    3866                     if (pOp)
    3867                     {
    3868                         if (pOp->fBinary != fBinary)
    3869                         {
    3870                             pszEnd = psz;
    3871                             /** @todo this is a parsing error really. */
    3872                             break;              /* the end. */
    3873                         }
    3874                         psz += pOp->cchName;
    3875                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    3876                             psz++;
    3877                         fBinary = false;
    3878                         continue;
    3879                     }
    3880                 }
    3881                 fBinary = true;
    3882             }
    3883 
    3884             /* next char */
    3885             psz++;
    3886         }
    3887         *pszEnd = '\0';
    3888         /* (psz = next char to process) */
    3889 
    3890         /*
    3891          * Parse and evaluate the argument.
    3892          */
    3893         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    3894         if (VBOX_FAILURE(rc))
    3895             return rc;
    3896 
    3897         /*
    3898          * Next.
    3899          */
    3900         pArg++;
    3901         (*pcArgs)++;
    3902         pszArgs = psz;
    3903         while (*pszArgs && isblank(*pszArgs))
    3904             pszArgs++;
    3905     } while (*pszArgs);
    3906 
    3907     /*
    3908      * Match the arguments.
    3909      */
    3910     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    3911 }
    3912 
    3913 
    3914 /**
    3915  * Process one command.
    3916  *
    3917  * @returns VBox status code. Any error indicates the termination of the console session.
    3918  * @param   pDbgc   Debugger console instance data.
    3919  * @param   pszCmd  Pointer to the command.
    3920  * @param   cchCmd  Length of the command.
    3921  */
    3922 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    3923 {
    3924     char *pszCmdInput = pszCmd;
    3925 
    3926     /*
    3927      * Skip blanks.
    3928      */
    3929     while (isblank(*pszCmd))
    3930         pszCmd++, cchCmd--;
    3931 
    3932     /* external command? */
    3933     bool fExternal = *pszCmd == '.';
    3934     if (fExternal)
    3935         pszCmd++, cchCmd--;
    3936 
    3937     /*
    3938      * Find arguments.
    3939      */
    3940     char *pszArgs = pszCmd;
    3941     while (isalnum(*pszArgs))
    3942         pszArgs++;
    3943     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    3944     {
    3945         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    3946         return 0;
    3947     }
    3948 
    3949     /*
    3950      * Find the command.
    3951      */
    3952     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    3953     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    3954         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    3955 
    3956     /*
    3957      * Parse arguments (if any).
    3958      */
    3959     unsigned    cArgs;
    3960     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    3961 
    3962     /*
    3963      * Execute the command.
    3964      */
    3965     if (!rc)
    3966     {
    3967         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    3968     }
    3969     else
    3970     {
    3971         /* report parse / eval error. */
    3972         switch (rc)
    3973         {
    3974             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    3975                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3976                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    3977                 break;
    3978             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    3979                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3980                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    3981                 break;
    3982             case VERR_PARSE_ARGUMENT_OVERFLOW:
    3983                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3984                     "Syntax error: Too many arguments.\n");
    3985                 break;
    3986             case VERR_PARSE_UNBALANCED_QUOTE:
    3987                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3988                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    3989                 break;
    3990             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    3991                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3992                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    3993                 break;
    3994             case VERR_PARSE_EMPTY_ARGUMENT:
    3995                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3996                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    3997                 break;
    3998             case VERR_PARSE_UNEXPECTED_OPERATOR:
    3999                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4000                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    4001                 break;
    4002             case VERR_PARSE_INVALID_NUMBER:
    4003                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4004                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    4005                 break;
    4006             case VERR_PARSE_NUMBER_TOO_BIG:
    4007                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4008                     "Error: Numeric overflow (argument %d).\n", cArgs);
    4009                 break;
    4010             case VERR_PARSE_INVALID_OPERATION:
    4011                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4012                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    4013                 break;
    4014             case VERR_PARSE_FUNCTION_NOT_FOUND:
    4015                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4016                     "Error: Function not found (argument %d).\n", cArgs);
    4017                 break;
    4018             case VERR_PARSE_NOT_A_FUNCTION:
    4019                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4020                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    4021                 break;
    4022             case VERR_PARSE_NO_MEMORY:
    4023                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4024                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    4025                 break;
    4026             case VERR_PARSE_INCORRECT_ARG_TYPE:
    4027                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4028                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    4029                 break;
    4030             case VERR_PARSE_VARIABLE_NOT_FOUND:
    4031                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4032                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    4033                 break;
    4034             case VERR_PARSE_CONVERSION_FAILED:
    4035                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4036                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    4037                 break;
    4038             case VERR_PARSE_NOT_IMPLEMENTED:
    4039                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4040                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    4041                 break;
    4042             case VERR_PARSE_BAD_RESULT_TYPE:
    4043                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4044                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    4045                 break;
    4046             case VERR_PARSE_WRITEONLY_SYMBOL:
    4047                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4048                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    4049                 break;
    4050 
    4051             default:
    4052                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4053                     "Error: Unknown error %d!\n", rc);
    4054                 return rc;
    4055         }
    4056 
    4057         /*
    4058          * Parse errors are non fatal.
    4059          */
    4060         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    4061             rc = 0;
    4062     }
    4063 
    4064     return rc;
    4065 }
    4066 
    4067 
    4068 /**
    4069  * Process all commands current in the buffer.
    4070  *
    4071  * @returns VBox status code. Any error indicates the termination of the console session.
    4072  * @param   pDbgc   Debugger console instance data.
    4073  */
    4074 static int dbgcProcessCommands(PDBGC pDbgc)
    4075 {
    4076     int rc = 0;
    4077     while (pDbgc->cInputLines)
    4078     {
    4079         /*
    4080          * Empty the log buffer if we're hooking the log.
    4081          */
    4082         if (pDbgc->fLog)
    4083         {
    4084             rc = dbgcProcessLog(pDbgc);
    4085             if (VBOX_FAILURE(rc))
    4086                 break;
    4087         }
    4088 
    4089         if (pDbgc->iRead == pDbgc->iWrite)
    4090         {
    4091             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    4092             pDbgc->cInputLines = 0;
    4093             return 0;
    4094         }
    4095 
    4096         /*
    4097          * Copy the command to the parse buffer.
    4098          */
    4099         char    ch;
    4100         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    4101         char   *pszTrg = &pDbgc->achScratch[0];
    4102         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    4103         {
    4104             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    4105                 psz = &pDbgc->achInput[0];
    4106 
    4107             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    4108             {
    4109                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    4110                 pDbgc->cInputLines = 0;
    4111                 return 0;
    4112             }
    4113 
    4114             pszTrg++;
    4115         }
    4116         *pszTrg = '\0';
    4117 
    4118         /*
    4119          * Advance the buffer.
    4120          */
    4121         pDbgc->iRead = psz - &pDbgc->achInput[0];
    4122         if (ch == '\n')
    4123             pDbgc->cInputLines--;
    4124 
    4125         /*
    4126          * Parse and execute this command.
    4127          */
    4128         pDbgc->pszScratch = psz;
    4129         pDbgc->iArg       = 0;
    4130         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    4131         if (rc)
    4132             break;
    4133     }
    4134 
    4135     return rc;
    4136 }
    4137 
    4138 
    4139 /**
    4140  * Reads input, parses it and executes commands on '\n'.
    4141  *
    4142  * @returns VBox status.
    4143  * @param   pDbgc   Debugger console instance data.
    4144  */
    4145 static int dbgcProcessInput(PDBGC pDbgc)
    4146 {
    4147     /*
    4148      * We know there's input ready, so let's read it first.
    4149      */
    4150     int rc = dbgcInputRead(pDbgc);
    4151     if (VBOX_FAILURE(rc))
    4152         return rc;
    4153 
    4154     /*
    4155      * Now execute any ready commands.
    4156      */
    4157     if (pDbgc->cInputLines)
    4158     {
    4159         /** @todo this fReady stuff is broken. */
    4160         pDbgc->fReady = false;
    4161         rc = dbgcProcessCommands(pDbgc);
    4162         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    4163             pDbgc->fReady = true;
    4164         if (    VBOX_SUCCESS(rc)
    4165             &&  pDbgc->iRead == pDbgc->iWrite
    4166             &&  pDbgc->fReady)
    4167             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    4168     }
    4169 
    4170     return rc;
    4171 }
    4172 
    4173 
    4174 /**
    4175  * Gets the event context identifier string.
    4176  * @returns Read only string.
    4177  * @param   enmCtx          The context.
    4178  */
    4179 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    4180 {
    4181     switch (enmCtx)
    4182     {
    4183         case DBGFEVENTCTX_RAW:      return "raw";
    4184         case DBGFEVENTCTX_REM:      return "rem";
    4185         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    4186         case DBGFEVENTCTX_HYPER:    return "hyper";
    4187         case DBGFEVENTCTX_OTHER:    return "other";
    4188 
    4189         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    4190         default:
    4191             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    4192             return "!Unknown Event Ctx!";
    4193     }
    4194 }
    4195 
    4196 
    4197 /**
    4198  * Processes debugger events.
    4199  *
    4200  * @returns VBox status.
    4201  * @param   pDbgc   DBGC Instance data.
    4202  * @param   pEvent  Pointer to event data.
    4203  */
    4204 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    4205 {
    4206     /*
    4207      * Flush log first.
    4208      */
    4209     if (pDbgc->fLog)
    4210     {
    4211         int rc = dbgcProcessLog(pDbgc);
    4212         if (VBOX_FAILURE(rc))
    4213             return rc;
    4214     }
    4215 
    4216     /*
    4217      * Process the event.
    4218      */
    4219     pDbgc->pszScratch = &pDbgc->achInput[0];
    4220     pDbgc->iArg       = 0;
    4221     bool fPrintPrompt = true;
    4222     int rc = VINF_SUCCESS;
    4223     switch (pEvent->enmType)
    4224     {
    4225         /*
    4226          * The first part is events we have initiated with commands.
    4227          */
    4228         case DBGFEVENT_HALT_DONE:
    4229         {
    4230             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    4231                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    4232             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    4233             if (VBOX_SUCCESS(rc))
    4234                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4235             break;
    4236         }
    4237 
    4238 
    4239         /*
    4240          * The second part is events which can occur at any time.
    4241          */
    4242         case DBGFEVENT_FATAL_ERROR:
    4243         {
    4244             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    4245                                          dbgcGetEventCtx(pEvent->enmCtx));
    4246             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    4247             if (VBOX_SUCCESS(rc))
    4248                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4249             break;
    4250         }
    4251 
    4252         case DBGFEVENT_BREAKPOINT:
    4253         case DBGFEVENT_BREAKPOINT_HYPER:
    4254         {
    4255             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    4256             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    4257 
    4258             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    4259             switch (rc)
    4260             {
    4261                 case VERR_DBGC_BP_NOT_FOUND:
    4262                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    4263                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    4264                     break;
    4265 
    4266                 case VINF_DBGC_BP_NO_COMMAND:
    4267                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    4268                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    4269                     break;
    4270 
    4271                 case VINF_BUFFER_OVERFLOW:
    4272                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    4273                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    4274                     break;
    4275 
    4276                 default:
    4277                     break;
    4278             }
    4279             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    4280                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4281             else
    4282                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    4283             break;
    4284         }
    4285 
    4286         case DBGFEVENT_STEPPED:
    4287         case DBGFEVENT_STEPPED_HYPER:
    4288         {
    4289             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    4290 
    4291             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    4292             if (VBOX_SUCCESS(rc))
    4293                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4294             break;
    4295         }
    4296 
    4297         case DBGFEVENT_ASSERTION_HYPER:
    4298         {
    4299             pDbgc->fRegCtxGuest = false;
    4300 
    4301             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4302                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    4303                                          "%s"
    4304                                          "%s"
    4305                                          "\n",
    4306                                          dbgcGetEventCtx(pEvent->enmCtx),
    4307                                          pEvent->u.Assert.pszMsg1,
    4308                                          pEvent->u.Assert.pszMsg2);
    4309             if (VBOX_SUCCESS(rc))
    4310                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4311             break;
    4312         }
    4313 
    4314         case DBGFEVENT_DEV_STOP:
    4315         {
    4316             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4317                                          "\n"
    4318                                          "dbgf event: DBGFSTOP (%s)\n"
    4319                                          "File:     %s\n"
    4320                                          "Line:     %d\n"
    4321                                          "Function: %s\n",
    4322                                          dbgcGetEventCtx(pEvent->enmCtx),
    4323                                          pEvent->u.Src.pszFile,
    4324                                          pEvent->u.Src.uLine,
    4325                                          pEvent->u.Src.pszFunction);
    4326             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    4327                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4328                                          "Message:  %s\n",
    4329                                              pEvent->u.Src.pszMessage);
    4330             if (VBOX_SUCCESS(rc))
    4331                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    4332             break;
    4333         }
    4334 
    4335 
    4336         case DBGFEVENT_INVALID_COMMAND:
    4337         {
    4338             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    4339             fPrintPrompt = !pDbgc->fReady;
    4340             break;
    4341         }
    4342 
    4343         case DBGFEVENT_TERMINATING:
    4344         {
    4345             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    4346             rc = VERR_GENERAL_FAILURE;
    4347             break;
    4348         }
    4349 
    4350 
    4351         default:
    4352         {
    4353             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    4354             fPrintPrompt = !pDbgc->fReady;
    4355             break;
    4356         }
    4357     }
    4358 
    4359     /*
    4360      * Prompt, anyone?
    4361      */
    4362     if (fPrintPrompt && VBOX_SUCCESS(rc))
    4363     {
    4364         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    4365     }
    4366 
    4367     return rc;
    4368 }
    4369 
    4370 
    4371 
    4372 
    4373 
    4374 /**
    4375  * Make a console instance.
    4376  *
    4377  * This will not return until either an 'exit' command is issued or a error code
    4378  * indicating connection loss is encountered.
    4379  *
    4380  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    4381  * @returns The VBox status code causing the console termination.
    4382  *
    4383  * @param   pVM         VM Handle.
    4384  * @param   pBack       Pointer to the backend structure. This must contain
    4385  *                      a full set of function pointers to service the console.
    4386  * @param   fFlags      Reserved, must be zero.
    4387  * @remark  A forced termination of the console is easiest done by forcing the
    4388  *          callbacks to return fatal failures.
    4389  */
    4390 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    4391 {
    4392     /*
    4393      * Validate input.
    4394      */
    4395     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    4396     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    4397     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    4398 
    4399     /*
    4400      * Allocate and initialize instance data
    4401      */
    4402     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    4403     if (!pDbgc)
    4404         return VERR_NO_MEMORY;
    4405 
    4406     pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    4407     pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
    4408     pDbgc->CmdHlp.pfnPrintf     = dbgcHlpPrintf;
    4409     pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
    4410     pDbgc->CmdHlp.pfnVBoxError  = dbgcHlpVBoxError;
    4411     pDbgc->CmdHlp.pfnMemRead    = dbgcHlpMemRead;
    4412     pDbgc->CmdHlp.pfnMemWrite   = dbgcHlpMemWrite;
    4413     pDbgc->CmdHlp.pfnEval       = dbgcHlpEval;
    4414     pDbgc->CmdHlp.pfnExec       = dbgcHlpExec;
    4415     pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    4416     pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
    4417     pDbgc->pBack            = pBack;
    4418     pDbgc->pVM              = NULL;
    4419     pDbgc->pszEmulation     = "CodeView/WinDbg";
    4420     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    4421     pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    4422     //pDbgc->fLog             = false;
    4423     pDbgc->fRegCtxGuest     = true;
    4424     pDbgc->fRegTerse        = true;
    4425     //pDbgc->DisasmPos        = {0};
    4426     //pDbgc->SourcePos        = {0};
    4427     //pDbgc->DumpPos          = {0};
    4428     //pDbgc->cbDumpElement    = 0;
    4429     //pDbgc->cVars            = 0;
    4430     //pDbgc->paVars           = NULL;
    4431     //pDbgc->pFirstBp         = NULL;
    4432     //pDbgc->uInputZero       = 0;
    4433     //pDbgc->iRead            = 0;
    4434     //pDbgc->iWrite           = 0;
    4435     //pDbgc->cInputLines      = 0;
    4436     //pDbgc->fInputOverflow   = false;
    4437     pDbgc->fReady           = true;
    4438     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    4439     //pDbgc->iArg             = 0;
    4440     //pDbgc->rcOutput         = 0;
    4441 
    4442     dbgcInitOpCharBitMap();
    4443 
    4444     /*
    4445      * Print welcome message.
    4446      */
    4447     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4448         "Welcome to the VirtualBox Debugger!\n");
    4449     if (VBOX_FAILURE(rc))
    4450         goto l_failure;
    4451 
    4452     /*
    4453      * Attach to the VM.
    4454      */
    4455     rc = DBGFR3Attach(pVM);
    4456     if (VBOX_FAILURE(rc))
    4457     {
    4458         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    4459         goto l_failure;
    4460     }
    4461     pDbgc->pVM = pVM;
    4462 
    4463     /*
    4464      * Print commandline and auto select result.
    4465      */
    4466     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4467         "Current VM is %08x\n" /** @todo get and print the VM name! */
    4468         "VBoxDbg> ",
    4469         pDbgc->pVM);
    4470     if (VBOX_FAILURE(rc))
    4471         goto l_failure;
    4472 
    4473     /*
    4474      * Main Debugger Loop.
    4475      *
    4476      * This loop will either block on waiting for input or on waiting on
    4477      * debug events. If we're forwarding the log we cannot wait for long
    4478      * before we must flush the log.
    4479      */
    4480     for (rc = 0;;)
    4481     {
    4482         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    4483         {
    4484             /*
    4485              * Wait for a debug event.
    4486              */
    4487             PCDBGFEVENT pEvent;
    4488             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    4489             if (VBOX_SUCCESS(rc))
    4490             {
    4491                 rc = dbgcProcessEvent(pDbgc, pEvent);
    4492                 if (VBOX_FAILURE(rc))
    4493                     break;
    4494             }
    4495             else if (rc != VERR_TIMEOUT)
    4496                 break;
    4497 
    4498             /*
    4499              * Check for input.
    4500              */
    4501             if (pBack->pfnInput(pDbgc->pBack, 0))
    4502             {
    4503                 rc = dbgcProcessInput(pDbgc);
    4504                 if (VBOX_FAILURE(rc))
    4505                     break;
    4506             }
    4507         }
    4508         else
    4509         {
    4510             /*
    4511              * Wait for input. If Logging is enabled we'll only wait very briefly.
    4512              */
    4513             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    4514             {
    4515                 rc = dbgcProcessInput(pDbgc);
    4516                 if (VBOX_FAILURE(rc))
    4517                     break;
    4518             }
    4519         }
    4520 
    4521         /*
    4522          * Forward log output.
    4523          */
    4524         if (pDbgc->fLog)
    4525         {
    4526             rc = dbgcProcessLog(pDbgc);
    4527             if (VBOX_FAILURE(rc))
    4528                 break;
    4529         }
    4530     }
    4531 
    4532 
    4533 l_failure:
    4534     /*
    4535      * Cleanup console debugger session.
    4536      */
    4537     /* Disable log hook. */
    4538     if (pDbgc->fLog)
    4539     {
    4540 
    4541     }
    4542 
    4543     /* Detach from the VM. */
    4544     if (pDbgc->pVM)
    4545         DBGFR3Detach(pDbgc->pVM);
    4546 
    4547     /* finally, free the instance memory. */
    4548     RTMemFree(pDbgc);
    4549 
    4550     return rc;
    4551 }
    4552 
    4553 
    4554 
    4555 /**
    4556  * Register one or more external commands.
    4557  *
    4558  * @returns VBox status.
    4559  * @param   paCommands      Pointer to an array of command descriptors.
    4560  *                          The commands must be unique. It's not possible
    4561  *                          to register the same commands more than once.
    4562  * @param   cCommands       Number of commands.
    4563  */
    4564 DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    4565 {
    4566     /*
    4567      * Lock the list.
    4568      */
    4569     DBGCEXTCMDS_LOCK_WR();
    4570     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    4571     while (pCur)
    4572     {
    4573         if (paCommands == pCur->paCmds)
    4574         {
    4575             DBGCEXTCMDS_UNLOCK_WR();
    4576             AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
    4577             return VWRN_DBGC_ALREADY_REGISTERED;
    4578         }
    4579         pCur = pCur->pNext;
    4580     }
    4581 
    4582     /*
    4583      * Allocate new chunk.
    4584      */
    4585     int rc = 0;
    4586     pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
    4587     if (pCur)
    4588     {
    4589         pCur->cCmds  = cCommands;
    4590         pCur->paCmds = paCommands;
    4591         pCur->pNext = g_pExtCmdsHead;
    4592         g_pExtCmdsHead = pCur;
    4593     }
    4594     else
    4595         rc = VERR_NO_MEMORY;
    4596     DBGCEXTCMDS_UNLOCK_WR();
    4597 
    4598     return rc;
    4599 }
    4600 
    4601 
    4602 /**
    4603  * Deregister one or more external commands previously registered by
    4604  * DBGCRegisterCommands().
    4605  *
    4606  * @returns VBox status.
    4607  * @param   paCommands      Pointer to an array of command descriptors
    4608  *                          as given to DBGCRegisterCommands().
    4609  * @param   cCommands       Number of commands.
    4610  */
    4611 DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    4612 {
    4613     /*
    4614      * Lock the list.
    4615      */
    4616     DBGCEXTCMDS_LOCK_WR();
    4617     PDBGCEXTCMDS pPrev = NULL;
    4618     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    4619     while (pCur)
    4620     {
    4621         if (paCommands == pCur->paCmds)
    4622         {
    4623             if (pPrev)
    4624                 pPrev->pNext = pCur->pNext;
    4625             else
    4626                 g_pExtCmdsHead = pCur->pNext;
    4627             DBGCEXTCMDS_UNLOCK_WR();
    4628 
    4629             RTMemFree(pCur);
    4630             return VINF_SUCCESS;
    4631         }
    4632         pPrev = pCur;
    4633         pCur = pCur->pNext;
    4634     }
    4635     DBGCEXTCMDS_UNLOCK_WR();
    4636 
    4637     NOREF(cCommands);
    4638     return VERR_DBGC_COMMANDS_NOT_REGISTERED;
    4639 }
    4640 
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r5673 r5674  
    148148static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    149149
    150 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
    151 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
    152 
    153150static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    154151static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
     
    281278    { "stop",       0,        0,        NULL,               0,                          NULL,               0,          dbgcCmdStop,        "",                     "Stop execution." },
    282279    { "unset",      1,        ~0,       &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr),   NULL,               0,          dbgcCmdUnset,       "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
    283 };
    284 
    285 
    286 /** Register symbol uUser value.
    287  * @{
    288  */
    289 /** If set the register set is the hypervisor and not the guest one. */
    290 #define SYMREG_FLAGS_HYPER      RT_BIT(20)
    291 /** If set a far conversion of the value will use the high 16 bit for the selector.
    292  * If clear the low 16 bit will be used. */
    293 #define SYMREG_FLAGS_HIGH_SEL   RT_BIT(21)
    294 /** The shift value to calc the size of a register symbol from the uUser value. */
    295 #define SYMREG_SIZE_SHIFT       (24)
    296 /** Get the offset */
    297 #define SYMREG_OFFSET(uUser)    (uUser & ((1 << 20) - 1))
    298 /** Get the size. */
    299 #define SYMREG_SIZE(uUser)      ((uUser >> SYMREG_SIZE_SHIFT) & 0xff)
    300 /** 1 byte. */
    301 #define SYMREG_SIZE_1           ( 1 << SYMREG_SIZE_SHIFT)
    302 /** 2 byte. */
    303 #define SYMREG_SIZE_2           ( 2 << SYMREG_SIZE_SHIFT)
    304 /** 4 byte. */
    305 #define SYMREG_SIZE_4           ( 4 << SYMREG_SIZE_SHIFT)
    306 /** 6 byte. */
    307 #define SYMREG_SIZE_6           ( 6 << SYMREG_SIZE_SHIFT)
    308 /** 8 byte. */
    309 #define SYMREG_SIZE_8           ( 8 << SYMREG_SIZE_SHIFT)
    310 /** 12 byte. */
    311 #define SYMREG_SIZE_12          (12 << SYMREG_SIZE_SHIFT)
    312 /** 16 byte. */
    313 #define SYMREG_SIZE_16          (16 << SYMREG_SIZE_SHIFT)
    314 /** @} */
    315 
    316 /** Builtin Symbols.
    317  * ASSUMES little endian register representation!
    318  */
    319 static const DBGCSYM    g_aSyms[] =
    320 {
    321     { "eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 },
    322     { "ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 },
    323     { "al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 },
    324     { "ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 },
    325 
    326     { "ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 },
    327     { "bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 },
    328     { "bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 },
    329     { "bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 },
    330 
    331     { "ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 },
    332     { "cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 },
    333     { "cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 },
    334     { "ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 },
    335 
    336     { "edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 },
    337     { "dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 },
    338     { "dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 },
    339     { "dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 },
    340 
    341     { "edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 },
    342     { "di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 },
    343 
    344     { "esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 },
    345     { "si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 },
    346 
    347     { "ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 },
    348     { "bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 },
    349 
    350     { "esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 },
    351     { "sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 },
    352 
    353     { "eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 },
    354     { "ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 },
    355 
    356     { "efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    357     { "eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 },
    358     { "fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    359     { "flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 },
    360 
    361     { "cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 },
    362     { "ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 },
    363     { "es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 },
    364     { "fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 },
    365     { "gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 },
    366     { "ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 },
    367 
    368     { "cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 },
    369     { "cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 },
    370     { "cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 },
    371     { "cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 },
    372 
    373     { "tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 },
    374     { "ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 },
    375 
    376     { "gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 },
    377     { "gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 },
    378     { "gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 },
    379 
    380     { "idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 },
    381     { "idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 },
    382     { "idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 },
    383 
    384     /* hypervisor */
    385 
    386     {".eax",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    387     {".ax",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    388     {".al",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    389     {".ah",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eax) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    390 
    391     {".ebx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    392     {".bx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    393     {".bl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    394     {".bh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    395 
    396     {".ecx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    397     {".cx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    398     {".cl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    399     {".ch",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ecx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    400 
    401     {".edx",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    402     {".dx",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    403     {".dl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx)      | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    404     {".dh",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edx) + 1  | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
    405 
    406     {".edi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    407     {".di",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, edi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    408 
    409     {".esi",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    410     {".si",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esi)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    411 
    412     {".ebp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    413     {".bp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ebp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    414 
    415     {".esp",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    416     {".sp",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, esp)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    417 
    418     {".eip",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    419     {".ip",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eip)      | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    420 
    421     {".efl",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    422     {".eflags", dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    423     {".fl",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    424     {".flags",  dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, eflags)   | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    425 
    426     {".cs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    427     {".ds",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ds)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    428     {".es",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, es)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    429     {".fs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, fs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    430     {".gs",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gs)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    431     {".ss",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ss)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    432 
    433     {".cr0",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr0)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    434     {".cr2",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr2)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    435     {".cr3",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr3)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    436     {".cr4",    dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, cr4)      | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    437 
    438     {".tr",     dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, tr)       | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    439     {".ldtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, ldtr)     | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
    440 
    441     {".gdtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, gdtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    442     {".gdtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    443     {".gdtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    444 
    445     {".idtr",   dbgcSymGetReg,          dbgcSymSetReg,      offsetof(CPUMCTX, idtr)     | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
    446     {".idtr.limit", dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
    447     {".idtr.base",  dbgcSymGetReg,      dbgcSymSetReg,      offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
    448 
    449280};
    450281
     
    14531284
    14541285
    1455 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1456 //
    1457 //
    1458 //      B u l t i n   S y m b o l s
    1459 //
    1460 //
    1461 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1462 
    1463 
    1464 
    1465 /**
    1466  * Get builtin register symbol.
    1467  *
    1468  * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
    1469  *
    1470  * @returns 0 on success.
    1471  * @returns VBox evaluation / parsing error code on failure.
    1472  *          The caller does the bitching.
    1473  * @param   pSymDesc    Pointer to the symbol descriptor.
    1474  * @param   pCmdHlp     Pointer to the command callback structure.
    1475  * @param   enmType     The result type.
    1476  * @param   pResult     Where to store the result.
    1477  */
    1478 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
    1479 {
    1480     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    1481 
    1482     /*
    1483      * pVM is required.
    1484      */
    1485     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1486     Assert(pDbgc->pVM);
    1487 
    1488     /*
    1489      * Get the right CPU context.
    1490      */
    1491     PCPUMCTX    pCtx;
    1492     int         rc;
    1493     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    1494         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    1495     else
    1496         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    1497     if (VBOX_FAILURE(rc))
    1498         return rc;
    1499 
    1500     /*
    1501      * Get the value.
    1502      */
    1503     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    1504     uint64_t    u64;
    1505     switch (SYMREG_SIZE(pSymDesc->uUser))
    1506     {
    1507         case 1: u64 = *(uint8_t *)pvValue; break;
    1508         case 2: u64 = *(uint16_t *)pvValue; break;
    1509         case 4: u64 = *(uint32_t *)pvValue; break;
    1510         case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
    1511         case 8: u64 = *(uint64_t *)pvValue; break;
    1512         default:
    1513             return VERR_PARSE_NOT_IMPLEMENTED;
    1514     }
    1515 
    1516     /*
    1517      * Construct the desired result.
    1518      */
    1519     if (enmType == DBGCVAR_TYPE_ANY)
    1520         enmType = DBGCVAR_TYPE_NUMBER;
    1521     pResult->pDesc          = NULL;
    1522     pResult->pNext          = NULL;
    1523     pResult->enmType        = enmType;
    1524     pResult->enmRangeType   = DBGCVAR_RANGE_NONE;
    1525     pResult->u64Range       = 0;
    1526 
    1527     switch (enmType)
    1528     {
    1529         case DBGCVAR_TYPE_GC_FLAT:
    1530             pResult->u.GCFlat = (RTGCPTR)u64;
    1531             break;
    1532 
    1533         case DBGCVAR_TYPE_GC_FAR:
    1534             switch (SYMREG_SIZE(pSymDesc->uUser))
    1535             {
    1536                 case 4:
    1537                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1538                     {
    1539                         pResult->u.GCFar.off = (uint16_t)u64;
    1540                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);
    1541                     }
    1542                     else
    1543                     {
    1544                         pResult->u.GCFar.sel = (uint16_t)u64;
    1545                         pResult->u.GCFar.off = (uint16_t)(u64 >> 16);
    1546                     }
    1547                     break;
    1548                 case 6:
    1549                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1550                     {
    1551                         pResult->u.GCFar.off = (uint32_t)u64;
    1552                         pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);
    1553                     }
    1554                     else
    1555                     {
    1556                         pResult->u.GCFar.sel = (uint32_t)u64;
    1557                         pResult->u.GCFar.off = (uint16_t)(u64 >> 32);
    1558                     }
    1559                     break;
    1560 
    1561                 default:
    1562                     return VERR_PARSE_BAD_RESULT_TYPE;
    1563             }
    1564             break;
    1565 
    1566         case DBGCVAR_TYPE_GC_PHYS:
    1567             pResult->u.GCPhys = (RTGCPHYS)u64;
    1568             break;
    1569 
    1570         case DBGCVAR_TYPE_HC_FLAT:
    1571             pResult->u.pvHCFlat = (void *)(uintptr_t)u64;
    1572             break;
    1573 
    1574         case DBGCVAR_TYPE_HC_FAR:
    1575             switch (SYMREG_SIZE(pSymDesc->uUser))
    1576             {
    1577                 case 4:
    1578                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1579                     {
    1580                         pResult->u.HCFar.off = (uint16_t)u64;
    1581                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);
    1582                     }
    1583                     else
    1584                     {
    1585                         pResult->u.HCFar.sel = (uint16_t)u64;
    1586                         pResult->u.HCFar.off = (uint16_t)(u64 >> 16);
    1587                     }
    1588                     break;
    1589                 case 6:
    1590                     if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
    1591                     {
    1592                         pResult->u.HCFar.off = (uint32_t)u64;
    1593                         pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);
    1594                     }
    1595                     else
    1596                     {
    1597                         pResult->u.HCFar.sel = (uint32_t)u64;
    1598                         pResult->u.HCFar.off = (uint16_t)(u64 >> 32);
    1599                     }
    1600                     break;
    1601 
    1602                 default:
    1603                     return VERR_PARSE_BAD_RESULT_TYPE;
    1604             }
    1605             break;
    1606 
    1607         case DBGCVAR_TYPE_HC_PHYS:
    1608             pResult->u.GCPhys = (RTGCPHYS)u64;
    1609             break;
    1610 
    1611         case DBGCVAR_TYPE_NUMBER:
    1612             pResult->u.u64Number = u64;
    1613             break;
    1614 
    1615         case DBGCVAR_TYPE_STRING:
    1616         case DBGCVAR_TYPE_UNKNOWN:
    1617         default:
    1618             return VERR_PARSE_BAD_RESULT_TYPE;
    1619 
    1620     }
    1621 
    1622     return 0;
    1623 }
    1624 
    1625 
    1626 /**
    1627  * Set builtin register symbol.
    1628  *
    1629  * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
    1630  *
    1631  * @returns 0 on success.
    1632  * @returns VBox evaluation / parsing error code on failure.
    1633  *          The caller does the bitching.
    1634  * @param   pSymDesc    Pointer to the symbol descriptor.
    1635  * @param   pCmdHlp     Pointer to the command callback structure.
    1636  * @param   pValue      The value to assign the symbol.
    1637  */
    1638 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)
    1639 {
    1640     LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
    1641 
    1642     /*
    1643      * pVM is required.
    1644      */
    1645     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1646     Assert(pDbgc->pVM);
    1647 
    1648     /*
    1649      * Get the right CPU context.
    1650      */
    1651     PCPUMCTX    pCtx;
    1652     int         rc;
    1653     if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
    1654         rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
    1655     else
    1656         rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
    1657     if (VBOX_FAILURE(rc))
    1658         return rc;
    1659 
    1660     /*
    1661      * Check the new value.
    1662      */
    1663     if (pValue->enmType != DBGCVAR_TYPE_NUMBER)
    1664         return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1665 
    1666     /*
    1667      * Set the value.
    1668      */
    1669     void       *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
    1670     switch (SYMREG_SIZE(pSymDesc->uUser))
    1671     {
    1672         case 1:
    1673             *(uint8_t *)pvValue  = (uint8_t)pValue->u.u64Number;
    1674             break;
    1675         case 2:
    1676             *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;
    1677             break;
    1678         case 4:
    1679             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    1680             break;
    1681         case 6:
    1682             *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
    1683             ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);
    1684             break;
    1685         case 8:
    1686             *(uint64_t *)pvValue = pValue->u.u64Number;
    1687             break;
    1688         default:
    1689             return VERR_PARSE_NOT_IMPLEMENTED;
    1690     }
    1691 
    1692     return VINF_SUCCESS;
    1693 }
    1694 
    1695 
    1696 
    1697 
    1698 
    1699 
    17001286
    17011287//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
     
    28082394}
    28092395
    2810 
    2811 /**
    2812  * Finds a builtin symbol.
    2813  * @returns Pointer to symbol descriptor on success.
    2814  * @returns NULL on failure.
    2815  * @param   pDbgc       The debug console instance.
    2816  * @param   pszSymbol   The symbol name.
    2817  */
    2818 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
    2819 {
    2820     for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)
    2821         if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
    2822             return &g_aSyms[iSym];
    2823 
    2824     /** @todo externally registered symbols. */
    2825     NOREF(pDbgc);
    2826     return NULL;
    2827 }
    28282396
    28292397
  • trunk/src/VBox/Debugger/Makefile.kmk

    r5673 r5674  
    3636Debugger_SOURCES   = \
    3737        DBGConsole.cpp \
     38        DBGCBuiltInSymbols.cpp \
     39        DBGCEmulateCodeView.cpp \
    3840        DBGCOps.cpp \
    39         DBGCEmulateCodeView.cpp \
    4041        DBGCTcp.cpp
    4142
     
    99100        VBoxDbgStats.cpp \
    100101        DBGConsole.cpp \
    101         DBGCOps.cpp \
    102         DBGCEmulateCodeView.cpp
     102        DBGCBuiltInSymbols.cpp \
     103        DBGCEmulateCodeView.cpp \
     104        DBGCOps.cpp
    103105
    104106VBoxDbg_LIBS = $(LIB_VMM)
Note: See TracChangeset for help on using the changeset viewer.

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