VirtualBox

Changeset 5677 in vbox


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

Split out command worker routines and stuffed the variable manipulation routines in with them.

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

Legend:

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

    r5676 r5677  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Command Worker Routines.
    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/*******************************************************************************
     
    12238#include <iprt/ctype.h>
    12339
    124 #include <stdlib.h>
    125 #include <stdio.h>
    126 
    12740#include "DBGCInternal.h"
    128 
    129 
    130 /*******************************************************************************
    131 *   Global Variables                                                           *
    132 *******************************************************************************/
    133 /** Bitmap where set bits indicates the characters the may start an operator name. */
    134 static uint32_t g_bmOperatorChars[256 / (4*8)];
    135 
    136 
    137 
    138 
    13941
    14042
     
    453355}
    454356
    455 
    456 
    457 
    458 
    459 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    460 //
    461 //
    462 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    463 //
    464 //
    465 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    466 
    467 
    468 
    469 /**
    470  * Prints any log lines from the log buffer.
    471  *
    472  * The caller must not call function this unless pDbgc->fLog is set.
    473  *
    474  * @returns VBox status. (output related)
    475  * @param   pDbgc   Debugger console instance data.
    476  */
    477 static int dbgcProcessLog(PDBGC pDbgc)
    478 {
    479     /** @todo */
    480     NOREF(pDbgc);
    481     return 0;
    482 }
    483 
    484 
    485 
    486 /**
    487  * Handle input buffer overflow.
    488  *
    489  * Will read any available input looking for a '\n' to reset the buffer on.
    490  *
    491  * @returns VBox status.
    492  * @param   pDbgc   Debugger console instance data.
    493  */
    494 static int dbgcInputOverflow(PDBGC pDbgc)
    495 {
    496     /*
    497      * Assert overflow status and reset the input buffer.
    498      */
    499     if (!pDbgc->fInputOverflow)
    500     {
    501         pDbgc->fInputOverflow = true;
    502         pDbgc->iRead = pDbgc->iWrite = 0;
    503         pDbgc->cInputLines = 0;
    504         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    505     }
    506 
    507     /*
    508      * Eat input till no more or there is a '\n'.
    509      * When finding a '\n' we'll continue normal processing.
    510      */
    511     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    512     {
    513         size_t cbRead;
    514         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    515         if (VBOX_FAILURE(rc))
    516             return rc;
    517         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    518         if (psz)
    519         {
    520             pDbgc->fInputOverflow = false;
    521             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    522             pDbgc->iWrite = (unsigned)cbRead;
    523             pDbgc->cInputLines = 0;
    524             break;
    525         }
    526     }
    527 
    528     return 0;
    529 }
    530 
    531 
    532 
    533 /**
    534  * Read input and do some preprocessing.
    535  *
    536  * @returns VBox status.
    537  *          In addition to the iWrite and achInput, cInputLines is maintained.
    538  *          In case of an input overflow the fInputOverflow flag will be set.
    539  * @param   pDbgc   Debugger console instance data.
    540  */
    541 static int dbgcInputRead(PDBGC pDbgc)
    542 {
    543     /*
    544      * We have ready input.
    545      * Read it till we don't have any or we have a full input buffer.
    546      */
    547     int     rc = 0;
    548     do
    549     {
    550         /*
    551          * More available buffer space?
    552          */
    553         size_t cbLeft;
    554         if (pDbgc->iWrite > pDbgc->iRead)
    555             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    556         else
    557             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    558         if (!cbLeft)
    559         {
    560             /* overflow? */
    561             if (!pDbgc->cInputLines)
    562                 rc = dbgcInputOverflow(pDbgc);
    563             break;
    564         }
    565 
    566         /*
    567          * Read one char and interpret it.
    568          */
    569         char    achRead[128];
    570         size_t  cbRead;
    571         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    572         if (VBOX_FAILURE(rc))
    573             return rc;
    574         char *psz = &achRead[0];
    575         while (cbRead-- > 0)
    576         {
    577             char ch = *psz++;
    578             switch (ch)
    579             {
    580                 /*
    581                  * Ignore.
    582                  */
    583                 case '\0':
    584                 case '\r':
    585                 case '\a':
    586                     break;
    587 
    588                 /*
    589                  * Backspace.
    590                  */
    591                 case '\b':
    592                     Log2(("DBGC: backspace\n"));
    593                     if (pDbgc->iRead != pDbgc->iWrite)
    594                     {
    595                         unsigned iWriteUndo = pDbgc->iWrite;
    596                         if (pDbgc->iWrite)
    597                             pDbgc->iWrite--;
    598                         else
    599                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    600 
    601                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    602                             pDbgc->iWrite = iWriteUndo;
    603                     }
    604                     break;
    605 
    606                 /*
    607                  * Add char to buffer.
    608                  */
    609                 case '\t':
    610                 case '\n':
    611                 case ';':
    612                     switch (ch)
    613                     {
    614                         case '\t': ch = ' '; break;
    615                         case '\n': pDbgc->cInputLines++; break;
    616                     }
    617                 default:
    618                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    619                     pDbgc->achInput[pDbgc->iWrite] = ch;
    620                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    621                         pDbgc->iWrite = 0;
    622                     break;
    623             }
    624         }
    625 
    626         /* Terminate it to make it easier to read in the debugger. */
    627         pDbgc->achInput[pDbgc->iWrite] = '\0';
    628     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    629 
    630     return rc;
    631 }
    632 
    633 
    634 
    635 /**
    636  * Resolves a symbol (or tries to do so at least).
    637  *
    638  * @returns 0 on success.
    639  * @returns VBox status on failure.
    640  * @param   pDbgc       The debug console instance.
    641  * @param   pszSymbol   The symbol name.
    642  * @param   enmType     The result type.
    643  * @param   pResult     Where to store the result.
    644  */
    645 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    646 {
    647     /*
    648      * Builtin?
    649      */
    650     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    651     if (pSymDesc)
    652     {
    653         if (!pSymDesc->pfnGet)
    654             return VERR_PARSE_WRITEONLY_SYMBOL;
    655         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    656     }
    657 
    658 
    659     /*
    660      * Ask PDM.
    661      */
    662     /** @todo resolve symbols using PDM. */
    663 
    664 
    665     /*
    666      * Ask the debug info manager.
    667      */
    668     DBGFSYMBOL Symbol;
    669     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    670     if (VBOX_SUCCESS(rc))
    671     {
    672         /*
    673          * Default return is a flat gc address.
    674          */
    675         memset(pResult, 0,  sizeof(*pResult));
    676         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    677         pResult->u64Range     = Symbol.cb;
    678         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    679         pResult->u.GCFlat     = Symbol.Value;
    680         DBGCVAR VarTmp;
    681         switch (enmType)
    682         {
    683             /* nothing to do. */
    684             case DBGCVAR_TYPE_GC_FLAT:
    685             case DBGCVAR_TYPE_GC_FAR:
    686             case DBGCVAR_TYPE_ANY:
    687                 return VINF_SUCCESS;
    688 
    689             /* simply make it numeric. */
    690             case DBGCVAR_TYPE_NUMBER:
    691                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    692                 pResult->u.u64Number = Symbol.Value;
    693                 return VINF_SUCCESS;
    694 
    695             /* cast it. */
    696 
    697             case DBGCVAR_TYPE_GC_PHYS:
    698                 VarTmp = *pResult;
    699                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    700 
    701             case DBGCVAR_TYPE_HC_FAR:
    702             case DBGCVAR_TYPE_HC_FLAT:
    703                 VarTmp = *pResult;
    704                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    705 
    706             case DBGCVAR_TYPE_HC_PHYS:
    707                 VarTmp = *pResult;
    708                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    709 
    710             default:
    711                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    712                 return VERR_INVALID_PARAMETER;
    713         }
    714     }
    715 
    716     return VERR_PARSE_NOT_IMPLEMENTED;
    717 }
    718 
    719 
    720 /**
    721  * Initalizes g_bmOperatorChars.
    722  */
    723 static void dbgcInitOpCharBitMap(void)
    724 {
    725     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    726     for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    727         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    728 }
    729 
    730 
    731 /**
    732  * Checks whether the character may be the start of an operator.
    733  *
    734  * @returns true/false.
    735  * @param   ch      The character.
    736  */
    737 DECLINLINE(bool) dbgcIsOpChar(char ch)
    738 {
    739     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    740 }
    741 
    742 
    743 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    744 {
    745     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    746 
    747     /*
    748      * Removing any quoting and escapings.
    749      */
    750     char ch = *pszExpr;
    751     if (ch == '"' || ch == '\'' || ch == '`')
    752     {
    753         if (pszExpr[--cchExpr] != ch)
    754             return VERR_PARSE_UNBALANCED_QUOTE;
    755         cchExpr--;
    756         pszExpr++;
    757 
    758         /** @todo string unescaping. */
    759     }
    760     pszExpr[cchExpr] = '\0';
    761 
    762     /*
    763      * Make the argument.
    764      */
    765     pArg->pDesc         = NULL;
    766     pArg->pNext         = NULL;
    767     pArg->enmType       = DBGCVAR_TYPE_STRING;
    768     pArg->u.pszString   = pszExpr;
    769     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    770     pArg->u64Range      = cchExpr;
    771 
    772     NOREF(pDbgc);
    773     return 0;
    774 }
    775 
    776 
    777 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    778 {
    779     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    780     /*
    781      * Convert to number.
    782      */
    783     uint64_t    u64 = 0;
    784     char        ch;
    785     while ((ch = *pszExpr) != '\0')
    786     {
    787         uint64_t    u64Prev = u64;
    788         unsigned    u = ch - '0';
    789         if (u < 10 && u < uBase)
    790             u64 = u64 * uBase + u;
    791         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    792             u64 = u64 * uBase + u;
    793         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    794             u64 = u64 * uBase + u;
    795         else
    796             return VERR_PARSE_INVALID_NUMBER;
    797 
    798         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    799         if (u64Prev != u64 / uBase)
    800             return VERR_PARSE_NUMBER_TOO_BIG;
    801 
    802         /* next */
    803         pszExpr++;
    804     }
    805 
    806     /*
    807      * Initialize the argument.
    808      */
    809     pArg->pDesc         = NULL;
    810     pArg->pNext         = NULL;
    811     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    812     pArg->u.u64Number   = u64;
    813     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    814     pArg->u64Range      = 0;
    815 
    816     return 0;
    817 }
    818 
    819 
    820 /**
    821  * Match variable and variable descriptor, promoting the variable if necessary.
    822  *
    823  * @returns VBox status code.
    824  * @param   pDbgc       Debug console instanace.
    825  * @param   pVar        Variable.
    826  * @param   pVarDesc    Variable descriptor.
    827  */
    828 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    829 {
    830     /*
    831      * (If match or promoted to match, return, else break.)
    832      */
    833     switch (pVarDesc->enmCategory)
    834     {
    835         /*
    836          * Anything goes
    837          */
    838         case DBGCVAR_CAT_ANY:
    839             return VINF_SUCCESS;
    840 
    841         /*
    842          * Pointer with and without range.
    843          * We can try resolve strings and symbols as symbols and
    844          * promote numbers to flat GC pointers.
    845          */
    846         case DBGCVAR_CAT_POINTER_NO_RANGE:
    847             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    848                 return VERR_PARSE_NO_RANGE_ALLOWED;
    849             /* fallthru */
    850         case DBGCVAR_CAT_POINTER:
    851             switch (pVar->enmType)
    852             {
    853                 case DBGCVAR_TYPE_GC_FLAT:
    854                 case DBGCVAR_TYPE_GC_FAR:
    855                 case DBGCVAR_TYPE_GC_PHYS:
    856                 case DBGCVAR_TYPE_HC_FLAT:
    857                 case DBGCVAR_TYPE_HC_FAR:
    858                 case DBGCVAR_TYPE_HC_PHYS:
    859                     return VINF_SUCCESS;
    860 
    861                 case DBGCVAR_TYPE_SYMBOL:
    862                 case DBGCVAR_TYPE_STRING:
    863                 {
    864                     DBGCVAR Var;
    865                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    866                     if (VBOX_SUCCESS(rc))
    867                     {
    868                         /* deal with range */
    869                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    870                         {
    871                             Var.enmRangeType = pVar->enmRangeType;
    872                             Var.u64Range = pVar->u64Range;
    873                         }
    874                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    875                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    876                         *pVar = Var;
    877                         return rc;
    878                     }
    879                     break;
    880                 }
    881 
    882                 case DBGCVAR_TYPE_NUMBER:
    883                 {
    884                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    885                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    886                     pVar->u.GCFlat = GCPtr;
    887                     return VINF_SUCCESS;
    888                 }
    889 
    890                 default:
    891                     break;
    892             }
    893             break;
    894 
    895         /*
    896          * GC pointer with and without range.
    897          * We can try resolve strings and symbols as symbols and
    898          * promote numbers to flat GC pointers.
    899          */
    900         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    901             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    902                 return VERR_PARSE_NO_RANGE_ALLOWED;
    903             /* fallthru */
    904         case DBGCVAR_CAT_GC_POINTER:
    905             switch (pVar->enmType)
    906             {
    907                 case DBGCVAR_TYPE_GC_FLAT:
    908                 case DBGCVAR_TYPE_GC_FAR:
    909                 case DBGCVAR_TYPE_GC_PHYS:
    910                     return VINF_SUCCESS;
    911 
    912                 case DBGCVAR_TYPE_HC_FLAT:
    913                 case DBGCVAR_TYPE_HC_FAR:
    914                 case DBGCVAR_TYPE_HC_PHYS:
    915                     return VERR_PARSE_CONVERSION_FAILED;
    916 
    917                 case DBGCVAR_TYPE_SYMBOL:
    918                 case DBGCVAR_TYPE_STRING:
    919                 {
    920                     DBGCVAR Var;
    921                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    922                     if (VBOX_SUCCESS(rc))
    923                     {
    924                         /* deal with range */
    925                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    926                         {
    927                             Var.enmRangeType = pVar->enmRangeType;
    928                             Var.u64Range = pVar->u64Range;
    929                         }
    930                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    931                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    932                         *pVar = Var;
    933                         return rc;
    934                     }
    935                     break;
    936                 }
    937 
    938                 case DBGCVAR_TYPE_NUMBER:
    939                 {
    940                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    941                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    942                     pVar->u.GCFlat = GCPtr;
    943                     return VINF_SUCCESS;
    944                 }
    945 
    946                 default:
    947                     break;
    948             }
    949             break;
    950 
    951         /*
    952          * Number with or without a range.
    953          * Numbers can be resolved from symbols, but we cannot demote a pointer
    954          * to a number.
    955          */
    956         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    957             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    958                 return VERR_PARSE_NO_RANGE_ALLOWED;
    959             /* fallthru */
    960         case DBGCVAR_CAT_NUMBER:
    961             switch (pVar->enmType)
    962             {
    963                 case DBGCVAR_TYPE_NUMBER:
    964                     return VINF_SUCCESS;
    965 
    966                 case DBGCVAR_TYPE_SYMBOL:
    967                 case DBGCVAR_TYPE_STRING:
    968                 {
    969                     DBGCVAR Var;
    970                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    971                     if (VBOX_SUCCESS(rc))
    972                     {
    973                         *pVar = Var;
    974                         return rc;
    975                     }
    976                     break;
    977                 }
    978                 default:
    979                     break;
    980             }
    981             break;
    982 
    983         /*
    984          * Strings can easily be made from symbols (and of course strings).
    985          * We could consider reformatting the addresses and numbers into strings later...
    986          */
    987         case DBGCVAR_CAT_STRING:
    988             switch (pVar->enmType)
    989             {
    990                 case DBGCVAR_TYPE_SYMBOL:
    991                     pVar->enmType = DBGCVAR_TYPE_STRING;
    992                     /* fallthru */
    993                 case DBGCVAR_TYPE_STRING:
    994                     return VINF_SUCCESS;
    995                 default:
    996                     break;
    997             }
    998             break;
    999 
    1000         /*
    1001          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    1002          */
    1003         case DBGCVAR_CAT_SYMBOL:
    1004             switch (pVar->enmType)
    1005             {
    1006                 case DBGCVAR_TYPE_STRING:
    1007                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    1008                     /* fallthru */
    1009                 case DBGCVAR_TYPE_SYMBOL:
    1010                     return VINF_SUCCESS;
    1011                 default:
    1012                     break;
    1013             }
    1014             break;
    1015 
    1016         /*
    1017          * Anything else is illegal.
    1018          */
    1019         default:
    1020             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    1021             break;
    1022     }
    1023 
    1024     return VERR_PARSE_NO_ARGUMENT_MATCH;
    1025 }
    1026 
    1027 
    1028 /**
    1029  * Matches a set of variables with a description set.
    1030  *
    1031  * This is typically used for routine arguments before a call. The effects in
    1032  * addition to the validation, is that some variables might be propagated to
    1033  * other types in order to match the description. The following transformations
    1034  * are supported:
    1035  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    1036  *      - Number to a pointer.
    1037  *      - Pointer to a number.
    1038  * @returns 0 on success with paVars.
    1039  * @returns VBox error code for match errors.
    1040  */
    1041 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    1042                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    1043                                 PDBGCVAR paVars, unsigned cVars)
    1044 {
    1045     /*
    1046      * Just do basic min / max checks first.
    1047      */
    1048     if (cVars < cVarsMin)
    1049         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    1050     if (cVars > cVarsMax)
    1051         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1052 
    1053     /*
    1054      * Match the descriptors and actual variables.
    1055      */
    1056     PCDBGCVARDESC   pPrevDesc = NULL;
    1057     unsigned        cCurDesc = 0;
    1058     unsigned        iVar = 0;
    1059     unsigned        iVarDesc = 0;
    1060     while (iVar < cVars)
    1061     {
    1062         /* walk the descriptors */
    1063         if (iVarDesc >= cVarDescs)
    1064             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1065         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    1066                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    1067             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    1068         {
    1069             iVarDesc++;
    1070             if (iVarDesc >= cVarDescs)
    1071                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1072             cCurDesc = 0;
    1073         }
    1074 
    1075         /*
    1076          * Skip thru optional arguments until we find something which matches
    1077          * or can easily be promoted to what the descriptor want.
    1078          */
    1079         for (;;)
    1080         {
    1081             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    1082             if (VBOX_SUCCESS(rc))
    1083             {
    1084                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    1085                 cCurDesc++;
    1086                 break;
    1087             }
    1088 
    1089             /* can we advance? */
    1090             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    1091                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1092             if (++iVarDesc >= cVarDescs)
    1093                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1094             cCurDesc = 0;
    1095         }
    1096 
    1097         /* next var */
    1098         iVar++;
    1099     }
    1100 
    1101     /*
    1102      * Check that the rest of the descriptors are optional.
    1103      */
    1104     while (iVarDesc < cVarDescs)
    1105     {
    1106         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    1107             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    1108         cCurDesc = 0;
    1109 
    1110         /* next */
    1111         iVarDesc++;
    1112     }
    1113 
    1114     return 0;
    1115 }
    1116 
    1117 
    1118 /**
    1119  * Evaluates one argument with respect to unary operators.
    1120  *
    1121  * @returns 0 on success. pResult contains the result.
    1122  * @returns VBox error code on parse or other evaluation error.
    1123  *
    1124  * @param   pDbgc       Debugger console instance data.
    1125  * @param   pszExpr     The expression string.
    1126  * @param   pResult     Where to store the result of the expression evaluation.
    1127  */
    1128 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    1129 {
    1130     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    1131 
    1132     /*
    1133      * The state of the expression is now such that it will start by zero or more
    1134      * unary operators and being followed by an expression of some kind.
    1135      * The expression is either plain or in parenthesis.
    1136      *
    1137      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    1138      * ASSUME: unary operators are all of equal precedence.
    1139      */
    1140     int         rc = 0;
    1141     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    1142     if (pOp)
    1143     {
    1144         /* binary operators means syntax error. */
    1145         if (pOp->fBinary)
    1146             return VERR_PARSE_UNEXPECTED_OPERATOR;
    1147 
    1148         /*
    1149          * If the next expression (the one following the unary operator) is in a
    1150          * parenthesis a full eval is needed. If not the unary eval will suffice.
    1151          */
    1152         /* calc and strip next expr. */
    1153         char *pszExpr2 = pszExpr + pOp->cchName;
    1154         while (isblank(*pszExpr2))
    1155             pszExpr2++;
    1156 
    1157         if (!*pszExpr2)
    1158             rc = VERR_PARSE_EMPTY_ARGUMENT;
    1159         else
    1160         {
    1161             DBGCVAR Arg;
    1162             if (*pszExpr2 == '(')
    1163                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    1164             else
    1165                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    1166             if (VBOX_SUCCESS(rc))
    1167                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    1168         }
    1169     }
    1170     else
    1171     {
    1172         /*
    1173          * Didn't find any operators, so it we have to check if this can be an
    1174          * function call before assuming numeric or string expression.
    1175          *
    1176          * (ASSUMPTIONS:)
    1177          * A function name only contains alphanumerical chars and it can not start
    1178          * with a numerical character.
    1179          * Immediately following the name is a parenthesis which must over
    1180          * the remaining part of the expression.
    1181          */
    1182         bool    fExternal = *pszExpr == '.';
    1183         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    1184         char   *pszFunEnd = NULL;
    1185         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    1186         {
    1187             pszFunEnd = pszExpr + 1;
    1188             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    1189                 pszFunEnd++;
    1190             if (*pszFunEnd != '(')
    1191                 pszFunEnd = NULL;
    1192         }
    1193 
    1194         if (pszFunEnd)
    1195         {
    1196             /*
    1197              * Ok, it's a function call.
    1198              */
    1199             if (fExternal)
    1200                 pszExpr++, cchExpr--;
    1201             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    1202             if (!pFun)
    1203                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    1204             if (!pFun->pResultDesc)
    1205                 return VERR_PARSE_NOT_A_FUNCTION;
    1206 
    1207             /*
    1208              * Parse the expression in parenthesis.
    1209              */
    1210             cchExpr -= pszFunEnd - pszExpr;
    1211             pszExpr = pszFunEnd;
    1212             /** @todo implement multiple arguments. */
    1213             DBGCVAR     Arg;
    1214             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    1215             if (!rc)
    1216             {
    1217                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    1218                 if (!rc)
    1219                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    1220             }
    1221             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    1222                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    1223         }
    1224         else
    1225         {
    1226             /*
    1227              * Didn't find any operators, so it must be a plain expression.
    1228              * This might be numeric or a string expression.
    1229              */
    1230             char ch  = pszExpr[0];
    1231             char ch2 = pszExpr[1];
    1232             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    1233                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    1234             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    1235                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    1236             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    1237                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    1238             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    1239             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    1240             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    1241             else
    1242             {
    1243                 /*
    1244                  * Hexadecimal number or a string?
    1245                  */
    1246                 char *psz = pszExpr;
    1247                 while (isxdigit(*psz))
    1248                     psz++;
    1249                 if (!*psz)
    1250                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    1251                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    1252                 {
    1253                     *psz = '\0';
    1254                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    1255                 }
    1256                 else
    1257                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    1258             }
    1259         }
    1260     }
    1261 
    1262     return rc;
    1263 }
    1264 
    1265 
    1266 /**
    1267  * Evaluates one argument.
    1268  *
    1269  * @returns 0 on success. pResult contains the result.
    1270  * @returns VBox error code on parse or other evaluation error.
    1271  *
    1272  * @param   pDbgc       Debugger console instance data.
    1273  * @param   pszExpr     The expression string.
    1274  * @param   pResult     Where to store the result of the expression evaluation.
    1275  */
    1276 int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    1277 {
    1278     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    1279     /*
    1280      * First we need to remove blanks in both ends.
    1281      * ASSUMES: There is no quoting unless the entire expression is a string.
    1282      */
    1283 
    1284     /* stripping. */
    1285     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    1286         pszExpr[--cchExpr] = '\0';
    1287     while (isblank(*pszExpr))
    1288         pszExpr++, cchExpr--;
    1289     if (!*pszExpr)
    1290         return VERR_PARSE_EMPTY_ARGUMENT;
    1291 
    1292     /* it there is any kind of quoting in the expression, it's string meat. */
    1293     if (strpbrk(pszExpr, "\"'`"))
    1294         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    1295 
    1296     /*
    1297      * Check if there are any parenthesis which needs removing.
    1298      */
    1299     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    1300     {
    1301         do
    1302         {
    1303             unsigned cPar = 1;
    1304             char    *psz = pszExpr + 1;
    1305             char     ch;
    1306             while ((ch = *psz) != '\0')
    1307             {
    1308                 if (ch == '(')
    1309                     cPar++;
    1310                 else if (ch == ')')
    1311                 {
    1312                     if (cPar <= 0)
    1313                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1314                     cPar--;
    1315                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    1316                         break;
    1317                 }
    1318                 /* next */
    1319                 psz++;
    1320             }
    1321             if (ch)
    1322                 break;
    1323 
    1324             /* remove the parenthesis. */
    1325             pszExpr++;
    1326             cchExpr -= 2;
    1327             pszExpr[cchExpr] = '\0';
    1328 
    1329             /* strip blanks. */
    1330             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    1331                 pszExpr[--cchExpr] = '\0';
    1332             while (isblank(*pszExpr))
    1333                 pszExpr++, cchExpr--;
    1334             if (!*pszExpr)
    1335                 return VERR_PARSE_EMPTY_ARGUMENT;
    1336         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    1337     }
    1338 
    1339     /* tabs to spaces. */
    1340     char *psz = pszExpr;
    1341     while ((psz = strchr(psz, '\t')) != NULL)
    1342         *psz = ' ';
    1343 
    1344     /*
    1345      * Now, we need to look for the binary operator with the lowest precedence.
    1346      *
    1347      * If there are no operators we're left with a simple expression which we
    1348      * evaluate with respect to unary operators
    1349      */
    1350     char       *pszOpSplit = NULL;
    1351     PCDBGCOP    pOpSplit = NULL;
    1352     unsigned    cBinaryOps = 0;
    1353     unsigned    cPar = 0;
    1354     char        ch;
    1355     char        chPrev = ' ';
    1356     bool        fBinary = false;
    1357     psz = pszExpr;
    1358 
    1359     while ((ch = *psz) != '\0')
    1360     {
    1361         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    1362         /*
    1363          * Parenthesis.
    1364          */
    1365         if (ch == '(')
    1366         {
    1367             cPar++;
    1368             fBinary = false;
    1369         }
    1370         else if (ch == ')')
    1371         {
    1372             if (cPar <= 0)
    1373                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1374             cPar--;
    1375             fBinary = true;
    1376         }
    1377         /*
    1378          * Potential operator.
    1379          */
    1380         else if (cPar == 0 && !isblank(ch))
    1381         {
    1382             PCDBGCOP pOp = dbgcIsOpChar(ch)
    1383                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    1384                          : NULL;
    1385             if (pOp)
    1386             {
    1387                 /* If not the right kind of operator we've got a syntax error. */
    1388                 if (pOp->fBinary != fBinary)
    1389                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    1390 
    1391                 /*
    1392                  * Update the parse state and skip the operator.
    1393                  */
    1394                 if (!pOpSplit)
    1395                 {
    1396                     pOpSplit = pOp;
    1397                     pszOpSplit = psz;
    1398                     cBinaryOps = fBinary;
    1399                 }
    1400                 else if (fBinary)
    1401                 {
    1402                     cBinaryOps++;
    1403                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    1404                     {
    1405                         pOpSplit = pOp;
    1406                         pszOpSplit = psz;
    1407                     }
    1408                 }
    1409 
    1410                 psz += pOp->cchName - 1;
    1411                 fBinary = false;
    1412             }
    1413             else
    1414                 fBinary = true;
    1415         }
    1416 
    1417         /* next */
    1418         psz++;
    1419         chPrev = ch;
    1420     } /* parse loop. */
    1421 
    1422 
    1423     /*
    1424      * Either we found an operator to divide the expression by
    1425      * or we didn't find any. In the first case it's divide and
    1426      * conquer. In the latter it's a single expression which
    1427      * needs dealing with its unary operators if any.
    1428      */
    1429     int rc;
    1430     if (    cBinaryOps
    1431         &&  pOpSplit->fBinary)
    1432     {
    1433         /* process 1st sub expression. */
    1434         *pszOpSplit = '\0';
    1435         DBGCVAR     Arg1;
    1436         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    1437         if (VBOX_SUCCESS(rc))
    1438         {
    1439             /* process 2nd sub expression. */
    1440             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    1441             DBGCVAR     Arg2;
    1442             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    1443             if (VBOX_SUCCESS(rc))
    1444                 /* apply the operator. */
    1445                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    1446         }
    1447     }
    1448     else if (cBinaryOps)
    1449     {
    1450         /* process sub expression. */
    1451         pszOpSplit += pOpSplit->cchName;
    1452         DBGCVAR     Arg;
    1453         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    1454         if (VBOX_SUCCESS(rc))
    1455             /* apply the operator. */
    1456             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    1457     }
    1458     else
    1459         /* plain expression or using unary operators perhaps with paratheses. */
    1460         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    1461 
    1462     return rc;
    1463 }
    1464 
    1465 
    1466 /**
    1467  * Parses the arguments of one command.
    1468  *
    1469  * @returns 0 on success.
    1470  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    1471  * @param   pDbgc       Debugger console instance data.
    1472  * @param   pCmd        Pointer to the command descriptor.
    1473  * @param   pszArg      Pointer to the arguments to parse.
    1474  * @param   paArgs      Where to store the parsed arguments.
    1475  * @param   cArgs       Size of the paArgs array.
    1476  * @param   pcArgs      Where to store the number of arguments.
    1477  *                      In the event of an error this is used to store the index of the offending argument.
    1478  */
    1479 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    1480 {
    1481     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    1482     /*
    1483      * Check if we have any argument and if the command takes any.
    1484      */
    1485     *pcArgs = 0;
    1486     /* strip leading blanks. */
    1487     while (*pszArgs && isblank(*pszArgs))
    1488         pszArgs++;
    1489     if (!*pszArgs)
    1490     {
    1491         if (!pCmd->cArgsMin)
    1492             return 0;
    1493         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    1494     }
    1495     /** @todo fixme - foo() doesn't work. */
    1496     if (!pCmd->cArgsMax)
    1497         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1498 
    1499     /*
    1500      * This is a hack, it's "temporary" and should go away "when" the parser is
    1501      * modified to match arguments while parsing.
    1502      */
    1503     if (    pCmd->cArgsMax == 1
    1504         &&  pCmd->cArgsMin == 1
    1505         &&  pCmd->cArgDescs == 1
    1506         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    1507         &&  cArgs >= 1)
    1508     {
    1509         *pcArgs = 1;
    1510         RTStrStripR(pszArgs);
    1511         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    1512     }
    1513 
    1514 
    1515     /*
    1516      * The parse loop.
    1517      */
    1518     PDBGCVAR        pArg0 = &paArgs[0];
    1519     PDBGCVAR        pArg = pArg0;
    1520     *pcArgs = 0;
    1521     do
    1522     {
    1523         /*
    1524          * Can we have another argument?
    1525          */
    1526         if (*pcArgs >= pCmd->cArgsMax)
    1527             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1528         if (pArg >= &paArgs[cArgs])
    1529             return VERR_PARSE_ARGUMENT_OVERFLOW;
    1530 
    1531         /*
    1532          * Find the end of the argument.
    1533          */
    1534         int     cPar    = 0;
    1535         char    chQuote = '\0';
    1536         char   *pszEnd  = NULL;
    1537         char   *psz     = pszArgs;
    1538         char    ch;
    1539         bool    fBinary = false;
    1540         for (;;)
    1541         {
    1542             /*
    1543              * Check for the end.
    1544              */
    1545             if ((ch = *psz) == '\0')
    1546             {
    1547                 if (chQuote)
    1548                     return VERR_PARSE_UNBALANCED_QUOTE;
    1549                 if (cPar)
    1550                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1551                 pszEnd = psz;
    1552                 break;
    1553             }
    1554             /*
    1555              * When quoted we ignore everything but the quotation char.
    1556              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    1557              */
    1558             else if (ch == '\'' || ch == '"' || ch == '`')
    1559             {
    1560                 if (chQuote)
    1561                 {
    1562                     /* end quote? */
    1563                     if (ch == chQuote)
    1564                     {
    1565                         if (psz[1] == ch)
    1566                             psz++;          /* skip the escaped quote char */
    1567                         else
    1568                             chQuote = '\0'; /* end of quoted string. */
    1569                     }
    1570                 }
    1571                 else
    1572                     chQuote = ch;           /* open new quote */
    1573             }
    1574             /*
    1575              * Parenthesis can of course be nested.
    1576              */
    1577             else if (ch == '(')
    1578             {
    1579                 cPar++;
    1580                 fBinary = false;
    1581             }
    1582             else if (ch == ')')
    1583             {
    1584                 if (!cPar)
    1585                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1586                 cPar--;
    1587                 fBinary = true;
    1588             }
    1589             else if (!chQuote && !cPar)
    1590             {
    1591                 /*
    1592                  * Encountering blanks may mean the end of it all. A binary operator
    1593                  * will force continued parsing.
    1594                  */
    1595                 if (isblank(*psz))
    1596                 {
    1597                     pszEnd = psz++;         /* just in case. */
    1598                     while (isblank(*psz))
    1599                         psz++;
    1600                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    1601                     if (!pOp || pOp->fBinary != fBinary)
    1602                         break;              /* the end. */
    1603                     psz += pOp->cchName;
    1604                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    1605                         psz++;
    1606                     fBinary = false;
    1607                     continue;
    1608                 }
    1609 
    1610                 /*
    1611                  * Look for operators without a space up front.
    1612                  */
    1613                 if (dbgcIsOpChar(*psz))
    1614                 {
    1615                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    1616                     if (pOp)
    1617                     {
    1618                         if (pOp->fBinary != fBinary)
    1619                         {
    1620                             pszEnd = psz;
    1621                             /** @todo this is a parsing error really. */
    1622                             break;              /* the end. */
    1623                         }
    1624                         psz += pOp->cchName;
    1625                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    1626                             psz++;
    1627                         fBinary = false;
    1628                         continue;
    1629                     }
    1630                 }
    1631                 fBinary = true;
    1632             }
    1633 
    1634             /* next char */
    1635             psz++;
    1636         }
    1637         *pszEnd = '\0';
    1638         /* (psz = next char to process) */
    1639 
    1640         /*
    1641          * Parse and evaluate the argument.
    1642          */
    1643         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    1644         if (VBOX_FAILURE(rc))
    1645             return rc;
    1646 
    1647         /*
    1648          * Next.
    1649          */
    1650         pArg++;
    1651         (*pcArgs)++;
    1652         pszArgs = psz;
    1653         while (*pszArgs && isblank(*pszArgs))
    1654             pszArgs++;
    1655     } while (*pszArgs);
    1656 
    1657     /*
    1658      * Match the arguments.
    1659      */
    1660     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    1661 }
    1662 
    1663 
    1664 /**
    1665  * Process one command.
    1666  *
    1667  * @returns VBox status code. Any error indicates the termination of the console session.
    1668  * @param   pDbgc   Debugger console instance data.
    1669  * @param   pszCmd  Pointer to the command.
    1670  * @param   cchCmd  Length of the command.
    1671  */
    1672 int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    1673 {
    1674     char *pszCmdInput = pszCmd;
    1675 
    1676     /*
    1677      * Skip blanks.
    1678      */
    1679     while (isblank(*pszCmd))
    1680         pszCmd++, cchCmd--;
    1681 
    1682     /* external command? */
    1683     bool fExternal = *pszCmd == '.';
    1684     if (fExternal)
    1685         pszCmd++, cchCmd--;
    1686 
    1687     /*
    1688      * Find arguments.
    1689      */
    1690     char *pszArgs = pszCmd;
    1691     while (isalnum(*pszArgs))
    1692         pszArgs++;
    1693     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    1694     {
    1695         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    1696         return 0;
    1697     }
    1698 
    1699     /*
    1700      * Find the command.
    1701      */
    1702     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    1703     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    1704         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    1705 
    1706     /*
    1707      * Parse arguments (if any).
    1708      */
    1709     unsigned    cArgs;
    1710     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    1711 
    1712     /*
    1713      * Execute the command.
    1714      */
    1715     if (!rc)
    1716     {
    1717         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    1718     }
    1719     else
    1720     {
    1721         /* report parse / eval error. */
    1722         switch (rc)
    1723         {
    1724             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    1725                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1726                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    1727                 break;
    1728             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    1729                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1730                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    1731                 break;
    1732             case VERR_PARSE_ARGUMENT_OVERFLOW:
    1733                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1734                     "Syntax error: Too many arguments.\n");
    1735                 break;
    1736             case VERR_PARSE_UNBALANCED_QUOTE:
    1737                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1738                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    1739                 break;
    1740             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    1741                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1742                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    1743                 break;
    1744             case VERR_PARSE_EMPTY_ARGUMENT:
    1745                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1746                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    1747                 break;
    1748             case VERR_PARSE_UNEXPECTED_OPERATOR:
    1749                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1750                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    1751                 break;
    1752             case VERR_PARSE_INVALID_NUMBER:
    1753                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1754                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    1755                 break;
    1756             case VERR_PARSE_NUMBER_TOO_BIG:
    1757                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1758                     "Error: Numeric overflow (argument %d).\n", cArgs);
    1759                 break;
    1760             case VERR_PARSE_INVALID_OPERATION:
    1761                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1762                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    1763                 break;
    1764             case VERR_PARSE_FUNCTION_NOT_FOUND:
    1765                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1766                     "Error: Function not found (argument %d).\n", cArgs);
    1767                 break;
    1768             case VERR_PARSE_NOT_A_FUNCTION:
    1769                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1770                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    1771                 break;
    1772             case VERR_PARSE_NO_MEMORY:
    1773                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1774                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    1775                 break;
    1776             case VERR_PARSE_INCORRECT_ARG_TYPE:
    1777                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1778                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    1779                 break;
    1780             case VERR_PARSE_VARIABLE_NOT_FOUND:
    1781                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1782                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    1783                 break;
    1784             case VERR_PARSE_CONVERSION_FAILED:
    1785                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1786                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    1787                 break;
    1788             case VERR_PARSE_NOT_IMPLEMENTED:
    1789                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1790                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    1791                 break;
    1792             case VERR_PARSE_BAD_RESULT_TYPE:
    1793                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1794                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    1795                 break;
    1796             case VERR_PARSE_WRITEONLY_SYMBOL:
    1797                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1798                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    1799                 break;
    1800 
    1801             default:
    1802                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    1803                     "Error: Unknown error %d!\n", rc);
    1804                 return rc;
    1805         }
    1806 
    1807         /*
    1808          * Parse errors are non fatal.
    1809          */
    1810         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    1811             rc = 0;
    1812     }
    1813 
    1814     return rc;
    1815 }
    1816 
    1817 
    1818 /**
    1819  * Process all commands current in the buffer.
    1820  *
    1821  * @returns VBox status code. Any error indicates the termination of the console session.
    1822  * @param   pDbgc   Debugger console instance data.
    1823  */
    1824 static int dbgcProcessCommands(PDBGC pDbgc)
    1825 {
    1826     int rc = 0;
    1827     while (pDbgc->cInputLines)
    1828     {
    1829         /*
    1830          * Empty the log buffer if we're hooking the log.
    1831          */
    1832         if (pDbgc->fLog)
    1833         {
    1834             rc = dbgcProcessLog(pDbgc);
    1835             if (VBOX_FAILURE(rc))
    1836                 break;
    1837         }
    1838 
    1839         if (pDbgc->iRead == pDbgc->iWrite)
    1840         {
    1841             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    1842             pDbgc->cInputLines = 0;
    1843             return 0;
    1844         }
    1845 
    1846         /*
    1847          * Copy the command to the parse buffer.
    1848          */
    1849         char    ch;
    1850         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    1851         char   *pszTrg = &pDbgc->achScratch[0];
    1852         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    1853         {
    1854             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    1855                 psz = &pDbgc->achInput[0];
    1856 
    1857             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    1858             {
    1859                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    1860                 pDbgc->cInputLines = 0;
    1861                 return 0;
    1862             }
    1863 
    1864             pszTrg++;
    1865         }
    1866         *pszTrg = '\0';
    1867 
    1868         /*
    1869          * Advance the buffer.
    1870          */
    1871         pDbgc->iRead = psz - &pDbgc->achInput[0];
    1872         if (ch == '\n')
    1873             pDbgc->cInputLines--;
    1874 
    1875         /*
    1876          * Parse and execute this command.
    1877          */
    1878         pDbgc->pszScratch = psz;
    1879         pDbgc->iArg       = 0;
    1880         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    1881         if (rc)
    1882             break;
    1883     }
    1884 
    1885     return rc;
    1886 }
    1887 
    1888 
    1889 /**
    1890  * Reads input, parses it and executes commands on '\n'.
    1891  *
    1892  * @returns VBox status.
    1893  * @param   pDbgc   Debugger console instance data.
    1894  */
    1895 static int dbgcProcessInput(PDBGC pDbgc)
    1896 {
    1897     /*
    1898      * We know there's input ready, so let's read it first.
    1899      */
    1900     int rc = dbgcInputRead(pDbgc);
    1901     if (VBOX_FAILURE(rc))
    1902         return rc;
    1903 
    1904     /*
    1905      * Now execute any ready commands.
    1906      */
    1907     if (pDbgc->cInputLines)
    1908     {
    1909         /** @todo this fReady stuff is broken. */
    1910         pDbgc->fReady = false;
    1911         rc = dbgcProcessCommands(pDbgc);
    1912         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    1913             pDbgc->fReady = true;
    1914         if (    VBOX_SUCCESS(rc)
    1915             &&  pDbgc->iRead == pDbgc->iWrite
    1916             &&  pDbgc->fReady)
    1917             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    1918     }
    1919 
    1920     return rc;
    1921 }
    1922 
    1923 
    1924 /**
    1925  * Gets the event context identifier string.
    1926  * @returns Read only string.
    1927  * @param   enmCtx          The context.
    1928  */
    1929 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    1930 {
    1931     switch (enmCtx)
    1932     {
    1933         case DBGFEVENTCTX_RAW:      return "raw";
    1934         case DBGFEVENTCTX_REM:      return "rem";
    1935         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    1936         case DBGFEVENTCTX_HYPER:    return "hyper";
    1937         case DBGFEVENTCTX_OTHER:    return "other";
    1938 
    1939         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    1940         default:
    1941             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    1942             return "!Unknown Event Ctx!";
    1943     }
    1944 }
    1945 
    1946 
    1947 /**
    1948  * Processes debugger events.
    1949  *
    1950  * @returns VBox status.
    1951  * @param   pDbgc   DBGC Instance data.
    1952  * @param   pEvent  Pointer to event data.
    1953  */
    1954 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    1955 {
    1956     /*
    1957      * Flush log first.
    1958      */
    1959     if (pDbgc->fLog)
    1960     {
    1961         int rc = dbgcProcessLog(pDbgc);
    1962         if (VBOX_FAILURE(rc))
    1963             return rc;
    1964     }
    1965 
    1966     /*
    1967      * Process the event.
    1968      */
    1969     pDbgc->pszScratch = &pDbgc->achInput[0];
    1970     pDbgc->iArg       = 0;
    1971     bool fPrintPrompt = true;
    1972     int rc = VINF_SUCCESS;
    1973     switch (pEvent->enmType)
    1974     {
    1975         /*
    1976          * The first part is events we have initiated with commands.
    1977          */
    1978         case DBGFEVENT_HALT_DONE:
    1979         {
    1980             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    1981                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    1982             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    1983             if (VBOX_SUCCESS(rc))
    1984                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    1985             break;
    1986         }
    1987 
    1988 
    1989         /*
    1990          * The second part is events which can occur at any time.
    1991          */
    1992         case DBGFEVENT_FATAL_ERROR:
    1993         {
    1994             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    1995                                          dbgcGetEventCtx(pEvent->enmCtx));
    1996             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    1997             if (VBOX_SUCCESS(rc))
    1998                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    1999             break;
    2000         }
    2001 
    2002         case DBGFEVENT_BREAKPOINT:
    2003         case DBGFEVENT_BREAKPOINT_HYPER:
    2004         {
    2005             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    2006             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    2007 
    2008             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    2009             switch (rc)
    2010             {
    2011                 case VERR_DBGC_BP_NOT_FOUND:
    2012                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    2013                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2014                     break;
    2015 
    2016                 case VINF_DBGC_BP_NO_COMMAND:
    2017                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    2018                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2019                     break;
    2020 
    2021                 case VINF_BUFFER_OVERFLOW:
    2022                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    2023                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2024                     break;
    2025 
    2026                 default:
    2027                     break;
    2028             }
    2029             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    2030                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2031             else
    2032                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    2033             break;
    2034         }
    2035 
    2036         case DBGFEVENT_STEPPED:
    2037         case DBGFEVENT_STEPPED_HYPER:
    2038         {
    2039             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    2040 
    2041             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    2042             if (VBOX_SUCCESS(rc))
    2043                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2044             break;
    2045         }
    2046 
    2047         case DBGFEVENT_ASSERTION_HYPER:
    2048         {
    2049             pDbgc->fRegCtxGuest = false;
    2050 
    2051             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2052                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    2053                                          "%s"
    2054                                          "%s"
    2055                                          "\n",
    2056                                          dbgcGetEventCtx(pEvent->enmCtx),
    2057                                          pEvent->u.Assert.pszMsg1,
    2058                                          pEvent->u.Assert.pszMsg2);
    2059             if (VBOX_SUCCESS(rc))
    2060                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2061             break;
    2062         }
    2063 
    2064         case DBGFEVENT_DEV_STOP:
    2065         {
    2066             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2067                                          "\n"
    2068                                          "dbgf event: DBGFSTOP (%s)\n"
    2069                                          "File:     %s\n"
    2070                                          "Line:     %d\n"
    2071                                          "Function: %s\n",
    2072                                          dbgcGetEventCtx(pEvent->enmCtx),
    2073                                          pEvent->u.Src.pszFile,
    2074                                          pEvent->u.Src.uLine,
    2075                                          pEvent->u.Src.pszFunction);
    2076             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    2077                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2078                                          "Message:  %s\n",
    2079                                              pEvent->u.Src.pszMessage);
    2080             if (VBOX_SUCCESS(rc))
    2081                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2082             break;
    2083         }
    2084 
    2085 
    2086         case DBGFEVENT_INVALID_COMMAND:
    2087         {
    2088             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    2089             fPrintPrompt = !pDbgc->fReady;
    2090             break;
    2091         }
    2092 
    2093         case DBGFEVENT_TERMINATING:
    2094         {
    2095             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    2096             rc = VERR_GENERAL_FAILURE;
    2097             break;
    2098         }
    2099 
    2100 
    2101         default:
    2102         {
    2103             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    2104             fPrintPrompt = !pDbgc->fReady;
    2105             break;
    2106         }
    2107     }
    2108 
    2109     /*
    2110      * Prompt, anyone?
    2111      */
    2112     if (fPrintPrompt && VBOX_SUCCESS(rc))
    2113     {
    2114         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    2115     }
    2116 
    2117     return rc;
    2118 }
    2119 
    2120 
    2121 
    2122 
    2123 
    2124 /**
    2125  * Make a console instance.
    2126  *
    2127  * This will not return until either an 'exit' command is issued or a error code
    2128  * indicating connection loss is encountered.
    2129  *
    2130  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    2131  * @returns The VBox status code causing the console termination.
    2132  *
    2133  * @param   pVM         VM Handle.
    2134  * @param   pBack       Pointer to the backend structure. This must contain
    2135  *                      a full set of function pointers to service the console.
    2136  * @param   fFlags      Reserved, must be zero.
    2137  * @remark  A forced termination of the console is easiest done by forcing the
    2138  *          callbacks to return fatal failures.
    2139  */
    2140 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    2141 {
    2142     /*
    2143      * Validate input.
    2144      */
    2145     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    2146     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    2147     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    2148 
    2149     /*
    2150      * Allocate and initialize instance data
    2151      */
    2152     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    2153     if (!pDbgc)
    2154         return VERR_NO_MEMORY;
    2155 
    2156     dbgcInitCmdHlp(pDbgc);
    2157     pDbgc->pBack            = pBack;
    2158     pDbgc->pVM              = NULL;
    2159     pDbgc->pszEmulation     = "CodeView/WinDbg";
    2160     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    2161     pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    2162     //pDbgc->fLog             = false;
    2163     pDbgc->fRegCtxGuest     = true;
    2164     pDbgc->fRegTerse        = true;
    2165     //pDbgc->DisasmPos        = {0};
    2166     //pDbgc->SourcePos        = {0};
    2167     //pDbgc->DumpPos          = {0};
    2168     //pDbgc->cbDumpElement    = 0;
    2169     //pDbgc->cVars            = 0;
    2170     //pDbgc->paVars           = NULL;
    2171     //pDbgc->pFirstBp         = NULL;
    2172     //pDbgc->uInputZero       = 0;
    2173     //pDbgc->iRead            = 0;
    2174     //pDbgc->iWrite           = 0;
    2175     //pDbgc->cInputLines      = 0;
    2176     //pDbgc->fInputOverflow   = false;
    2177     pDbgc->fReady           = true;
    2178     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    2179     //pDbgc->iArg             = 0;
    2180     //pDbgc->rcOutput         = 0;
    2181 
    2182     dbgcInitOpCharBitMap();
    2183 
    2184     /*
    2185      * Print welcome message.
    2186      */
    2187     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2188         "Welcome to the VirtualBox Debugger!\n");
    2189     if (VBOX_FAILURE(rc))
    2190         goto l_failure;
    2191 
    2192     /*
    2193      * Attach to the VM.
    2194      */
    2195     rc = DBGFR3Attach(pVM);
    2196     if (VBOX_FAILURE(rc))
    2197     {
    2198         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    2199         goto l_failure;
    2200     }
    2201     pDbgc->pVM = pVM;
    2202 
    2203     /*
    2204      * Print commandline and auto select result.
    2205      */
    2206     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2207         "Current VM is %08x\n" /** @todo get and print the VM name! */
    2208         "VBoxDbg> ",
    2209         pDbgc->pVM);
    2210     if (VBOX_FAILURE(rc))
    2211         goto l_failure;
    2212 
    2213     /*
    2214      * Main Debugger Loop.
    2215      *
    2216      * This loop will either block on waiting for input or on waiting on
    2217      * debug events. If we're forwarding the log we cannot wait for long
    2218      * before we must flush the log.
    2219      */
    2220     for (rc = 0;;)
    2221     {
    2222         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    2223         {
    2224             /*
    2225              * Wait for a debug event.
    2226              */
    2227             PCDBGFEVENT pEvent;
    2228             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    2229             if (VBOX_SUCCESS(rc))
    2230             {
    2231                 rc = dbgcProcessEvent(pDbgc, pEvent);
    2232                 if (VBOX_FAILURE(rc))
    2233                     break;
    2234             }
    2235             else if (rc != VERR_TIMEOUT)
    2236                 break;
    2237 
    2238             /*
    2239              * Check for input.
    2240              */
    2241             if (pBack->pfnInput(pDbgc->pBack, 0))
    2242             {
    2243                 rc = dbgcProcessInput(pDbgc);
    2244                 if (VBOX_FAILURE(rc))
    2245                     break;
    2246             }
    2247         }
    2248         else
    2249         {
    2250             /*
    2251              * Wait for input. If Logging is enabled we'll only wait very briefly.
    2252              */
    2253             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    2254             {
    2255                 rc = dbgcProcessInput(pDbgc);
    2256                 if (VBOX_FAILURE(rc))
    2257                     break;
    2258             }
    2259         }
    2260 
    2261         /*
    2262          * Forward log output.
    2263          */
    2264         if (pDbgc->fLog)
    2265         {
    2266             rc = dbgcProcessLog(pDbgc);
    2267             if (VBOX_FAILURE(rc))
    2268                 break;
    2269         }
    2270     }
    2271 
    2272 
    2273 l_failure:
    2274     /*
    2275      * Cleanup console debugger session.
    2276      */
    2277     /* Disable log hook. */
    2278     if (pDbgc->fLog)
    2279     {
    2280 
    2281     }
    2282 
    2283     /* Detach from the VM. */
    2284     if (pDbgc->pVM)
    2285         DBGFR3Detach(pDbgc->pVM);
    2286 
    2287     /* finally, free the instance memory. */
    2288     RTMemFree(pDbgc);
    2289 
    2290     return rc;
    2291 }
    2292 
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r5676 r5677  
    136136
    137137
    138 
    139 
    140 
    141 
    142 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    143 //
    144 //
    145 //      V a r i a b l e   M a n i p u l a t i o n
    146 //
    147 //
    148 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    149 
    150 
    151 
    152 /** @todo move me!*/
    153 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
     138/**
     139 * Initalizes g_bmOperatorChars.
     140 */
     141static void dbgcInitOpCharBitMap(void)
    154142{
    155     if (pVar)
    156     {
    157         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    158         pVar->u.GCFlat = GCFlat;
    159         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    160         pVar->u64Range  = 0;
    161     }
     143    memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
     144    for (unsigned iOp = 0; iOp < g_cOps; iOp++)
     145        ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    162146}
    163147
    164148
    165 /** @todo move me!*/
    166 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
     149/**
     150 * Checks whether the character may be the start of an operator.
     151 *
     152 * @returns true/false.
     153 * @param   ch      The character.
     154 */
     155DECLINLINE(bool) dbgcIsOpChar(char ch)
    167156{
    168     if (pVar)
    169     {
    170         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    171         pVar->u.GCFlat = GCFlat;
    172         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    173         pVar->u64Range  = cb;
    174     }
     157    return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    175158}
    176 
    177 
    178 /** @todo move me!*/
    179 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    180 {
    181     if (pVar)
    182     {
    183         if (pVar2)
    184             *pVar = *pVar2;
    185         else
    186         {
    187             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    188             memset(&pVar->u, 0, sizeof(pVar->u));
    189             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    190             pVar->u64Range  = 0;
    191         }
    192     }
    193 }
    194 
    195 
    196 /** @todo move me!*/
    197 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    198 {
    199     if (pVar)
    200     {
    201         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    202         pVar->u64Range  = cb;
    203     }
    204 }
    205 
    206 
    207 /** @todo move me!*/
    208 void dbgcVarSetNoRange(PDBGCVAR pVar)
    209 {
    210     if (pVar)
    211     {
    212         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    213         pVar->u64Range  = 0;
    214     }
    215 }
    216 
    217 
    218 /**
    219  * Converts a DBGC variable to a DBGF address.
    220  *
    221  * @returns VBox status code.
    222  * @param   pDbgc       The DBGC instance.
    223  * @param   pVar        The variable.
    224  * @param   pAddress    Where to store the address.
    225  */
    226 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    227 {
    228     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    229     switch (pVar->enmType)
    230     {
    231         case DBGCVAR_TYPE_GC_FLAT:
    232             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    233             return VINF_SUCCESS;
    234 
    235         case DBGCVAR_TYPE_NUMBER:
    236             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    237             return VINF_SUCCESS;
    238 
    239         case DBGCVAR_TYPE_GC_FAR:
    240             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    241 
    242         case DBGCVAR_TYPE_STRING:
    243         case DBGCVAR_TYPE_SYMBOL:
    244         {
    245             DBGCVAR Var;
    246             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    247             if (VBOX_FAILURE(rc))
    248                 return rc;
    249             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    250         }
    251 
    252         case DBGCVAR_TYPE_GC_PHYS:
    253         case DBGCVAR_TYPE_HC_FLAT:
    254         case DBGCVAR_TYPE_HC_FAR:
    255         case DBGCVAR_TYPE_HC_PHYS:
    256         default:
    257             return VERR_PARSE_CONVERSION_FAILED;
    258     }
    259 }
    260 
    261 
    262 
    263 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    264 //
    265 //
    266 //      B r e a k p o i n t   M a n a g e m e n t
    267 //
    268 //
    269 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    270 
    271 
    272 /**
    273  * Adds a breakpoint to the DBGC breakpoint list.
    274  */
    275 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    276 {
    277     /*
    278      * Check if it already exists.
    279      */
    280     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    281     if (pBp)
    282         return VERR_DBGC_BP_EXISTS;
    283 
    284     /*
    285      * Add the breakpoint.
    286      */
    287     if (pszCmd)
    288         pszCmd = RTStrStripL(pszCmd);
    289     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    290     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    291     if (!pBp)
    292         return VERR_NO_MEMORY;
    293     if (cchCmd)
    294         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    295     else
    296         pBp->szCmd[0] = '\0';
    297     pBp->cchCmd = cchCmd;
    298     pBp->iBp    = iBp;
    299     pBp->pNext  = pDbgc->pFirstBp;
    300     pDbgc->pFirstBp = pBp;
    301 
    302     return VINF_SUCCESS;
    303 }
    304 
    305 /**
    306  * Updates the a breakpoint.
    307  *
    308  * @returns VBox status code.
    309  * @param   pDbgc       The DBGC instance.
    310  * @param   iBp         The breakpoint to update.
    311  * @param   pszCmd      The new command.
    312  */
    313 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    314 {
    315     /*
    316      * Find the breakpoint.
    317      */
    318     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    319     if (!pBp)
    320         return VERR_DBGC_BP_NOT_FOUND;
    321 
    322     /*
    323      * Do we need to reallocate?
    324      */
    325     if (pszCmd)
    326         pszCmd = RTStrStripL(pszCmd);
    327     if (!pszCmd || !*pszCmd)
    328         pBp->szCmd[0] = '\0';
    329     else
    330     {
    331         size_t cchCmd = strlen(pszCmd);
    332         if (strlen(pBp->szCmd) >= cchCmd)
    333         {
    334             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    335             pBp->cchCmd = cchCmd;
    336         }
    337         else
    338         {
    339             /*
    340              * Yes, let's do it the simple way...
    341              */
    342             int rc = dbgcBpDelete(pDbgc, iBp);
    343             AssertRC(rc);
    344             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    345         }
    346     }
    347     return VINF_SUCCESS;
    348 }
    349 
    350 
    351 /**
    352  * Deletes a breakpoint.
    353  *
    354  * @returns VBox status code.
    355  * @param   pDbgc       The DBGC instance.
    356  * @param   iBp         The breakpoint to delete.
    357  */
    358 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    359 {
    360     /*
    361      * Search thru the list, when found unlink and free it.
    362      */
    363     PDBGCBP pBpPrev = NULL;
    364     PDBGCBP pBp = pDbgc->pFirstBp;
    365     for (; pBp; pBp = pBp->pNext)
    366     {
    367         if (pBp->iBp == iBp)
    368         {
    369             if (pBpPrev)
    370                 pBpPrev->pNext = pBp->pNext;
    371             else
    372                 pDbgc->pFirstBp = pBp->pNext;
    373             RTMemFree(pBp);
    374             return VINF_SUCCESS;
    375         }
    376         pBpPrev = pBp;
    377     }
    378 
    379     return VERR_DBGC_BP_NOT_FOUND;
    380 }
    381 
    382 
    383 /**
    384  * Get a breakpoint.
    385  *
    386  * @returns Pointer to the breakpoint.
    387  * @returns NULL if the breakpoint wasn't found.
    388  * @param   pDbgc       The DBGC instance.
    389  * @param   iBp         The breakpoint to get.
    390  */
    391 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    392 {
    393     /*
    394      * Enumerate the list.
    395      */
    396     PDBGCBP pBp = pDbgc->pFirstBp;
    397     for (; pBp; pBp = pBp->pNext)
    398         if (pBp->iBp == iBp)
    399             return pBp;
    400     return NULL;
    401 }
    402 
    403 
    404 /**
    405  * Executes the command of a breakpoint.
    406  *
    407  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    408  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    409  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    410  * @returns VBox status code from dbgcProcessCommand() other wise.
    411  * @param   pDbgc       The DBGC instance.
    412  * @param   iBp         The breakpoint to execute.
    413  */
    414 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    415 {
    416     /*
    417      * Find the breakpoint.
    418      */
    419     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    420     if (!pBp)
    421         return VERR_DBGC_BP_NOT_FOUND;
    422 
    423     /*
    424      * Anything to do?
    425      */
    426     if (!pBp->cchCmd)
    427         return VINF_DBGC_BP_NO_COMMAND;
    428 
    429     /*
    430      * Execute the command.
    431      * This means copying it to the scratch buffer and process it as if it
    432      * were user input. We must save and restore the state of the scratch buffer.
    433      */
    434     /* Save the scratch state. */
    435     char       *pszScratch  = pDbgc->pszScratch;
    436     unsigned    iArg        = pDbgc->iArg;
    437 
    438     /* Copy the command to the scratch buffer. */
    439     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    440     if (pBp->cchCmd >= cbScratch)
    441         return VERR_BUFFER_OVERFLOW;
    442     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    443 
    444     /* Execute the command. */
    445     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    446     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    447 
    448     /* Restore the scratch state. */
    449     pDbgc->iArg         = iArg;
    450     pDbgc->pszScratch   = pszScratch;
    451 
    452     return rc;
    453 }
    454 
    455 
    456 
    457 
    458 
    459 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    460 //
    461 //
    462 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    463 //
    464 //
    465 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    466 
    467159
    468160
     
    715407
    716408    return VERR_PARSE_NOT_IMPLEMENTED;
    717 }
    718 
    719 
    720 /**
    721  * Initalizes g_bmOperatorChars.
    722  */
    723 static void dbgcInitOpCharBitMap(void)
    724 {
    725     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    726     for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    727         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    728 }
    729 
    730 
    731 /**
    732  * Checks whether the character may be the start of an operator.
    733  *
    734  * @returns true/false.
    735  * @param   ch      The character.
    736  */
    737 DECLINLINE(bool) dbgcIsOpChar(char ch)
    738 {
    739     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    740409}
    741410
  • trunk/src/VBox/Debugger/Makefile.kmk

    r5676 r5677  
    3838        DBGCBuiltInSymbols.cpp \
    3939        DBGCCmdHlp.cpp \
     40        DBGCCmdWorkers.cpp \
    4041        DBGCCommands.cpp \
    4142        DBGCEmulateCodeView.cpp \
     
    104105        DBGCBuiltInSymbols.cpp \
    105106        DBGCCmdHlp.cpp \
     107        DBGCCmdWorkers.cpp \
    106108        DBGCCommands.cpp \
    107109        DBGCEmulateCodeView.cpp \
Note: See TracChangeset for help on using the changeset viewer.

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