VirtualBox

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

Split out the commands.

File:
1 copied

Legend:

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

    r5674 r5675  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Native Commands.
    44 */
    55
     
    1515 * be useful, but WITHOUT ANY WARRANTY of any kind.
    1616 */
    17 
    18 
    19 /** @page pg_dbgc                       DBGC - The Debug Console
    20  *
    21  * The debugger console is a first attempt to make some interactive
    22  * debugging facilities for the VirtualBox backend (i.e. the VM). At a later
    23  * stage we'll make a fancy gui around this, but for the present a telnet (or
    24  * serial terminal) will have to suffice.
    25  *
    26  * The debugger is only built into the VM with debug builds or when
    27  * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this
    28  * define to enable special debugger hooks, but the general approach is to
    29  * make generic interfaces. The individual components also can register
    30  * external commands, and such code must be within \#ifdef.
    31  *
    32  *
    33  * @section sec_dbgc_op                 Operation (intentions)
    34  *
    35  * The console will process commands in a manner similar to the OS/2 and
    36  * windows kernel debuggers. This means ';' is a command separator and
    37  * that when possible we'll use the same command names as these two uses.
    38  *
    39  *
    40  * @subsection sec_dbg_op_numbers       Numbers
    41  *
    42  * Numbers are hexadecimal unless specified with a prefix indicating
    43  * elsewise. Prefixes:
    44  *      - '0x' - hexadecimal.
    45  *      - '0i' - decimal
    46  *      - '0t' - octal.
    47  *      - '0y' - binary.
    48  *
    49  *
    50  * @subsection sec_dbg_op_address       Addressing modes
    51  *
    52  *      - Default is flat. For compatability '%' also means flat.
    53  *      - Segmented addresses are specified selector:offset.
    54  *      - Physical addresses are specified using '%%'.
    55  *      - The default target for the addressing is the guest context, the '#'
    56  *        will override this and set it to the host.
    57  *
    58  *
    59  * @subsection sec_dbg_op_evalution     Evaluation
    60  *
    61  * As time permits support will be implemented support for a subset of the C
    62  * binary operators, starting with '+', '-', '*' and '/'. Support for variables
    63  * are provided thru commands 'set' and 'unset' and the unary operator '$'. The
    64  * unary '@' operator will indicate function calls. The debugger needs a set of
    65  * memory read functions, but we might later extend this to allow registration of
    66  * external functions too.
    67  *
    68  * A special command '?' will then be added which evalutates a given expression
    69  * and prints it in all the different formats.
    70  *
    71  *
    72  * @subsection sec_dbg_op_registers     Registers
    73  *
    74  * Registers are addressed using their name. Some registers which have several fields
    75  * (like gdtr) will have separate names indicating the different fields. The default
    76  * register set is the guest one. To access the hypervisor register one have to
    77  * prefix the register names with '.'.
    78  *
    79  *
    80  * @subsection sec_dbg_op_commands      Commands
    81  *
    82  * The commands are all lowercase, case sensitive, and starting with a letter. We will
    83  * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')
    84  *
    85  *
    86  * @section sec_dbg_tasks               Tasks
    87  *
    88  * To implement DBGT and instrument VMM for basic state inspection and log
    89  * viewing, the follwing task must be executed:
    90  *
    91  *      -# Basic threading layer in RT.
    92  *      -# Basic tcpip server abstration in RT.
    93  *      -# Write DBGC.
    94  *      -# Write DBCTCP.
    95  *      -# Integrate with VMM and the rest.
    96  *      -# Start writing DBGF (VMM).
    97  */
    98 
    99 
    100 
    10117
    10218/*******************************************************************************
     
    14864static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
    14965
    150 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    151 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
    152 
    15366
    15467/*******************************************************************************
    15568*   Global Variables                                                           *
    15669*******************************************************************************/
    157 /**
    158  * Pointer to head of the list of external commands.
    159  */
    160 static PDBGCEXTCMDS     g_pExtCmdsHead;     /** @todo rw protect g_pExtCmdsHead! */
    161 /** Locks the g_pExtCmdsHead list for reading. */
    162 #define DBGCEXTCMDS_LOCK_RD()       do { } while (0)
    163 /** Locks the g_pExtCmdsHead list for writing. */
    164 #define DBGCEXTCMDS_LOCK_WR()       do { } while (0)
    165 /** UnLocks the g_pExtCmdsHead list after reading. */
    166 #define DBGCEXTCMDS_UNLOCK_RD()     do { } while (0)
    167 /** UnLocks the g_pExtCmdsHead list after writing. */
    168 #define DBGCEXTCMDS_UNLOCK_WR()     do { } while (0)
    169 
    170 
    17170/** One argument of any kind. */
    17271static const DBGCVARDESC    g_aArgAny[] =
     
    257156
    258157/** Command descriptors for the basic commands. */
    259 static const DBGCCMD    g_aCmds[] =
     158const DBGCCMD    g_aCmds[] =
    260159{
    261160    /* pszCmd,      cArgsMin, cArgsMax, paArgDescs,         cArgDescs,                  pResultDesc,        fFlags,     pfnHandler          pszSyntax,          ....pszDescription */
     
    280179};
    281180
    282 
    283 /** Bitmap where set bits indicates the characters the may start an operator name. */
    284 static uint32_t g_bmOperatorChars[256 / (4*8)];
    285 
    286 
    287 
    288 
     181/** The number of native commands. */
     182const unsigned g_cCmds = RT_ELEMENTS(g_aCmds);
     183
     184
     185/**
     186 * Pointer to head of the list of external commands.
     187 */
     188static PDBGCEXTCMDS g_pExtCmdsHead;     /** @todo rw protect g_pExtCmdsHead! */
     189/** Locks the g_pExtCmdsHead list for reading. */
     190#define DBGCEXTCMDS_LOCK_RD()       do { } while (0)
     191/** Locks the g_pExtCmdsHead list for writing. */
     192#define DBGCEXTCMDS_LOCK_WR()       do { } while (0)
     193/** UnLocks the g_pExtCmdsHead list after reading. */
     194#define DBGCEXTCMDS_UNLOCK_RD()     do { } while (0)
     195/** UnLocks the g_pExtCmdsHead list after writing. */
     196#define DBGCEXTCMDS_UNLOCK_WR()     do { } while (0)
     197
     198
     199
     200
     201/**
     202 * Finds a routine.
     203 *
     204 * @returns Pointer to the command descriptor.
     205 *          If the request was for an external command, the caller is responsible for
     206 *          unlocking the external command list.
     207 * @returns NULL if not found.
     208 * @param   pDbgc       The debug console instance.
     209 * @param   pachName    Pointer to the routine string (not terminated).
     210 * @param   cchName     Length of the routine name.
     211 * @param   fExternal   Whether or not the routine is external.
     212 */
     213PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
     214{
     215    if (!fExternal)
     216    {
     217        /* emulation first, so commands can be overloaded (info ++). */
     218        PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
     219        unsigned cLeft = pDbgc->cEmulationCmds;
     220        while (cLeft-- > 0)
     221        {
     222            if (    !strncmp(pachName, pCmd->pszCmd, cchName)
     223                &&  !pCmd->pszCmd[cchName])
     224                return pCmd;
     225            pCmd++;
     226        }
     227
     228        for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
     229        {
     230            if (    !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
     231                &&  !g_aCmds[iCmd].pszCmd[cchName])
     232                return &g_aCmds[iCmd];
     233        }
     234    }
     235    else
     236    {
     237        DBGCEXTCMDS_LOCK_RD();
     238        for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
     239        {
     240            for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
     241            {
     242                if (    !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
     243                    &&  !pExtCmds->paCmds[iCmd].pszCmd[cchName])
     244                    return &pExtCmds->paCmds[iCmd];
     245            }
     246        }
     247        DBGCEXTCMDS_UNLOCK_RD();
     248    }
     249
     250    NOREF(pDbgc);
     251    return NULL;
     252}
     253
     254
     255/**
     256 * Register one or more external commands.
     257 *
     258 * @returns VBox status.
     259 * @param   paCommands      Pointer to an array of command descriptors.
     260 *                          The commands must be unique. It's not possible
     261 *                          to register the same commands more than once.
     262 * @param   cCommands       Number of commands.
     263 */
     264DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
     265{
     266    /*
     267     * Lock the list.
     268     */
     269    DBGCEXTCMDS_LOCK_WR();
     270    PDBGCEXTCMDS pCur = g_pExtCmdsHead;
     271    while (pCur)
     272    {
     273        if (paCommands == pCur->paCmds)
     274        {
     275            DBGCEXTCMDS_UNLOCK_WR();
     276            AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
     277            return VWRN_DBGC_ALREADY_REGISTERED;
     278        }
     279        pCur = pCur->pNext;
     280    }
     281
     282    /*
     283     * Allocate new chunk.
     284     */
     285    int rc = 0;
     286    pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
     287    if (pCur)
     288    {
     289        pCur->cCmds  = cCommands;
     290        pCur->paCmds = paCommands;
     291        pCur->pNext = g_pExtCmdsHead;
     292        g_pExtCmdsHead = pCur;
     293    }
     294    else
     295        rc = VERR_NO_MEMORY;
     296    DBGCEXTCMDS_UNLOCK_WR();
     297
     298    return rc;
     299}
     300
     301
     302/**
     303 * Deregister one or more external commands previously registered by
     304 * DBGCRegisterCommands().
     305 *
     306 * @returns VBox status.
     307 * @param   paCommands      Pointer to an array of command descriptors
     308 *                          as given to DBGCRegisterCommands().
     309 * @param   cCommands       Number of commands.
     310 */
     311DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
     312{
     313    /*
     314     * Lock the list.
     315     */
     316    DBGCEXTCMDS_LOCK_WR();
     317    PDBGCEXTCMDS pPrev = NULL;
     318    PDBGCEXTCMDS pCur = g_pExtCmdsHead;
     319    while (pCur)
     320    {
     321        if (paCommands == pCur->paCmds)
     322        {
     323            if (pPrev)
     324                pPrev->pNext = pCur->pNext;
     325            else
     326                g_pExtCmdsHead = pCur->pNext;
     327            DBGCEXTCMDS_UNLOCK_WR();
     328
     329            RTMemFree(pCur);
     330            return VINF_SUCCESS;
     331        }
     332        pPrev = pCur;
     333        pCur = pCur->pNext;
     334    }
     335    DBGCEXTCMDS_UNLOCK_WR();
     336
     337    NOREF(cCommands);
     338    return VERR_DBGC_COMMANDS_NOT_REGISTERED;
     339}
    289340
    290341
     
    12801331}
    12811332
    1282 
    1283 
    1284 
    1285 
    1286 
    1287 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1288 //
    1289 //
    1290 //      C a l l b a c k   H e l p e r s
    1291 //
    1292 //
    1293 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1294 
    1295 
    1296 
    1297 /**
    1298  * Command helper for writing text to the debug console.
    1299  *
    1300  * @returns VBox status.
    1301  * @param   pCmdHlp     Pointer to the command callback structure.
    1302  * @param   pvBuf       What to write.
    1303  * @param   cbBuf       Number of bytes to write.
    1304  * @param   pcbWritten  Where to store the number of bytes actually written.
    1305  *                      If NULL the entire buffer must be successfully written.
    1306  */
    1307 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    1308 {
    1309     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1310     return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
    1311 }
    1312 
    1313 
    1314 /**
    1315  * Command helper for writing formatted text to the debug console.
    1316  *
    1317  * @returns VBox status.
    1318  * @param   pCmdHlp     Pointer to the command callback structure.
    1319  * @param   pcb         Where to store the number of bytes written.
    1320  * @param   pszFormat   The format string.
    1321  *                      This is using the log formatter, so it's format extensions can be used.
    1322  * @param   ...         Arguments specified in the format string.
    1323  */
    1324 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
    1325 {
    1326     /*
    1327      * Do the formatting and output.
    1328      */
    1329     va_list args;
    1330     va_start(args, pszFormat);
    1331     int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
    1332     va_end(args);
    1333 
    1334     return rc;
    1335 }
    1336 
    1337 /**
    1338  * Callback to format non-standard format specifiers.
    1339  *
    1340  * @returns The number of bytes formatted.
    1341  * @param   pvArg           Formatter argument.
    1342  * @param   pfnOutput       Pointer to output function.
    1343  * @param   pvArgOutput     Argument for the output function.
    1344  * @param   ppszFormat      Pointer to the format string pointer. Advance this till the char
    1345  *                          after the format specifier.
    1346  * @param   pArgs           Pointer to the argument list. Use this to fetch the arguments.
    1347  * @param   cchWidth        Format Width. -1 if not specified.
    1348  * @param   cchPrecision    Format Precision. -1 if not specified.
    1349  * @param   fFlags          Flags (RTSTR_NTFS_*).
    1350  * @param   chArgSize       The argument size specifier, 'l' or 'L'.
    1351  */
    1352 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
    1353                                                 const char **ppszFormat, va_list *pArgs, int cchWidth,
    1354                                                 int cchPrecision, unsigned fFlags, char chArgSize)
    1355 {
    1356     NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
    1357     if (**ppszFormat != 'D')
    1358     {
    1359         (*ppszFormat)++;
    1360         return 0;
    1361     }
    1362 
    1363     (*ppszFormat)++;
    1364     switch (**ppszFormat)
    1365     {
    1366         /*
    1367          * Print variable without range.
    1368          * The argument is a const pointer to the variable.
    1369          */
    1370         case 'V':
    1371         {
    1372             (*ppszFormat)++;
    1373             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    1374             switch (pVar->enmType)
    1375             {
    1376                 case DBGCVAR_TYPE_GC_FLAT:
    1377                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
    1378                 case DBGCVAR_TYPE_GC_FAR:
    1379                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
    1380                 case DBGCVAR_TYPE_GC_PHYS:
    1381                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
    1382                 case DBGCVAR_TYPE_HC_FLAT:
    1383                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
    1384                 case DBGCVAR_TYPE_HC_FAR:
    1385                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
    1386                 case DBGCVAR_TYPE_HC_PHYS:
    1387                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
    1388                 case DBGCVAR_TYPE_STRING:
    1389                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    1390                 case DBGCVAR_TYPE_NUMBER:
    1391                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
    1392 
    1393                 case DBGCVAR_TYPE_UNKNOWN:
    1394                 default:
    1395                     return pfnOutput(pvArgOutput, "??", 2);
    1396             }
    1397         }
    1398 
    1399         /*
    1400          * Print variable with range.
    1401          * The argument is a const pointer to the variable.
    1402          */
    1403         case 'v':
    1404         {
    1405             (*ppszFormat)++;
    1406             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    1407 
    1408             char szRange[32];
    1409             switch (pVar->enmRangeType)
    1410             {
    1411                 case DBGCVAR_RANGE_NONE:
    1412                     szRange[0] = '\0';
    1413                     break;
    1414                 case DBGCVAR_RANGE_ELEMENTS:
    1415                     RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
    1416                     break;
    1417                 case DBGCVAR_RANGE_BYTES:
    1418                     RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
    1419                     break;
    1420             }
    1421 
    1422             switch (pVar->enmType)
    1423             {
    1424                 case DBGCVAR_TYPE_GC_FLAT:
    1425                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
    1426                 case DBGCVAR_TYPE_GC_FAR:
    1427                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
    1428                 case DBGCVAR_TYPE_GC_PHYS:
    1429                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
    1430                 case DBGCVAR_TYPE_HC_FLAT:
    1431                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
    1432                 case DBGCVAR_TYPE_HC_FAR:
    1433                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
    1434                 case DBGCVAR_TYPE_HC_PHYS:
    1435                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
    1436                 case DBGCVAR_TYPE_STRING:
    1437                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    1438                 case DBGCVAR_TYPE_NUMBER:
    1439                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
    1440 
    1441                 case DBGCVAR_TYPE_UNKNOWN:
    1442                 default:
    1443                     return pfnOutput(pvArgOutput, "??", 2);
    1444             }
    1445         }
    1446 
    1447         default:
    1448             AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
    1449             return 0;
    1450     }
    1451 }
    1452 
    1453 
    1454 /**
    1455  * Output callback.
    1456  *
    1457  * @returns number of bytes written.
    1458  * @param   pvArg       User argument.
    1459  * @param   pachChars   Pointer to an array of utf-8 characters.
    1460  * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    1461  */
    1462 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
    1463 {
    1464     PDBGC   pDbgc = (PDBGC)pvArg;
    1465     if (cbChars)
    1466     {
    1467         int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
    1468         if (VBOX_FAILURE(rc))
    1469         {
    1470             pDbgc->rcOutput = rc;
    1471             cbChars = 0;
    1472         }
    1473     }
    1474 
    1475     return cbChars;
    1476 }
    1477 
    1478 
    1479 
    1480 /**
    1481  * Command helper for writing formatted text to the debug console.
    1482  *
    1483  * @returns VBox status.
    1484  * @param   pCmdHlp     Pointer to the command callback structure.
    1485  * @param   pcb         Where to store the number of bytes written.
    1486  * @param   pszFormat   The format string.
    1487  *                      This is using the log formatter, so it's format extensions can be used.
    1488  * @param   args        Arguments specified in the format string.
    1489  */
    1490 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
    1491 {
    1492     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1493 
    1494     /*
    1495      * Do the formatting and output.
    1496      */
    1497     pDbgc->rcOutput = 0;
    1498     size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
    1499 
    1500     if (pcbWritten)
    1501         *pcbWritten = cb;
    1502 
    1503     return pDbgc->rcOutput;
    1504 }
    1505 
    1506 
    1507 /**
    1508  * Reports an error from a DBGF call.
    1509  *
    1510  * @returns VBox status code appropriate to return from a command.
    1511  * @param   pCmdHlp     Pointer to command helpers.
    1512  * @param   rc          The VBox status code returned by a DBGF call.
    1513  * @param   pszFormat   Format string for additional messages. Can be NULL.
    1514  * @param   ...         Format arguments, optional.
    1515  */
    1516 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
    1517 {
    1518     switch (rc)
    1519     {
    1520         case VINF_SUCCESS:
    1521             break;
    1522 
    1523         default:
    1524             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
    1525             if (VBOX_SUCCESS(rc) && pszFormat)
    1526                 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    1527             break;
    1528     }
    1529     return rc;
    1530 }
    1531 
    1532 
    1533 /**
    1534  * Reports an error from a DBGF call.
    1535  *
    1536  * @returns VBox status code appropriate to return from a command.
    1537  * @param   pCmdHlp     Pointer to command helpers.
    1538  * @param   rc          The VBox status code returned by a DBGF call.
    1539  * @param   pszFormat   Format string for additional messages. Can be NULL.
    1540  * @param   ...         Format arguments, optional.
    1541  */
    1542 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
    1543 {
    1544     va_list args;
    1545     va_start(args, pszFormat);
    1546     int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
    1547     va_end(args);
    1548     return rcRet;
    1549 }
    1550 
    1551 
    1552 /**
    1553  * Command helper for reading memory specified by a DBGC variable.
    1554  *
    1555  * @returns VBox status code appropriate to return from a command.
    1556  * @param   pCmdHlp     Pointer to the command callback structure.
    1557  * @param   pVM         VM handle if GC or physical HC address.
    1558  * @param   pvBuffer    Where to store the read data.
    1559  * @param   cbRead      Number of bytes to read.
    1560  * @param   pVarPointer DBGC variable specifying where to start reading.
    1561  * @param   pcbRead     Where to store the number of bytes actually read.
    1562  *                      This optional, but it's useful when read GC virtual memory where a
    1563  *                      page in the requested range might not be present.
    1564  *                      If not specified not-present failure or end of a HC physical page
    1565  *                      will cause failure.
    1566  */
    1567 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
    1568 {
    1569     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1570 
    1571     /*
    1572      * Dummy check.
    1573      */
    1574     if (cbRead == 0)
    1575     {
    1576         if (*pcbRead)
    1577             *pcbRead = 0;
    1578         return VINF_SUCCESS;
    1579     }
    1580 
    1581     /*
    1582      * Convert Far addresses getting size and the correct base address.
    1583      * Getting and checking the size is what makes this messy and slow.
    1584      */
    1585     DBGCVAR Var = *pVarPointer;
    1586     switch (pVarPointer->enmType)
    1587     {
    1588         case DBGCVAR_TYPE_GC_FAR:
    1589         {
    1590             /* Use DBGFR3AddrFromSelOff for the conversion. */
    1591             Assert(pDbgc->pVM);
    1592             DBGFADDRESS Address;
    1593             int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
    1594             if (VBOX_FAILURE(rc))
    1595                 return rc;
    1596 
    1597             /* don't bother with flat selectors (for now). */
    1598             if (!DBGFADDRESS_IS_FLAT(&Address))
    1599             {
    1600                 SELMSELINFO SelInfo;
    1601                 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
    1602                 if (VBOX_SUCCESS(rc))
    1603                 {
    1604                     RTGCUINTPTR cb; /* -1 byte */
    1605                     if (SELMSelInfoIsExpandDown(&SelInfo))
    1606                     {
    1607                         if (    !SelInfo.Raw.Gen.u1Granularity
    1608                             &&  Address.off > UINT16_C(0xffff))
    1609                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    1610                         if (Address.off <= SelInfo.cbLimit)
    1611                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    1612                         cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
    1613                     }
    1614                     else
    1615                     {
    1616                         if (Address.off > SelInfo.cbLimit)
    1617                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    1618                         cb = SelInfo.cbLimit - Address.off;
    1619                     }
    1620                     if (cbRead - 1 > cb)
    1621                     {
    1622                         if (!pcbRead)
    1623                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    1624                         cbRead = cb + 1;
    1625                     }
    1626                 }
    1627 
    1628                 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
    1629                 Var.u.GCFlat = Address.FlatPtr;
    1630             }
    1631             break;
    1632         }
    1633 
    1634         case DBGCVAR_TYPE_GC_FLAT:
    1635         case DBGCVAR_TYPE_GC_PHYS:
    1636         case DBGCVAR_TYPE_HC_FLAT:
    1637         case DBGCVAR_TYPE_HC_PHYS:
    1638             break;
    1639 
    1640         case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
    1641         default:
    1642             return VERR_NOT_IMPLEMENTED;
    1643     }
    1644 
    1645 
    1646 
    1647     /*
    1648      * Copy page by page.
    1649      */
    1650     size_t cbLeft = cbRead;
    1651     for (;;)
    1652     {
    1653         /*
    1654          * Calc read size.
    1655          */
    1656         size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
    1657         switch (pVarPointer->enmType)
    1658         {
    1659             case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
    1660             case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
    1661             case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
    1662             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! */
    1663             default: break;
    1664         }
    1665 
    1666         /*
    1667          * Perform read.
    1668          */
    1669         int rc;
    1670         switch (Var.enmType)
    1671         {
    1672             case DBGCVAR_TYPE_GC_FLAT:
    1673                 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
    1674                 break;
    1675             case DBGCVAR_TYPE_GC_PHYS:
    1676                 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
    1677                 break;
    1678 
    1679             case DBGCVAR_TYPE_HC_PHYS:
    1680             case DBGCVAR_TYPE_HC_FLAT:
    1681             case DBGCVAR_TYPE_HC_FAR:
    1682             {
    1683                 DBGCVAR Var2;
    1684                 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
    1685                 if (VBOX_SUCCESS(rc))
    1686                 {
    1687                     /** @todo protect this!!! */
    1688                     memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
    1689                     rc = 0;
    1690                 }
    1691                 else
    1692                     rc = VERR_INVALID_POINTER;
    1693                 break;
    1694             }
    1695 
    1696             default:
    1697                 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
    1698         }
    1699 
    1700         /*
    1701          * Check for failure.
    1702          */
    1703         if (VBOX_FAILURE(rc))
    1704         {
    1705             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    1706                 return VINF_SUCCESS;
    1707             return rc;
    1708         }
    1709 
    1710         /*
    1711          * Next.
    1712          */
    1713         cbLeft -= cb;
    1714         if (!cbLeft)
    1715             break;
    1716         pvBuffer = (char *)pvBuffer + cb;
    1717         rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
    1718         if (VBOX_FAILURE(rc))
    1719         {
    1720             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    1721                 return VINF_SUCCESS;
    1722             return rc;
    1723         }
    1724     }
    1725 
    1726     /*
    1727      * Done
    1728      */
    1729     if (pcbRead)
    1730         *pcbRead = cbRead;
    1731     return 0;
    1732 }
    1733 
    1734 /**
    1735  * Command helper for writing memory specified by a DBGC variable.
    1736  *
    1737  * @returns VBox status code appropriate to return from a command.
    1738  * @param   pCmdHlp     Pointer to the command callback structure.
    1739  * @param   pVM         VM handle if GC or physical HC address.
    1740  * @param   pvBuffer    What to write.
    1741  * @param   cbWrite     Number of bytes to write.
    1742  * @param   pVarPointer DBGC variable specifying where to start reading.
    1743  * @param   pcbWritten  Where to store the number of bytes written.
    1744  *                      This is optional. If NULL be aware that some of the buffer
    1745  *                      might have been written to the specified address.
    1746  */
    1747 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
    1748 {
    1749     NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
    1750     return VERR_NOT_IMPLEMENTED;
    1751 }
    1752 
    1753 
    1754 /**
    1755  * Evaluates an expression.
    1756  * (Hopefully the parser and functions are fully reentrant.)
    1757  *
    1758  * @returns VBox status code appropriate to return from a command.
    1759  * @param   pCmdHlp     Pointer to the command callback structure.
    1760  * @param   pResult     Where to store the result.
    1761  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    1762  * @param   ...         Format arguments.
    1763  */
    1764 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
    1765 {
    1766     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1767 
    1768     /*
    1769      * Format the expression.
    1770      */
    1771     char szExprFormatted[2048];
    1772     va_list args;
    1773     va_start(args, pszExpr);
    1774     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
    1775     va_end(args);
    1776     /* ignore overflows. */
    1777 
    1778     return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
    1779 }
    1780 
    1781 
    1782 /**
    1783  * Executes one command expression.
    1784  * (Hopefully the parser and functions are fully reentrant.)
    1785  *
    1786  * @returns VBox status code appropriate to return from a command.
    1787  * @param   pCmdHlp     Pointer to the command callback structure.
    1788  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    1789  * @param   ...         Format arguments.
    1790  */
    1791 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
    1792 {
    1793     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1794     /* Save the scratch state. */
    1795     char       *pszScratch  = pDbgc->pszScratch;
    1796     unsigned    iArg        = pDbgc->iArg;
    1797 
    1798     /*
    1799      * Format the expression.
    1800      */
    1801     va_list args;
    1802     va_start(args, pszExpr);
    1803     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    1804     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
    1805     va_end(args);
    1806     if (cb >= cbScratch)
    1807         return VERR_BUFFER_OVERFLOW;
    1808 
    1809     /*
    1810      * Execute the command.
    1811      * We save and restore the arg index and scratch buffer pointer.
    1812      */
    1813     pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
    1814     int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
    1815 
    1816     /* Restore the scratch state. */
    1817     pDbgc->iArg         = iArg;
    1818     pDbgc->pszScratch   = pszScratch;
    1819 
    1820     return rc;
    1821 }
    1822 
    1823 
    1824 /**
    1825  * Converts a DBGC variable to a DBGF address structure.
    1826  *
    1827  * @returns VBox status code.
    1828  * @param   pCmdHlp     Pointer to the command callback structure.
    1829  * @param   pVar        The variable to convert.
    1830  * @param   pAddress    The target address.
    1831  */
    1832 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    1833 {
    1834     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1835     return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
    1836 }
    1837 
    1838 
    1839 /**
    1840  * Converts a DBGC variable to a boolean.
    1841  *
    1842  * @returns VBox status code.
    1843  * @param   pCmdHlp     Pointer to the command callback structure.
    1844  * @param   pVar        The variable to convert.
    1845  * @param   pf          Where to store the boolean.
    1846  */
    1847 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
    1848 {
    1849     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    1850     NOREF(pDbgc);
    1851 
    1852     switch (pVar->enmType)
    1853     {
    1854         case DBGCVAR_TYPE_STRING:
    1855             /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
    1856             if (    !strcmp(pVar->u.pszString, "true")
    1857                 ||  !strcmp(pVar->u.pszString, "True")
    1858                 ||  !strcmp(pVar->u.pszString, "TRUE")
    1859                 ||  !strcmp(pVar->u.pszString, "on")
    1860                 ||  !strcmp(pVar->u.pszString, "On")
    1861                 ||  !strcmp(pVar->u.pszString, "oN")
    1862                 ||  !strcmp(pVar->u.pszString, "ON")
    1863                 ||  !strcmp(pVar->u.pszString, "enabled")
    1864                 ||  !strcmp(pVar->u.pszString, "Enabled")
    1865                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    1866             {
    1867                 *pf = true;
    1868                 return VINF_SUCCESS;
    1869             }
    1870             if (    !strcmp(pVar->u.pszString, "false")
    1871                 ||  !strcmp(pVar->u.pszString, "False")
    1872                 ||  !strcmp(pVar->u.pszString, "FALSE")
    1873                 ||  !strcmp(pVar->u.pszString, "off")
    1874                 ||  !strcmp(pVar->u.pszString, "Off")
    1875                 ||  !strcmp(pVar->u.pszString, "OFF")
    1876                 ||  !strcmp(pVar->u.pszString, "disabled")
    1877                 ||  !strcmp(pVar->u.pszString, "Disabled")
    1878                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    1879             {
    1880                 *pf = false;
    1881                 return VINF_SUCCESS;
    1882             }
    1883             return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
    1884 
    1885         case DBGCVAR_TYPE_GC_FLAT:
    1886         case DBGCVAR_TYPE_GC_PHYS:
    1887         case DBGCVAR_TYPE_HC_FLAT:
    1888         case DBGCVAR_TYPE_HC_PHYS:
    1889         case DBGCVAR_TYPE_NUMBER:
    1890             *pf = pVar->u.u64Number != 0;
    1891             return VINF_SUCCESS;
    1892 
    1893         case DBGCVAR_TYPE_HC_FAR:
    1894         case DBGCVAR_TYPE_GC_FAR:
    1895         case DBGCVAR_TYPE_SYMBOL:
    1896         default:
    1897             return VERR_PARSE_INCORRECT_ARG_TYPE;
    1898     }
    1899 }
    1900 
    1901 
    1902 
    1903 
    1904 
    1905 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1906 //
    1907 //
    1908 //      V a r i a b l e   M a n i p u l a t i o n
    1909 //
    1910 //
    1911 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1912 
    1913 
    1914 
    1915 /** @todo move me!*/
    1916 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
    1917 {
    1918     if (pVar)
    1919     {
    1920         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    1921         pVar->u.GCFlat = GCFlat;
    1922         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    1923         pVar->u64Range  = 0;
    1924     }
    1925 }
    1926 
    1927 
    1928 /** @todo move me!*/
    1929 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
    1930 {
    1931     if (pVar)
    1932     {
    1933         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    1934         pVar->u.GCFlat = GCFlat;
    1935         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    1936         pVar->u64Range  = cb;
    1937     }
    1938 }
    1939 
    1940 
    1941 /** @todo move me!*/
    1942 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    1943 {
    1944     if (pVar)
    1945     {
    1946         if (pVar2)
    1947             *pVar = *pVar2;
    1948         else
    1949         {
    1950             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    1951             memset(&pVar->u, 0, sizeof(pVar->u));
    1952             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    1953             pVar->u64Range  = 0;
    1954         }
    1955     }
    1956 }
    1957 
    1958 
    1959 /** @todo move me!*/
    1960 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    1961 {
    1962     if (pVar)
    1963     {
    1964         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    1965         pVar->u64Range  = cb;
    1966     }
    1967 }
    1968 
    1969 
    1970 /** @todo move me!*/
    1971 void dbgcVarSetNoRange(PDBGCVAR pVar)
    1972 {
    1973     if (pVar)
    1974     {
    1975         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    1976         pVar->u64Range  = 0;
    1977     }
    1978 }
    1979 
    1980 
    1981 /**
    1982  * Converts a DBGC variable to a DBGF address.
    1983  *
    1984  * @returns VBox status code.
    1985  * @param   pDbgc       The DBGC instance.
    1986  * @param   pVar        The variable.
    1987  * @param   pAddress    Where to store the address.
    1988  */
    1989 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    1990 {
    1991     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    1992     switch (pVar->enmType)
    1993     {
    1994         case DBGCVAR_TYPE_GC_FLAT:
    1995             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    1996             return VINF_SUCCESS;
    1997 
    1998         case DBGCVAR_TYPE_NUMBER:
    1999             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    2000             return VINF_SUCCESS;
    2001 
    2002         case DBGCVAR_TYPE_GC_FAR:
    2003             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    2004 
    2005         case DBGCVAR_TYPE_STRING:
    2006         case DBGCVAR_TYPE_SYMBOL:
    2007         {
    2008             DBGCVAR Var;
    2009             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    2010             if (VBOX_FAILURE(rc))
    2011                 return rc;
    2012             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    2013         }
    2014 
    2015         case DBGCVAR_TYPE_GC_PHYS:
    2016         case DBGCVAR_TYPE_HC_FLAT:
    2017         case DBGCVAR_TYPE_HC_FAR:
    2018         case DBGCVAR_TYPE_HC_PHYS:
    2019         default:
    2020             return VERR_PARSE_CONVERSION_FAILED;
    2021     }
    2022 }
    2023 
    2024 
    2025 
    2026 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2027 //
    2028 //
    2029 //      B r e a k p o i n t   M a n a g e m e n t
    2030 //
    2031 //
    2032 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2033 
    2034 
    2035 /**
    2036  * Adds a breakpoint to the DBGC breakpoint list.
    2037  */
    2038 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    2039 {
    2040     /*
    2041      * Check if it already exists.
    2042      */
    2043     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2044     if (pBp)
    2045         return VERR_DBGC_BP_EXISTS;
    2046 
    2047     /*
    2048      * Add the breakpoint.
    2049      */
    2050     if (pszCmd)
    2051         pszCmd = RTStrStripL(pszCmd);
    2052     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    2053     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    2054     if (!pBp)
    2055         return VERR_NO_MEMORY;
    2056     if (cchCmd)
    2057         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    2058     else
    2059         pBp->szCmd[0] = '\0';
    2060     pBp->cchCmd = cchCmd;
    2061     pBp->iBp    = iBp;
    2062     pBp->pNext  = pDbgc->pFirstBp;
    2063     pDbgc->pFirstBp = pBp;
    2064 
    2065     return VINF_SUCCESS;
    2066 }
    2067 
    2068 /**
    2069  * Updates the a breakpoint.
    2070  *
    2071  * @returns VBox status code.
    2072  * @param   pDbgc       The DBGC instance.
    2073  * @param   iBp         The breakpoint to update.
    2074  * @param   pszCmd      The new command.
    2075  */
    2076 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    2077 {
    2078     /*
    2079      * Find the breakpoint.
    2080      */
    2081     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2082     if (!pBp)
    2083         return VERR_DBGC_BP_NOT_FOUND;
    2084 
    2085     /*
    2086      * Do we need to reallocate?
    2087      */
    2088     if (pszCmd)
    2089         pszCmd = RTStrStripL(pszCmd);
    2090     if (!pszCmd || !*pszCmd)
    2091         pBp->szCmd[0] = '\0';
    2092     else
    2093     {
    2094         size_t cchCmd = strlen(pszCmd);
    2095         if (strlen(pBp->szCmd) >= cchCmd)
    2096         {
    2097             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    2098             pBp->cchCmd = cchCmd;
    2099         }
    2100         else
    2101         {
    2102             /*
    2103              * Yes, let's do it the simple way...
    2104              */
    2105             int rc = dbgcBpDelete(pDbgc, iBp);
    2106             AssertRC(rc);
    2107             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    2108         }
    2109     }
    2110     return VINF_SUCCESS;
    2111 }
    2112 
    2113 
    2114 /**
    2115  * Deletes a breakpoint.
    2116  *
    2117  * @returns VBox status code.
    2118  * @param   pDbgc       The DBGC instance.
    2119  * @param   iBp         The breakpoint to delete.
    2120  */
    2121 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    2122 {
    2123     /*
    2124      * Search thru the list, when found unlink and free it.
    2125      */
    2126     PDBGCBP pBpPrev = NULL;
    2127     PDBGCBP pBp = pDbgc->pFirstBp;
    2128     for (; pBp; pBp = pBp->pNext)
    2129     {
    2130         if (pBp->iBp == iBp)
    2131         {
    2132             if (pBpPrev)
    2133                 pBpPrev->pNext = pBp->pNext;
    2134             else
    2135                 pDbgc->pFirstBp = pBp->pNext;
    2136             RTMemFree(pBp);
    2137             return VINF_SUCCESS;
    2138         }
    2139         pBpPrev = pBp;
    2140     }
    2141 
    2142     return VERR_DBGC_BP_NOT_FOUND;
    2143 }
    2144 
    2145 
    2146 /**
    2147  * Get a breakpoint.
    2148  *
    2149  * @returns Pointer to the breakpoint.
    2150  * @returns NULL if the breakpoint wasn't found.
    2151  * @param   pDbgc       The DBGC instance.
    2152  * @param   iBp         The breakpoint to get.
    2153  */
    2154 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    2155 {
    2156     /*
    2157      * Enumerate the list.
    2158      */
    2159     PDBGCBP pBp = pDbgc->pFirstBp;
    2160     for (; pBp; pBp = pBp->pNext)
    2161         if (pBp->iBp == iBp)
    2162             return pBp;
    2163     return NULL;
    2164 }
    2165 
    2166 
    2167 /**
    2168  * Executes the command of a breakpoint.
    2169  *
    2170  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    2171  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    2172  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    2173  * @returns VBox status code from dbgcProcessCommand() other wise.
    2174  * @param   pDbgc       The DBGC instance.
    2175  * @param   iBp         The breakpoint to execute.
    2176  */
    2177 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    2178 {
    2179     /*
    2180      * Find the breakpoint.
    2181      */
    2182     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    2183     if (!pBp)
    2184         return VERR_DBGC_BP_NOT_FOUND;
    2185 
    2186     /*
    2187      * Anything to do?
    2188      */
    2189     if (!pBp->cchCmd)
    2190         return VINF_DBGC_BP_NO_COMMAND;
    2191 
    2192     /*
    2193      * Execute the command.
    2194      * This means copying it to the scratch buffer and process it as if it
    2195      * were user input. We must save and restore the state of the scratch buffer.
    2196      */
    2197     /* Save the scratch state. */
    2198     char       *pszScratch  = pDbgc->pszScratch;
    2199     unsigned    iArg        = pDbgc->iArg;
    2200 
    2201     /* Copy the command to the scratch buffer. */
    2202     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    2203     if (pBp->cchCmd >= cbScratch)
    2204         return VERR_BUFFER_OVERFLOW;
    2205     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    2206 
    2207     /* Execute the command. */
    2208     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    2209     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    2210 
    2211     /* Restore the scratch state. */
    2212     pDbgc->iArg         = iArg;
    2213     pDbgc->pszScratch   = pszScratch;
    2214 
    2215     return rc;
    2216 }
    2217 
    2218 
    2219 
    2220 
    2221 
    2222 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2223 //
    2224 //
    2225 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    2226 //
    2227 //
    2228 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    2229 
    2230 
    2231 
    2232 /**
    2233  * Prints any log lines from the log buffer.
    2234  *
    2235  * The caller must not call function this unless pDbgc->fLog is set.
    2236  *
    2237  * @returns VBox status. (output related)
    2238  * @param   pDbgc   Debugger console instance data.
    2239  */
    2240 static int dbgcProcessLog(PDBGC pDbgc)
    2241 {
    2242     /** @todo */
    2243     NOREF(pDbgc);
    2244     return 0;
    2245 }
    2246 
    2247 
    2248 
    2249 /**
    2250  * Handle input buffer overflow.
    2251  *
    2252  * Will read any available input looking for a '\n' to reset the buffer on.
    2253  *
    2254  * @returns VBox status.
    2255  * @param   pDbgc   Debugger console instance data.
    2256  */
    2257 static int dbgcInputOverflow(PDBGC pDbgc)
    2258 {
    2259     /*
    2260      * Assert overflow status and reset the input buffer.
    2261      */
    2262     if (!pDbgc->fInputOverflow)
    2263     {
    2264         pDbgc->fInputOverflow = true;
    2265         pDbgc->iRead = pDbgc->iWrite = 0;
    2266         pDbgc->cInputLines = 0;
    2267         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    2268     }
    2269 
    2270     /*
    2271      * Eat input till no more or there is a '\n'.
    2272      * When finding a '\n' we'll continue normal processing.
    2273      */
    2274     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    2275     {
    2276         size_t cbRead;
    2277         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    2278         if (VBOX_FAILURE(rc))
    2279             return rc;
    2280         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    2281         if (psz)
    2282         {
    2283             pDbgc->fInputOverflow = false;
    2284             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    2285             pDbgc->iWrite = (unsigned)cbRead;
    2286             pDbgc->cInputLines = 0;
    2287             break;
    2288         }
    2289     }
    2290 
    2291     return 0;
    2292 }
    2293 
    2294 
    2295 
    2296 /**
    2297  * Read input and do some preprocessing.
    2298  *
    2299  * @returns VBox status.
    2300  *          In addition to the iWrite and achInput, cInputLines is maintained.
    2301  *          In case of an input overflow the fInputOverflow flag will be set.
    2302  * @param   pDbgc   Debugger console instance data.
    2303  */
    2304 static int dbgcInputRead(PDBGC pDbgc)
    2305 {
    2306     /*
    2307      * We have ready input.
    2308      * Read it till we don't have any or we have a full input buffer.
    2309      */
    2310     int     rc = 0;
    2311     do
    2312     {
    2313         /*
    2314          * More available buffer space?
    2315          */
    2316         size_t cbLeft;
    2317         if (pDbgc->iWrite > pDbgc->iRead)
    2318             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    2319         else
    2320             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    2321         if (!cbLeft)
    2322         {
    2323             /* overflow? */
    2324             if (!pDbgc->cInputLines)
    2325                 rc = dbgcInputOverflow(pDbgc);
    2326             break;
    2327         }
    2328 
    2329         /*
    2330          * Read one char and interpret it.
    2331          */
    2332         char    achRead[128];
    2333         size_t  cbRead;
    2334         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    2335         if (VBOX_FAILURE(rc))
    2336             return rc;
    2337         char *psz = &achRead[0];
    2338         while (cbRead-- > 0)
    2339         {
    2340             char ch = *psz++;
    2341             switch (ch)
    2342             {
    2343                 /*
    2344                  * Ignore.
    2345                  */
    2346                 case '\0':
    2347                 case '\r':
    2348                 case '\a':
    2349                     break;
    2350 
    2351                 /*
    2352                  * Backspace.
    2353                  */
    2354                 case '\b':
    2355                     Log2(("DBGC: backspace\n"));
    2356                     if (pDbgc->iRead != pDbgc->iWrite)
    2357                     {
    2358                         unsigned iWriteUndo = pDbgc->iWrite;
    2359                         if (pDbgc->iWrite)
    2360                             pDbgc->iWrite--;
    2361                         else
    2362                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    2363 
    2364                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    2365                             pDbgc->iWrite = iWriteUndo;
    2366                     }
    2367                     break;
    2368 
    2369                 /*
    2370                  * Add char to buffer.
    2371                  */
    2372                 case '\t':
    2373                 case '\n':
    2374                 case ';':
    2375                     switch (ch)
    2376                     {
    2377                         case '\t': ch = ' '; break;
    2378                         case '\n': pDbgc->cInputLines++; break;
    2379                     }
    2380                 default:
    2381                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    2382                     pDbgc->achInput[pDbgc->iWrite] = ch;
    2383                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    2384                         pDbgc->iWrite = 0;
    2385                     break;
    2386             }
    2387         }
    2388 
    2389         /* Terminate it to make it easier to read in the debugger. */
    2390         pDbgc->achInput[pDbgc->iWrite] = '\0';
    2391     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    2392 
    2393     return rc;
    2394 }
    2395 
    2396 
    2397 
    2398 /**
    2399  * Resolves a symbol (or tries to do so at least).
    2400  *
    2401  * @returns 0 on success.
    2402  * @returns VBox status on failure.
    2403  * @param   pDbgc       The debug console instance.
    2404  * @param   pszSymbol   The symbol name.
    2405  * @param   enmType     The result type.
    2406  * @param   pResult     Where to store the result.
    2407  */
    2408 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    2409 {
    2410     /*
    2411      * Builtin?
    2412      */
    2413     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    2414     if (pSymDesc)
    2415     {
    2416         if (!pSymDesc->pfnGet)
    2417             return VERR_PARSE_WRITEONLY_SYMBOL;
    2418         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    2419     }
    2420 
    2421 
    2422     /*
    2423      * Ask PDM.
    2424      */
    2425     /** @todo resolve symbols using PDM. */
    2426 
    2427 
    2428     /*
    2429      * Ask the debug info manager.
    2430      */
    2431     DBGFSYMBOL Symbol;
    2432     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    2433     if (VBOX_SUCCESS(rc))
    2434     {
    2435         /*
    2436          * Default return is a flat gc address.
    2437          */
    2438         memset(pResult, 0,  sizeof(*pResult));
    2439         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    2440         pResult->u64Range     = Symbol.cb;
    2441         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    2442         pResult->u.GCFlat     = Symbol.Value;
    2443         DBGCVAR VarTmp;
    2444         switch (enmType)
    2445         {
    2446             /* nothing to do. */
    2447             case DBGCVAR_TYPE_GC_FLAT:
    2448             case DBGCVAR_TYPE_GC_FAR:
    2449             case DBGCVAR_TYPE_ANY:
    2450                 return VINF_SUCCESS;
    2451 
    2452             /* simply make it numeric. */
    2453             case DBGCVAR_TYPE_NUMBER:
    2454                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    2455                 pResult->u.u64Number = Symbol.Value;
    2456                 return VINF_SUCCESS;
    2457 
    2458             /* cast it. */
    2459 
    2460             case DBGCVAR_TYPE_GC_PHYS:
    2461                 VarTmp = *pResult;
    2462                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    2463 
    2464             case DBGCVAR_TYPE_HC_FAR:
    2465             case DBGCVAR_TYPE_HC_FLAT:
    2466                 VarTmp = *pResult;
    2467                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    2468 
    2469             case DBGCVAR_TYPE_HC_PHYS:
    2470                 VarTmp = *pResult;
    2471                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    2472 
    2473             default:
    2474                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    2475                 return VERR_INVALID_PARAMETER;
    2476         }
    2477     }
    2478 
    2479     return VERR_PARSE_NOT_IMPLEMENTED;
    2480 }
    2481 
    2482 
    2483 
    2484 /**
    2485  * Finds a routine.
    2486  *
    2487  * @returns Pointer to the command descriptor.
    2488  *          If the request was for an external command, the caller is responsible for
    2489  *          unlocking the external command list.
    2490  * @returns NULL if not found.
    2491  * @param   pDbgc       The debug console instance.
    2492  * @param   pachName    Pointer to the routine string (not terminated).
    2493  * @param   cchName     Length of the routine name.
    2494  * @param   fExternal   Whether or not the routine is external.
    2495  */
    2496 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
    2497 {
    2498     if (!fExternal)
    2499     {
    2500         /* emulation first, so commands can be overloaded (info ++). */
    2501         PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
    2502         unsigned cLeft = pDbgc->cEmulationCmds;
    2503         while (cLeft-- > 0)
    2504         {
    2505             if (    !strncmp(pachName, pCmd->pszCmd, cchName)
    2506                 &&  !pCmd->pszCmd[cchName])
    2507                 return pCmd;
    2508             pCmd++;
    2509         }
    2510 
    2511         for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
    2512         {
    2513             if (    !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
    2514                 &&  !g_aCmds[iCmd].pszCmd[cchName])
    2515                 return &g_aCmds[iCmd];
    2516         }
    2517     }
    2518     else
    2519     {
    2520         DBGCEXTCMDS_LOCK_RD();
    2521         for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
    2522         {
    2523             for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
    2524             {
    2525                 if (    !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
    2526                     &&  !pExtCmds->paCmds[iCmd].pszCmd[cchName])
    2527                     return &pExtCmds->paCmds[iCmd];
    2528             }
    2529         }
    2530         DBGCEXTCMDS_UNLOCK_RD();
    2531     }
    2532 
    2533     NOREF(pDbgc);
    2534     return NULL;
    2535 }
    2536 
    2537 
    2538 /**
    2539  * Initalizes g_bmOperatorChars.
    2540  */
    2541 static void dbgcInitOpCharBitMap(void)
    2542 {
    2543     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    2544     for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    2545         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    2546 }
    2547 
    2548 
    2549 /**
    2550  * Checks whether the character may be the start of an operator.
    2551  *
    2552  * @returns true/false.
    2553  * @param   ch      The character.
    2554  */
    2555 DECLINLINE(bool) dbgcIsOpChar(char ch)
    2556 {
    2557     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    2558 }
    2559 
    2560 
    2561 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    2562 {
    2563     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    2564 
    2565     /*
    2566      * Removing any quoting and escapings.
    2567      */
    2568     char ch = *pszExpr;
    2569     if (ch == '"' || ch == '\'' || ch == '`')
    2570     {
    2571         if (pszExpr[--cchExpr] != ch)
    2572             return VERR_PARSE_UNBALANCED_QUOTE;
    2573         cchExpr--;
    2574         pszExpr++;
    2575 
    2576         /** @todo string unescaping. */
    2577     }
    2578     pszExpr[cchExpr] = '\0';
    2579 
    2580     /*
    2581      * Make the argument.
    2582      */
    2583     pArg->pDesc         = NULL;
    2584     pArg->pNext         = NULL;
    2585     pArg->enmType       = DBGCVAR_TYPE_STRING;
    2586     pArg->u.pszString   = pszExpr;
    2587     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    2588     pArg->u64Range      = cchExpr;
    2589 
    2590     NOREF(pDbgc);
    2591     return 0;
    2592 }
    2593 
    2594 
    2595 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    2596 {
    2597     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    2598     /*
    2599      * Convert to number.
    2600      */
    2601     uint64_t    u64 = 0;
    2602     char        ch;
    2603     while ((ch = *pszExpr) != '\0')
    2604     {
    2605         uint64_t    u64Prev = u64;
    2606         unsigned    u = ch - '0';
    2607         if (u < 10 && u < uBase)
    2608             u64 = u64 * uBase + u;
    2609         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    2610             u64 = u64 * uBase + u;
    2611         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    2612             u64 = u64 * uBase + u;
    2613         else
    2614             return VERR_PARSE_INVALID_NUMBER;
    2615 
    2616         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    2617         if (u64Prev != u64 / uBase)
    2618             return VERR_PARSE_NUMBER_TOO_BIG;
    2619 
    2620         /* next */
    2621         pszExpr++;
    2622     }
    2623 
    2624     /*
    2625      * Initialize the argument.
    2626      */
    2627     pArg->pDesc         = NULL;
    2628     pArg->pNext         = NULL;
    2629     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    2630     pArg->u.u64Number   = u64;
    2631     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    2632     pArg->u64Range      = 0;
    2633 
    2634     return 0;
    2635 }
    2636 
    2637 
    2638 /**
    2639  * Match variable and variable descriptor, promoting the variable if necessary.
    2640  *
    2641  * @returns VBox status code.
    2642  * @param   pDbgc       Debug console instanace.
    2643  * @param   pVar        Variable.
    2644  * @param   pVarDesc    Variable descriptor.
    2645  */
    2646 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    2647 {
    2648     /*
    2649      * (If match or promoted to match, return, else break.)
    2650      */
    2651     switch (pVarDesc->enmCategory)
    2652     {
    2653         /*
    2654          * Anything goes
    2655          */
    2656         case DBGCVAR_CAT_ANY:
    2657             return VINF_SUCCESS;
    2658 
    2659         /*
    2660          * Pointer with and without range.
    2661          * We can try resolve strings and symbols as symbols and
    2662          * promote numbers to flat GC pointers.
    2663          */
    2664         case DBGCVAR_CAT_POINTER_NO_RANGE:
    2665             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    2666                 return VERR_PARSE_NO_RANGE_ALLOWED;
    2667             /* fallthru */
    2668         case DBGCVAR_CAT_POINTER:
    2669             switch (pVar->enmType)
    2670             {
    2671                 case DBGCVAR_TYPE_GC_FLAT:
    2672                 case DBGCVAR_TYPE_GC_FAR:
    2673                 case DBGCVAR_TYPE_GC_PHYS:
    2674                 case DBGCVAR_TYPE_HC_FLAT:
    2675                 case DBGCVAR_TYPE_HC_FAR:
    2676                 case DBGCVAR_TYPE_HC_PHYS:
    2677                     return VINF_SUCCESS;
    2678 
    2679                 case DBGCVAR_TYPE_SYMBOL:
    2680                 case DBGCVAR_TYPE_STRING:
    2681                 {
    2682                     DBGCVAR Var;
    2683                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    2684                     if (VBOX_SUCCESS(rc))
    2685                     {
    2686                         /* deal with range */
    2687                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    2688                         {
    2689                             Var.enmRangeType = pVar->enmRangeType;
    2690                             Var.u64Range = pVar->u64Range;
    2691                         }
    2692                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    2693                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    2694                         *pVar = Var;
    2695                         return rc;
    2696                     }
    2697                     break;
    2698                 }
    2699 
    2700                 case DBGCVAR_TYPE_NUMBER:
    2701                 {
    2702                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    2703                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    2704                     pVar->u.GCFlat = GCPtr;
    2705                     return VINF_SUCCESS;
    2706                 }
    2707 
    2708                 default:
    2709                     break;
    2710             }
    2711             break;
    2712 
    2713         /*
    2714          * GC pointer with and without range.
    2715          * We can try resolve strings and symbols as symbols and
    2716          * promote numbers to flat GC pointers.
    2717          */
    2718         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    2719             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    2720                 return VERR_PARSE_NO_RANGE_ALLOWED;
    2721             /* fallthru */
    2722         case DBGCVAR_CAT_GC_POINTER:
    2723             switch (pVar->enmType)
    2724             {
    2725                 case DBGCVAR_TYPE_GC_FLAT:
    2726                 case DBGCVAR_TYPE_GC_FAR:
    2727                 case DBGCVAR_TYPE_GC_PHYS:
    2728                     return VINF_SUCCESS;
    2729 
    2730                 case DBGCVAR_TYPE_HC_FLAT:
    2731                 case DBGCVAR_TYPE_HC_FAR:
    2732                 case DBGCVAR_TYPE_HC_PHYS:
    2733                     return VERR_PARSE_CONVERSION_FAILED;
    2734 
    2735                 case DBGCVAR_TYPE_SYMBOL:
    2736                 case DBGCVAR_TYPE_STRING:
    2737                 {
    2738                     DBGCVAR Var;
    2739                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    2740                     if (VBOX_SUCCESS(rc))
    2741                     {
    2742                         /* deal with range */
    2743                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    2744                         {
    2745                             Var.enmRangeType = pVar->enmRangeType;
    2746                             Var.u64Range = pVar->u64Range;
    2747                         }
    2748                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    2749                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    2750                         *pVar = Var;
    2751                         return rc;
    2752                     }
    2753                     break;
    2754                 }
    2755 
    2756                 case DBGCVAR_TYPE_NUMBER:
    2757                 {
    2758                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    2759                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    2760                     pVar->u.GCFlat = GCPtr;
    2761                     return VINF_SUCCESS;
    2762                 }
    2763 
    2764                 default:
    2765                     break;
    2766             }
    2767             break;
    2768 
    2769         /*
    2770          * Number with or without a range.
    2771          * Numbers can be resolved from symbols, but we cannot demote a pointer
    2772          * to a number.
    2773          */
    2774         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    2775             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    2776                 return VERR_PARSE_NO_RANGE_ALLOWED;
    2777             /* fallthru */
    2778         case DBGCVAR_CAT_NUMBER:
    2779             switch (pVar->enmType)
    2780             {
    2781                 case DBGCVAR_TYPE_NUMBER:
    2782                     return VINF_SUCCESS;
    2783 
    2784                 case DBGCVAR_TYPE_SYMBOL:
    2785                 case DBGCVAR_TYPE_STRING:
    2786                 {
    2787                     DBGCVAR Var;
    2788                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    2789                     if (VBOX_SUCCESS(rc))
    2790                     {
    2791                         *pVar = Var;
    2792                         return rc;
    2793                     }
    2794                     break;
    2795                 }
    2796                 default:
    2797                     break;
    2798             }
    2799             break;
    2800 
    2801         /*
    2802          * Strings can easily be made from symbols (and of course strings).
    2803          * We could consider reformatting the addresses and numbers into strings later...
    2804          */
    2805         case DBGCVAR_CAT_STRING:
    2806             switch (pVar->enmType)
    2807             {
    2808                 case DBGCVAR_TYPE_SYMBOL:
    2809                     pVar->enmType = DBGCVAR_TYPE_STRING;
    2810                     /* fallthru */
    2811                 case DBGCVAR_TYPE_STRING:
    2812                     return VINF_SUCCESS;
    2813                 default:
    2814                     break;
    2815             }
    2816             break;
    2817 
    2818         /*
    2819          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    2820          */
    2821         case DBGCVAR_CAT_SYMBOL:
    2822             switch (pVar->enmType)
    2823             {
    2824                 case DBGCVAR_TYPE_STRING:
    2825                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    2826                     /* fallthru */
    2827                 case DBGCVAR_TYPE_SYMBOL:
    2828                     return VINF_SUCCESS;
    2829                 default:
    2830                     break;
    2831             }
    2832             break;
    2833 
    2834         /*
    2835          * Anything else is illegal.
    2836          */
    2837         default:
    2838             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    2839             break;
    2840     }
    2841 
    2842     return VERR_PARSE_NO_ARGUMENT_MATCH;
    2843 }
    2844 
    2845 
    2846 /**
    2847  * Matches a set of variables with a description set.
    2848  *
    2849  * This is typically used for routine arguments before a call. The effects in
    2850  * addition to the validation, is that some variables might be propagated to
    2851  * other types in order to match the description. The following transformations
    2852  * are supported:
    2853  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    2854  *      - Number to a pointer.
    2855  *      - Pointer to a number.
    2856  * @returns 0 on success with paVars.
    2857  * @returns VBox error code for match errors.
    2858  */
    2859 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    2860                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    2861                                 PDBGCVAR paVars, unsigned cVars)
    2862 {
    2863     /*
    2864      * Just do basic min / max checks first.
    2865      */
    2866     if (cVars < cVarsMin)
    2867         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    2868     if (cVars > cVarsMax)
    2869         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    2870 
    2871     /*
    2872      * Match the descriptors and actual variables.
    2873      */
    2874     PCDBGCVARDESC   pPrevDesc = NULL;
    2875     unsigned        cCurDesc = 0;
    2876     unsigned        iVar = 0;
    2877     unsigned        iVarDesc = 0;
    2878     while (iVar < cVars)
    2879     {
    2880         /* walk the descriptors */
    2881         if (iVarDesc >= cVarDescs)
    2882             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    2883         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    2884                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    2885             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    2886         {
    2887             iVarDesc++;
    2888             if (iVarDesc >= cVarDescs)
    2889                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    2890             cCurDesc = 0;
    2891         }
    2892 
    2893         /*
    2894          * Skip thru optional arguments until we find something which matches
    2895          * or can easily be promoted to what the descriptor want.
    2896          */
    2897         for (;;)
    2898         {
    2899             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    2900             if (VBOX_SUCCESS(rc))
    2901             {
    2902                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    2903                 cCurDesc++;
    2904                 break;
    2905             }
    2906 
    2907             /* can we advance? */
    2908             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    2909                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    2910             if (++iVarDesc >= cVarDescs)
    2911                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    2912             cCurDesc = 0;
    2913         }
    2914 
    2915         /* next var */
    2916         iVar++;
    2917     }
    2918 
    2919     /*
    2920      * Check that the rest of the descriptors are optional.
    2921      */
    2922     while (iVarDesc < cVarDescs)
    2923     {
    2924         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    2925             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    2926         cCurDesc = 0;
    2927 
    2928         /* next */
    2929         iVarDesc++;
    2930     }
    2931 
    2932     return 0;
    2933 }
    2934 
    2935 
    2936 /**
    2937  * Evaluates one argument with respect to unary operators.
    2938  *
    2939  * @returns 0 on success. pResult contains the result.
    2940  * @returns VBox error code on parse or other evaluation error.
    2941  *
    2942  * @param   pDbgc       Debugger console instance data.
    2943  * @param   pszExpr     The expression string.
    2944  * @param   pResult     Where to store the result of the expression evaluation.
    2945  */
    2946 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    2947 {
    2948     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    2949 
    2950     /*
    2951      * The state of the expression is now such that it will start by zero or more
    2952      * unary operators and being followed by an expression of some kind.
    2953      * The expression is either plain or in parenthesis.
    2954      *
    2955      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    2956      * ASSUME: unary operators are all of equal precedence.
    2957      */
    2958     int         rc = 0;
    2959     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    2960     if (pOp)
    2961     {
    2962         /* binary operators means syntax error. */
    2963         if (pOp->fBinary)
    2964             return VERR_PARSE_UNEXPECTED_OPERATOR;
    2965 
    2966         /*
    2967          * If the next expression (the one following the unary operator) is in a
    2968          * parenthesis a full eval is needed. If not the unary eval will suffice.
    2969          */
    2970         /* calc and strip next expr. */
    2971         char *pszExpr2 = pszExpr + pOp->cchName;
    2972         while (isblank(*pszExpr2))
    2973             pszExpr2++;
    2974 
    2975         if (!*pszExpr2)
    2976             rc = VERR_PARSE_EMPTY_ARGUMENT;
    2977         else
    2978         {
    2979             DBGCVAR Arg;
    2980             if (*pszExpr2 == '(')
    2981                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    2982             else
    2983                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    2984             if (VBOX_SUCCESS(rc))
    2985                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    2986         }
    2987     }
    2988     else
    2989     {
    2990         /*
    2991          * Didn't find any operators, so it we have to check if this can be an
    2992          * function call before assuming numeric or string expression.
    2993          *
    2994          * (ASSUMPTIONS:)
    2995          * A function name only contains alphanumerical chars and it can not start
    2996          * with a numerical character.
    2997          * Immediately following the name is a parenthesis which must over
    2998          * the remaining part of the expression.
    2999          */
    3000         bool    fExternal = *pszExpr == '.';
    3001         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    3002         char   *pszFunEnd = NULL;
    3003         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    3004         {
    3005             pszFunEnd = pszExpr + 1;
    3006             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    3007                 pszFunEnd++;
    3008             if (*pszFunEnd != '(')
    3009                 pszFunEnd = NULL;
    3010         }
    3011 
    3012         if (pszFunEnd)
    3013         {
    3014             /*
    3015              * Ok, it's a function call.
    3016              */
    3017             if (fExternal)
    3018                 pszExpr++, cchExpr--;
    3019             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    3020             if (!pFun)
    3021                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    3022             if (!pFun->pResultDesc)
    3023                 return VERR_PARSE_NOT_A_FUNCTION;
    3024 
    3025             /*
    3026              * Parse the expression in parenthesis.
    3027              */
    3028             cchExpr -= pszFunEnd - pszExpr;
    3029             pszExpr = pszFunEnd;
    3030             /** @todo implement multiple arguments. */
    3031             DBGCVAR     Arg;
    3032             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    3033             if (!rc)
    3034             {
    3035                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    3036                 if (!rc)
    3037                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    3038             }
    3039             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    3040                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    3041         }
    3042         else
    3043         {
    3044             /*
    3045              * Didn't find any operators, so it must be a plain expression.
    3046              * This might be numeric or a string expression.
    3047              */
    3048             char ch  = pszExpr[0];
    3049             char ch2 = pszExpr[1];
    3050             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    3051                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    3052             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    3053                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    3054             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    3055                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    3056             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    3057             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    3058             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    3059             else
    3060             {
    3061                 /*
    3062                  * Hexadecimal number or a string?
    3063                  */
    3064                 char *psz = pszExpr;
    3065                 while (isxdigit(*psz))
    3066                     psz++;
    3067                 if (!*psz)
    3068                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    3069                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    3070                 {
    3071                     *psz = '\0';
    3072                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    3073                 }
    3074                 else
    3075                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    3076             }
    3077         }
    3078     }
    3079 
    3080     return rc;
    3081 }
    3082 
    3083 
    3084 /**
    3085  * Evaluates one argument.
    3086  *
    3087  * @returns 0 on success. pResult contains the result.
    3088  * @returns VBox error code on parse or other evaluation error.
    3089  *
    3090  * @param   pDbgc       Debugger console instance data.
    3091  * @param   pszExpr     The expression string.
    3092  * @param   pResult     Where to store the result of the expression evaluation.
    3093  */
    3094 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    3095 {
    3096     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    3097     /*
    3098      * First we need to remove blanks in both ends.
    3099      * ASSUMES: There is no quoting unless the entire expression is a string.
    3100      */
    3101 
    3102     /* stripping. */
    3103     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    3104         pszExpr[--cchExpr] = '\0';
    3105     while (isblank(*pszExpr))
    3106         pszExpr++, cchExpr--;
    3107     if (!*pszExpr)
    3108         return VERR_PARSE_EMPTY_ARGUMENT;
    3109 
    3110     /* it there is any kind of quoting in the expression, it's string meat. */
    3111     if (strpbrk(pszExpr, "\"'`"))
    3112         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    3113 
    3114     /*
    3115      * Check if there are any parenthesis which needs removing.
    3116      */
    3117     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    3118     {
    3119         do
    3120         {
    3121             unsigned cPar = 1;
    3122             char    *psz = pszExpr + 1;
    3123             char     ch;
    3124             while ((ch = *psz) != '\0')
    3125             {
    3126                 if (ch == '(')
    3127                     cPar++;
    3128                 else if (ch == ')')
    3129                 {
    3130                     if (cPar <= 0)
    3131                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3132                     cPar--;
    3133                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    3134                         break;
    3135                 }
    3136                 /* next */
    3137                 psz++;
    3138             }
    3139             if (ch)
    3140                 break;
    3141 
    3142             /* remove the parenthesis. */
    3143             pszExpr++;
    3144             cchExpr -= 2;
    3145             pszExpr[cchExpr] = '\0';
    3146 
    3147             /* strip blanks. */
    3148             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    3149                 pszExpr[--cchExpr] = '\0';
    3150             while (isblank(*pszExpr))
    3151                 pszExpr++, cchExpr--;
    3152             if (!*pszExpr)
    3153                 return VERR_PARSE_EMPTY_ARGUMENT;
    3154         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    3155     }
    3156 
    3157     /* tabs to spaces. */
    3158     char *psz = pszExpr;
    3159     while ((psz = strchr(psz, '\t')) != NULL)
    3160         *psz = ' ';
    3161 
    3162     /*
    3163      * Now, we need to look for the binary operator with the lowest precedence.
    3164      *
    3165      * If there are no operators we're left with a simple expression which we
    3166      * evaluate with respect to unary operators
    3167      */
    3168     char       *pszOpSplit = NULL;
    3169     PCDBGCOP    pOpSplit = NULL;
    3170     unsigned    cBinaryOps = 0;
    3171     unsigned    cPar = 0;
    3172     char        ch;
    3173     char        chPrev = ' ';
    3174     bool        fBinary = false;
    3175     psz = pszExpr;
    3176 
    3177     while ((ch = *psz) != '\0')
    3178     {
    3179         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    3180         /*
    3181          * Parenthesis.
    3182          */
    3183         if (ch == '(')
    3184         {
    3185             cPar++;
    3186             fBinary = false;
    3187         }
    3188         else if (ch == ')')
    3189         {
    3190             if (cPar <= 0)
    3191                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3192             cPar--;
    3193             fBinary = true;
    3194         }
    3195         /*
    3196          * Potential operator.
    3197          */
    3198         else if (cPar == 0 && !isblank(ch))
    3199         {
    3200             PCDBGCOP pOp = dbgcIsOpChar(ch)
    3201                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    3202                          : NULL;
    3203             if (pOp)
    3204             {
    3205                 /* If not the right kind of operator we've got a syntax error. */
    3206                 if (pOp->fBinary != fBinary)
    3207                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    3208 
    3209                 /*
    3210                  * Update the parse state and skip the operator.
    3211                  */
    3212                 if (!pOpSplit)
    3213                 {
    3214                     pOpSplit = pOp;
    3215                     pszOpSplit = psz;
    3216                     cBinaryOps = fBinary;
    3217                 }
    3218                 else if (fBinary)
    3219                 {
    3220                     cBinaryOps++;
    3221                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    3222                     {
    3223                         pOpSplit = pOp;
    3224                         pszOpSplit = psz;
    3225                     }
    3226                 }
    3227 
    3228                 psz += pOp->cchName - 1;
    3229                 fBinary = false;
    3230             }
    3231             else
    3232                 fBinary = true;
    3233         }
    3234 
    3235         /* next */
    3236         psz++;
    3237         chPrev = ch;
    3238     } /* parse loop. */
    3239 
    3240 
    3241     /*
    3242      * Either we found an operator to divide the expression by
    3243      * or we didn't find any. In the first case it's divide and
    3244      * conquer. In the latter it's a single expression which
    3245      * needs dealing with its unary operators if any.
    3246      */
    3247     int rc;
    3248     if (    cBinaryOps
    3249         &&  pOpSplit->fBinary)
    3250     {
    3251         /* process 1st sub expression. */
    3252         *pszOpSplit = '\0';
    3253         DBGCVAR     Arg1;
    3254         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    3255         if (VBOX_SUCCESS(rc))
    3256         {
    3257             /* process 2nd sub expression. */
    3258             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    3259             DBGCVAR     Arg2;
    3260             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    3261             if (VBOX_SUCCESS(rc))
    3262                 /* apply the operator. */
    3263                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    3264         }
    3265     }
    3266     else if (cBinaryOps)
    3267     {
    3268         /* process sub expression. */
    3269         pszOpSplit += pOpSplit->cchName;
    3270         DBGCVAR     Arg;
    3271         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    3272         if (VBOX_SUCCESS(rc))
    3273             /* apply the operator. */
    3274             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    3275     }
    3276     else
    3277         /* plain expression or using unary operators perhaps with paratheses. */
    3278         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    3279 
    3280     return rc;
    3281 }
    3282 
    3283 
    3284 /**
    3285  * Parses the arguments of one command.
    3286  *
    3287  * @returns 0 on success.
    3288  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    3289  * @param   pDbgc       Debugger console instance data.
    3290  * @param   pCmd        Pointer to the command descriptor.
    3291  * @param   pszArg      Pointer to the arguments to parse.
    3292  * @param   paArgs      Where to store the parsed arguments.
    3293  * @param   cArgs       Size of the paArgs array.
    3294  * @param   pcArgs      Where to store the number of arguments.
    3295  *                      In the event of an error this is used to store the index of the offending argument.
    3296  */
    3297 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    3298 {
    3299     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    3300     /*
    3301      * Check if we have any argument and if the command takes any.
    3302      */
    3303     *pcArgs = 0;
    3304     /* strip leading blanks. */
    3305     while (*pszArgs && isblank(*pszArgs))
    3306         pszArgs++;
    3307     if (!*pszArgs)
    3308     {
    3309         if (!pCmd->cArgsMin)
    3310             return 0;
    3311         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    3312     }
    3313     /** @todo fixme - foo() doesn't work. */
    3314     if (!pCmd->cArgsMax)
    3315         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3316 
    3317     /*
    3318      * This is a hack, it's "temporary" and should go away "when" the parser is
    3319      * modified to match arguments while parsing.
    3320      */
    3321     if (    pCmd->cArgsMax == 1
    3322         &&  pCmd->cArgsMin == 1
    3323         &&  pCmd->cArgDescs == 1
    3324         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    3325         &&  cArgs >= 1)
    3326     {
    3327         *pcArgs = 1;
    3328         RTStrStripR(pszArgs);
    3329         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    3330     }
    3331 
    3332 
    3333     /*
    3334      * The parse loop.
    3335      */
    3336     PDBGCVAR        pArg0 = &paArgs[0];
    3337     PDBGCVAR        pArg = pArg0;
    3338     *pcArgs = 0;
    3339     do
    3340     {
    3341         /*
    3342          * Can we have another argument?
    3343          */
    3344         if (*pcArgs >= pCmd->cArgsMax)
    3345             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    3346         if (pArg >= &paArgs[cArgs])
    3347             return VERR_PARSE_ARGUMENT_OVERFLOW;
    3348 
    3349         /*
    3350          * Find the end of the argument.
    3351          */
    3352         int     cPar    = 0;
    3353         char    chQuote = '\0';
    3354         char   *pszEnd  = NULL;
    3355         char   *psz     = pszArgs;
    3356         char    ch;
    3357         bool    fBinary = false;
    3358         for (;;)
    3359         {
    3360             /*
    3361              * Check for the end.
    3362              */
    3363             if ((ch = *psz) == '\0')
    3364             {
    3365                 if (chQuote)
    3366                     return VERR_PARSE_UNBALANCED_QUOTE;
    3367                 if (cPar)
    3368                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3369                 pszEnd = psz;
    3370                 break;
    3371             }
    3372             /*
    3373              * When quoted we ignore everything but the quotation char.
    3374              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    3375              */
    3376             else if (ch == '\'' || ch == '"' || ch == '`')
    3377             {
    3378                 if (chQuote)
    3379                 {
    3380                     /* end quote? */
    3381                     if (ch == chQuote)
    3382                     {
    3383                         if (psz[1] == ch)
    3384                             psz++;          /* skip the escaped quote char */
    3385                         else
    3386                             chQuote = '\0'; /* end of quoted string. */
    3387                     }
    3388                 }
    3389                 else
    3390                     chQuote = ch;           /* open new quote */
    3391             }
    3392             /*
    3393              * Parenthesis can of course be nested.
    3394              */
    3395             else if (ch == '(')
    3396             {
    3397                 cPar++;
    3398                 fBinary = false;
    3399             }
    3400             else if (ch == ')')
    3401             {
    3402                 if (!cPar)
    3403                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    3404                 cPar--;
    3405                 fBinary = true;
    3406             }
    3407             else if (!chQuote && !cPar)
    3408             {
    3409                 /*
    3410                  * Encountering blanks may mean the end of it all. A binary operator
    3411                  * will force continued parsing.
    3412                  */
    3413                 if (isblank(*psz))
    3414                 {
    3415                     pszEnd = psz++;         /* just in case. */
    3416                     while (isblank(*psz))
    3417                         psz++;
    3418                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    3419                     if (!pOp || pOp->fBinary != fBinary)
    3420                         break;              /* the end. */
    3421                     psz += pOp->cchName;
    3422                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    3423                         psz++;
    3424                     fBinary = false;
    3425                     continue;
    3426                 }
    3427 
    3428                 /*
    3429                  * Look for operators without a space up front.
    3430                  */
    3431                 if (dbgcIsOpChar(*psz))
    3432                 {
    3433                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    3434                     if (pOp)
    3435                     {
    3436                         if (pOp->fBinary != fBinary)
    3437                         {
    3438                             pszEnd = psz;
    3439                             /** @todo this is a parsing error really. */
    3440                             break;              /* the end. */
    3441                         }
    3442                         psz += pOp->cchName;
    3443                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    3444                             psz++;
    3445                         fBinary = false;
    3446                         continue;
    3447                     }
    3448                 }
    3449                 fBinary = true;
    3450             }
    3451 
    3452             /* next char */
    3453             psz++;
    3454         }
    3455         *pszEnd = '\0';
    3456         /* (psz = next char to process) */
    3457 
    3458         /*
    3459          * Parse and evaluate the argument.
    3460          */
    3461         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    3462         if (VBOX_FAILURE(rc))
    3463             return rc;
    3464 
    3465         /*
    3466          * Next.
    3467          */
    3468         pArg++;
    3469         (*pcArgs)++;
    3470         pszArgs = psz;
    3471         while (*pszArgs && isblank(*pszArgs))
    3472             pszArgs++;
    3473     } while (*pszArgs);
    3474 
    3475     /*
    3476      * Match the arguments.
    3477      */
    3478     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    3479 }
    3480 
    3481 
    3482 /**
    3483  * Process one command.
    3484  *
    3485  * @returns VBox status code. Any error indicates the termination of the console session.
    3486  * @param   pDbgc   Debugger console instance data.
    3487  * @param   pszCmd  Pointer to the command.
    3488  * @param   cchCmd  Length of the command.
    3489  */
    3490 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    3491 {
    3492     char *pszCmdInput = pszCmd;
    3493 
    3494     /*
    3495      * Skip blanks.
    3496      */
    3497     while (isblank(*pszCmd))
    3498         pszCmd++, cchCmd--;
    3499 
    3500     /* external command? */
    3501     bool fExternal = *pszCmd == '.';
    3502     if (fExternal)
    3503         pszCmd++, cchCmd--;
    3504 
    3505     /*
    3506      * Find arguments.
    3507      */
    3508     char *pszArgs = pszCmd;
    3509     while (isalnum(*pszArgs))
    3510         pszArgs++;
    3511     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    3512     {
    3513         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    3514         return 0;
    3515     }
    3516 
    3517     /*
    3518      * Find the command.
    3519      */
    3520     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    3521     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    3522         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    3523 
    3524     /*
    3525      * Parse arguments (if any).
    3526      */
    3527     unsigned    cArgs;
    3528     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    3529 
    3530     /*
    3531      * Execute the command.
    3532      */
    3533     if (!rc)
    3534     {
    3535         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    3536     }
    3537     else
    3538     {
    3539         /* report parse / eval error. */
    3540         switch (rc)
    3541         {
    3542             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    3543                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3544                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    3545                 break;
    3546             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    3547                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3548                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    3549                 break;
    3550             case VERR_PARSE_ARGUMENT_OVERFLOW:
    3551                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3552                     "Syntax error: Too many arguments.\n");
    3553                 break;
    3554             case VERR_PARSE_UNBALANCED_QUOTE:
    3555                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3556                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    3557                 break;
    3558             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    3559                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3560                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    3561                 break;
    3562             case VERR_PARSE_EMPTY_ARGUMENT:
    3563                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3564                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    3565                 break;
    3566             case VERR_PARSE_UNEXPECTED_OPERATOR:
    3567                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3568                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    3569                 break;
    3570             case VERR_PARSE_INVALID_NUMBER:
    3571                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3572                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    3573                 break;
    3574             case VERR_PARSE_NUMBER_TOO_BIG:
    3575                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3576                     "Error: Numeric overflow (argument %d).\n", cArgs);
    3577                 break;
    3578             case VERR_PARSE_INVALID_OPERATION:
    3579                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3580                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    3581                 break;
    3582             case VERR_PARSE_FUNCTION_NOT_FOUND:
    3583                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3584                     "Error: Function not found (argument %d).\n", cArgs);
    3585                 break;
    3586             case VERR_PARSE_NOT_A_FUNCTION:
    3587                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3588                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    3589                 break;
    3590             case VERR_PARSE_NO_MEMORY:
    3591                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3592                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    3593                 break;
    3594             case VERR_PARSE_INCORRECT_ARG_TYPE:
    3595                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3596                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    3597                 break;
    3598             case VERR_PARSE_VARIABLE_NOT_FOUND:
    3599                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3600                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    3601                 break;
    3602             case VERR_PARSE_CONVERSION_FAILED:
    3603                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3604                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    3605                 break;
    3606             case VERR_PARSE_NOT_IMPLEMENTED:
    3607                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3608                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    3609                 break;
    3610             case VERR_PARSE_BAD_RESULT_TYPE:
    3611                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3612                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    3613                 break;
    3614             case VERR_PARSE_WRITEONLY_SYMBOL:
    3615                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3616                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    3617                 break;
    3618 
    3619             default:
    3620                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3621                     "Error: Unknown error %d!\n", rc);
    3622                 return rc;
    3623         }
    3624 
    3625         /*
    3626          * Parse errors are non fatal.
    3627          */
    3628         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    3629             rc = 0;
    3630     }
    3631 
    3632     return rc;
    3633 }
    3634 
    3635 
    3636 /**
    3637  * Process all commands current in the buffer.
    3638  *
    3639  * @returns VBox status code. Any error indicates the termination of the console session.
    3640  * @param   pDbgc   Debugger console instance data.
    3641  */
    3642 static int dbgcProcessCommands(PDBGC pDbgc)
    3643 {
    3644     int rc = 0;
    3645     while (pDbgc->cInputLines)
    3646     {
    3647         /*
    3648          * Empty the log buffer if we're hooking the log.
    3649          */
    3650         if (pDbgc->fLog)
    3651         {
    3652             rc = dbgcProcessLog(pDbgc);
    3653             if (VBOX_FAILURE(rc))
    3654                 break;
    3655         }
    3656 
    3657         if (pDbgc->iRead == pDbgc->iWrite)
    3658         {
    3659             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    3660             pDbgc->cInputLines = 0;
    3661             return 0;
    3662         }
    3663 
    3664         /*
    3665          * Copy the command to the parse buffer.
    3666          */
    3667         char    ch;
    3668         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    3669         char   *pszTrg = &pDbgc->achScratch[0];
    3670         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    3671         {
    3672             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    3673                 psz = &pDbgc->achInput[0];
    3674 
    3675             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    3676             {
    3677                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    3678                 pDbgc->cInputLines = 0;
    3679                 return 0;
    3680             }
    3681 
    3682             pszTrg++;
    3683         }
    3684         *pszTrg = '\0';
    3685 
    3686         /*
    3687          * Advance the buffer.
    3688          */
    3689         pDbgc->iRead = psz - &pDbgc->achInput[0];
    3690         if (ch == '\n')
    3691             pDbgc->cInputLines--;
    3692 
    3693         /*
    3694          * Parse and execute this command.
    3695          */
    3696         pDbgc->pszScratch = psz;
    3697         pDbgc->iArg       = 0;
    3698         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    3699         if (rc)
    3700             break;
    3701     }
    3702 
    3703     return rc;
    3704 }
    3705 
    3706 
    3707 /**
    3708  * Reads input, parses it and executes commands on '\n'.
    3709  *
    3710  * @returns VBox status.
    3711  * @param   pDbgc   Debugger console instance data.
    3712  */
    3713 static int dbgcProcessInput(PDBGC pDbgc)
    3714 {
    3715     /*
    3716      * We know there's input ready, so let's read it first.
    3717      */
    3718     int rc = dbgcInputRead(pDbgc);
    3719     if (VBOX_FAILURE(rc))
    3720         return rc;
    3721 
    3722     /*
    3723      * Now execute any ready commands.
    3724      */
    3725     if (pDbgc->cInputLines)
    3726     {
    3727         /** @todo this fReady stuff is broken. */
    3728         pDbgc->fReady = false;
    3729         rc = dbgcProcessCommands(pDbgc);
    3730         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    3731             pDbgc->fReady = true;
    3732         if (    VBOX_SUCCESS(rc)
    3733             &&  pDbgc->iRead == pDbgc->iWrite
    3734             &&  pDbgc->fReady)
    3735             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    3736     }
    3737 
    3738     return rc;
    3739 }
    3740 
    3741 
    3742 /**
    3743  * Gets the event context identifier string.
    3744  * @returns Read only string.
    3745  * @param   enmCtx          The context.
    3746  */
    3747 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    3748 {
    3749     switch (enmCtx)
    3750     {
    3751         case DBGFEVENTCTX_RAW:      return "raw";
    3752         case DBGFEVENTCTX_REM:      return "rem";
    3753         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    3754         case DBGFEVENTCTX_HYPER:    return "hyper";
    3755         case DBGFEVENTCTX_OTHER:    return "other";
    3756 
    3757         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    3758         default:
    3759             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    3760             return "!Unknown Event Ctx!";
    3761     }
    3762 }
    3763 
    3764 
    3765 /**
    3766  * Processes debugger events.
    3767  *
    3768  * @returns VBox status.
    3769  * @param   pDbgc   DBGC Instance data.
    3770  * @param   pEvent  Pointer to event data.
    3771  */
    3772 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    3773 {
    3774     /*
    3775      * Flush log first.
    3776      */
    3777     if (pDbgc->fLog)
    3778     {
    3779         int rc = dbgcProcessLog(pDbgc);
    3780         if (VBOX_FAILURE(rc))
    3781             return rc;
    3782     }
    3783 
    3784     /*
    3785      * Process the event.
    3786      */
    3787     pDbgc->pszScratch = &pDbgc->achInput[0];
    3788     pDbgc->iArg       = 0;
    3789     bool fPrintPrompt = true;
    3790     int rc = VINF_SUCCESS;
    3791     switch (pEvent->enmType)
    3792     {
    3793         /*
    3794          * The first part is events we have initiated with commands.
    3795          */
    3796         case DBGFEVENT_HALT_DONE:
    3797         {
    3798             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    3799                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    3800             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    3801             if (VBOX_SUCCESS(rc))
    3802                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3803             break;
    3804         }
    3805 
    3806 
    3807         /*
    3808          * The second part is events which can occur at any time.
    3809          */
    3810         case DBGFEVENT_FATAL_ERROR:
    3811         {
    3812             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    3813                                          dbgcGetEventCtx(pEvent->enmCtx));
    3814             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    3815             if (VBOX_SUCCESS(rc))
    3816                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3817             break;
    3818         }
    3819 
    3820         case DBGFEVENT_BREAKPOINT:
    3821         case DBGFEVENT_BREAKPOINT_HYPER:
    3822         {
    3823             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    3824             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    3825 
    3826             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    3827             switch (rc)
    3828             {
    3829                 case VERR_DBGC_BP_NOT_FOUND:
    3830                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    3831                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    3832                     break;
    3833 
    3834                 case VINF_DBGC_BP_NO_COMMAND:
    3835                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    3836                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    3837                     break;
    3838 
    3839                 case VINF_BUFFER_OVERFLOW:
    3840                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    3841                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    3842                     break;
    3843 
    3844                 default:
    3845                     break;
    3846             }
    3847             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    3848                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3849             else
    3850                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    3851             break;
    3852         }
    3853 
    3854         case DBGFEVENT_STEPPED:
    3855         case DBGFEVENT_STEPPED_HYPER:
    3856         {
    3857             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    3858 
    3859             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    3860             if (VBOX_SUCCESS(rc))
    3861                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3862             break;
    3863         }
    3864 
    3865         case DBGFEVENT_ASSERTION_HYPER:
    3866         {
    3867             pDbgc->fRegCtxGuest = false;
    3868 
    3869             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3870                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    3871                                          "%s"
    3872                                          "%s"
    3873                                          "\n",
    3874                                          dbgcGetEventCtx(pEvent->enmCtx),
    3875                                          pEvent->u.Assert.pszMsg1,
    3876                                          pEvent->u.Assert.pszMsg2);
    3877             if (VBOX_SUCCESS(rc))
    3878                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3879             break;
    3880         }
    3881 
    3882         case DBGFEVENT_DEV_STOP:
    3883         {
    3884             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3885                                          "\n"
    3886                                          "dbgf event: DBGFSTOP (%s)\n"
    3887                                          "File:     %s\n"
    3888                                          "Line:     %d\n"
    3889                                          "Function: %s\n",
    3890                                          dbgcGetEventCtx(pEvent->enmCtx),
    3891                                          pEvent->u.Src.pszFile,
    3892                                          pEvent->u.Src.uLine,
    3893                                          pEvent->u.Src.pszFunction);
    3894             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    3895                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    3896                                          "Message:  %s\n",
    3897                                              pEvent->u.Src.pszMessage);
    3898             if (VBOX_SUCCESS(rc))
    3899                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    3900             break;
    3901         }
    3902 
    3903 
    3904         case DBGFEVENT_INVALID_COMMAND:
    3905         {
    3906             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    3907             fPrintPrompt = !pDbgc->fReady;
    3908             break;
    3909         }
    3910 
    3911         case DBGFEVENT_TERMINATING:
    3912         {
    3913             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    3914             rc = VERR_GENERAL_FAILURE;
    3915             break;
    3916         }
    3917 
    3918 
    3919         default:
    3920         {
    3921             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    3922             fPrintPrompt = !pDbgc->fReady;
    3923             break;
    3924         }
    3925     }
    3926 
    3927     /*
    3928      * Prompt, anyone?
    3929      */
    3930     if (fPrintPrompt && VBOX_SUCCESS(rc))
    3931     {
    3932         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    3933     }
    3934 
    3935     return rc;
    3936 }
    3937 
    3938 
    3939 
    3940 
    3941 
    3942 /**
    3943  * Make a console instance.
    3944  *
    3945  * This will not return until either an 'exit' command is issued or a error code
    3946  * indicating connection loss is encountered.
    3947  *
    3948  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    3949  * @returns The VBox status code causing the console termination.
    3950  *
    3951  * @param   pVM         VM Handle.
    3952  * @param   pBack       Pointer to the backend structure. This must contain
    3953  *                      a full set of function pointers to service the console.
    3954  * @param   fFlags      Reserved, must be zero.
    3955  * @remark  A forced termination of the console is easiest done by forcing the
    3956  *          callbacks to return fatal failures.
    3957  */
    3958 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    3959 {
    3960     /*
    3961      * Validate input.
    3962      */
    3963     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    3964     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    3965     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    3966 
    3967     /*
    3968      * Allocate and initialize instance data
    3969      */
    3970     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    3971     if (!pDbgc)
    3972         return VERR_NO_MEMORY;
    3973 
    3974     pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    3975     pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
    3976     pDbgc->CmdHlp.pfnPrintf     = dbgcHlpPrintf;
    3977     pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
    3978     pDbgc->CmdHlp.pfnVBoxError  = dbgcHlpVBoxError;
    3979     pDbgc->CmdHlp.pfnMemRead    = dbgcHlpMemRead;
    3980     pDbgc->CmdHlp.pfnMemWrite   = dbgcHlpMemWrite;
    3981     pDbgc->CmdHlp.pfnEval       = dbgcHlpEval;
    3982     pDbgc->CmdHlp.pfnExec       = dbgcHlpExec;
    3983     pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    3984     pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
    3985     pDbgc->pBack            = pBack;
    3986     pDbgc->pVM              = NULL;
    3987     pDbgc->pszEmulation     = "CodeView/WinDbg";
    3988     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    3989     pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    3990     //pDbgc->fLog             = false;
    3991     pDbgc->fRegCtxGuest     = true;
    3992     pDbgc->fRegTerse        = true;
    3993     //pDbgc->DisasmPos        = {0};
    3994     //pDbgc->SourcePos        = {0};
    3995     //pDbgc->DumpPos          = {0};
    3996     //pDbgc->cbDumpElement    = 0;
    3997     //pDbgc->cVars            = 0;
    3998     //pDbgc->paVars           = NULL;
    3999     //pDbgc->pFirstBp         = NULL;
    4000     //pDbgc->uInputZero       = 0;
    4001     //pDbgc->iRead            = 0;
    4002     //pDbgc->iWrite           = 0;
    4003     //pDbgc->cInputLines      = 0;
    4004     //pDbgc->fInputOverflow   = false;
    4005     pDbgc->fReady           = true;
    4006     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    4007     //pDbgc->iArg             = 0;
    4008     //pDbgc->rcOutput         = 0;
    4009 
    4010     dbgcInitOpCharBitMap();
    4011 
    4012     /*
    4013      * Print welcome message.
    4014      */
    4015     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4016         "Welcome to the VirtualBox Debugger!\n");
    4017     if (VBOX_FAILURE(rc))
    4018         goto l_failure;
    4019 
    4020     /*
    4021      * Attach to the VM.
    4022      */
    4023     rc = DBGFR3Attach(pVM);
    4024     if (VBOX_FAILURE(rc))
    4025     {
    4026         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    4027         goto l_failure;
    4028     }
    4029     pDbgc->pVM = pVM;
    4030 
    4031     /*
    4032      * Print commandline and auto select result.
    4033      */
    4034     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    4035         "Current VM is %08x\n" /** @todo get and print the VM name! */
    4036         "VBoxDbg> ",
    4037         pDbgc->pVM);
    4038     if (VBOX_FAILURE(rc))
    4039         goto l_failure;
    4040 
    4041     /*
    4042      * Main Debugger Loop.
    4043      *
    4044      * This loop will either block on waiting for input or on waiting on
    4045      * debug events. If we're forwarding the log we cannot wait for long
    4046      * before we must flush the log.
    4047      */
    4048     for (rc = 0;;)
    4049     {
    4050         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    4051         {
    4052             /*
    4053              * Wait for a debug event.
    4054              */
    4055             PCDBGFEVENT pEvent;
    4056             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    4057             if (VBOX_SUCCESS(rc))
    4058             {
    4059                 rc = dbgcProcessEvent(pDbgc, pEvent);
    4060                 if (VBOX_FAILURE(rc))
    4061                     break;
    4062             }
    4063             else if (rc != VERR_TIMEOUT)
    4064                 break;
    4065 
    4066             /*
    4067              * Check for input.
    4068              */
    4069             if (pBack->pfnInput(pDbgc->pBack, 0))
    4070             {
    4071                 rc = dbgcProcessInput(pDbgc);
    4072                 if (VBOX_FAILURE(rc))
    4073                     break;
    4074             }
    4075         }
    4076         else
    4077         {
    4078             /*
    4079              * Wait for input. If Logging is enabled we'll only wait very briefly.
    4080              */
    4081             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    4082             {
    4083                 rc = dbgcProcessInput(pDbgc);
    4084                 if (VBOX_FAILURE(rc))
    4085                     break;
    4086             }
    4087         }
    4088 
    4089         /*
    4090          * Forward log output.
    4091          */
    4092         if (pDbgc->fLog)
    4093         {
    4094             rc = dbgcProcessLog(pDbgc);
    4095             if (VBOX_FAILURE(rc))
    4096                 break;
    4097         }
    4098     }
    4099 
    4100 
    4101 l_failure:
    4102     /*
    4103      * Cleanup console debugger session.
    4104      */
    4105     /* Disable log hook. */
    4106     if (pDbgc->fLog)
    4107     {
    4108 
    4109     }
    4110 
    4111     /* Detach from the VM. */
    4112     if (pDbgc->pVM)
    4113         DBGFR3Detach(pDbgc->pVM);
    4114 
    4115     /* finally, free the instance memory. */
    4116     RTMemFree(pDbgc);
    4117 
    4118     return rc;
    4119 }
    4120 
    4121 
    4122 
    4123 /**
    4124  * Register one or more external commands.
    4125  *
    4126  * @returns VBox status.
    4127  * @param   paCommands      Pointer to an array of command descriptors.
    4128  *                          The commands must be unique. It's not possible
    4129  *                          to register the same commands more than once.
    4130  * @param   cCommands       Number of commands.
    4131  */
    4132 DBGDECL(int)    DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    4133 {
    4134     /*
    4135      * Lock the list.
    4136      */
    4137     DBGCEXTCMDS_LOCK_WR();
    4138     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    4139     while (pCur)
    4140     {
    4141         if (paCommands == pCur->paCmds)
    4142         {
    4143             DBGCEXTCMDS_UNLOCK_WR();
    4144             AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
    4145             return VWRN_DBGC_ALREADY_REGISTERED;
    4146         }
    4147         pCur = pCur->pNext;
    4148     }
    4149 
    4150     /*
    4151      * Allocate new chunk.
    4152      */
    4153     int rc = 0;
    4154     pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
    4155     if (pCur)
    4156     {
    4157         pCur->cCmds  = cCommands;
    4158         pCur->paCmds = paCommands;
    4159         pCur->pNext = g_pExtCmdsHead;
    4160         g_pExtCmdsHead = pCur;
    4161     }
    4162     else
    4163         rc = VERR_NO_MEMORY;
    4164     DBGCEXTCMDS_UNLOCK_WR();
    4165 
    4166     return rc;
    4167 }
    4168 
    4169 
    4170 /**
    4171  * Deregister one or more external commands previously registered by
    4172  * DBGCRegisterCommands().
    4173  *
    4174  * @returns VBox status.
    4175  * @param   paCommands      Pointer to an array of command descriptors
    4176  *                          as given to DBGCRegisterCommands().
    4177  * @param   cCommands       Number of commands.
    4178  */
    4179 DBGDECL(int)    DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
    4180 {
    4181     /*
    4182      * Lock the list.
    4183      */
    4184     DBGCEXTCMDS_LOCK_WR();
    4185     PDBGCEXTCMDS pPrev = NULL;
    4186     PDBGCEXTCMDS pCur = g_pExtCmdsHead;
    4187     while (pCur)
    4188     {
    4189         if (paCommands == pCur->paCmds)
    4190         {
    4191             if (pPrev)
    4192                 pPrev->pNext = pCur->pNext;
    4193             else
    4194                 g_pExtCmdsHead = pCur->pNext;
    4195             DBGCEXTCMDS_UNLOCK_WR();
    4196 
    4197             RTMemFree(pCur);
    4198             return VINF_SUCCESS;
    4199         }
    4200         pPrev = pCur;
    4201         pCur = pCur->pNext;
    4202     }
    4203     DBGCEXTCMDS_UNLOCK_WR();
    4204 
    4205     NOREF(cCommands);
    4206     return VERR_DBGC_COMMANDS_NOT_REGISTERED;
    4207 }
    4208 
Note: See TracChangeset for help on using the changeset viewer.

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