VirtualBox

Changeset 5676 in vbox


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

Split out the DBGCCMDHLP stuff.

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

Legend:

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

    r5675 r5676  
    11/** $Id$ */
    22/** @file
    3  * DBGC - Debugger Console.
     3 * DBGC - Debugger Console, Command Helpers.
    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 *   Internal Functions                                                         *
    132 *******************************************************************************/
    133 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    134 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
    135 
    136 
    137 /*******************************************************************************
    138 *   Global Variables                                                           *
    139 *******************************************************************************/
    140 /** Bitmap where set bits indicates the characters the may start an operator name. */
    141 static uint32_t g_bmOperatorChars[256 / (4*8)];
    142 
    143 
    144 
    145 
    146 
    147 
    148 
    149 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    150 //
    151 //
    152 //      C a l l b a c k   H e l p e r s
    153 //
    154 //
    155 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    15641
    15742
     
    762647
    763648
    764 
    765 
    766 
    767 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    768 //
    769 //
    770 //      V a r i a b l e   M a n i p u l a t i o n
    771 //
    772 //
    773 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    774 
    775 
    776 
    777 /** @todo move me!*/
    778 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
    779 {
    780     if (pVar)
    781     {
    782         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    783         pVar->u.GCFlat = GCFlat;
    784         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    785         pVar->u64Range  = 0;
    786     }
    787 }
    788 
    789 
    790 /** @todo move me!*/
    791 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
    792 {
    793     if (pVar)
    794     {
    795         pVar->enmType  = DBGCVAR_TYPE_GC_FLAT;
    796         pVar->u.GCFlat = GCFlat;
    797         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    798         pVar->u64Range  = cb;
    799     }
    800 }
    801 
    802 
    803 /** @todo move me!*/
    804 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
    805 {
    806     if (pVar)
    807     {
    808         if (pVar2)
    809             *pVar = *pVar2;
    810         else
    811         {
    812             pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
    813             memset(&pVar->u, 0, sizeof(pVar->u));
    814             pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    815             pVar->u64Range  = 0;
    816         }
    817     }
    818 }
    819 
    820 
    821 /** @todo move me!*/
    822 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
    823 {
    824     if (pVar)
    825     {
    826         pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
    827         pVar->u64Range  = cb;
    828     }
    829 }
    830 
    831 
    832 /** @todo move me!*/
    833 void dbgcVarSetNoRange(PDBGCVAR pVar)
    834 {
    835     if (pVar)
    836     {
    837         pVar->enmRangeType = DBGCVAR_RANGE_NONE;
    838         pVar->u64Range  = 0;
    839     }
    840 }
    841 
    842 
    843 /**
    844  * Converts a DBGC variable to a DBGF address.
    845  *
    846  * @returns VBox status code.
    847  * @param   pDbgc       The DBGC instance.
    848  * @param   pVar        The variable.
    849  * @param   pAddress    Where to store the address.
    850  */
    851 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    852 {
    853     AssertReturn(pVar, VERR_INVALID_PARAMETER);
    854     switch (pVar->enmType)
    855     {
    856         case DBGCVAR_TYPE_GC_FLAT:
    857             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
    858             return VINF_SUCCESS;
    859 
    860         case DBGCVAR_TYPE_NUMBER:
    861             DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
    862             return VINF_SUCCESS;
    863 
    864         case DBGCVAR_TYPE_GC_FAR:
    865             return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
    866 
    867         case DBGCVAR_TYPE_STRING:
    868         case DBGCVAR_TYPE_SYMBOL:
    869         {
    870             DBGCVAR Var;
    871             int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
    872             if (VBOX_FAILURE(rc))
    873                 return rc;
    874             return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
    875         }
    876 
    877         case DBGCVAR_TYPE_GC_PHYS:
    878         case DBGCVAR_TYPE_HC_FLAT:
    879         case DBGCVAR_TYPE_HC_FAR:
    880         case DBGCVAR_TYPE_HC_PHYS:
    881         default:
    882             return VERR_PARSE_CONVERSION_FAILED;
    883     }
    884 }
    885 
    886 
    887 
    888 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    889 //
    890 //
    891 //      B r e a k p o i n t   M a n a g e m e n t
    892 //
    893 //
    894 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    895 
    896 
    897 /**
    898  * Adds a breakpoint to the DBGC breakpoint list.
    899  */
    900 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    901 {
    902     /*
    903      * Check if it already exists.
    904      */
    905     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    906     if (pBp)
    907         return VERR_DBGC_BP_EXISTS;
    908 
    909     /*
    910      * Add the breakpoint.
    911      */
    912     if (pszCmd)
    913         pszCmd = RTStrStripL(pszCmd);
    914     size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
    915     pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
    916     if (!pBp)
    917         return VERR_NO_MEMORY;
    918     if (cchCmd)
    919         memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    920     else
    921         pBp->szCmd[0] = '\0';
    922     pBp->cchCmd = cchCmd;
    923     pBp->iBp    = iBp;
    924     pBp->pNext  = pDbgc->pFirstBp;
    925     pDbgc->pFirstBp = pBp;
    926 
    927     return VINF_SUCCESS;
    928 }
    929 
    930 /**
    931  * Updates the a breakpoint.
    932  *
    933  * @returns VBox status code.
    934  * @param   pDbgc       The DBGC instance.
    935  * @param   iBp         The breakpoint to update.
    936  * @param   pszCmd      The new command.
    937  */
    938 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
    939 {
    940     /*
    941      * Find the breakpoint.
    942      */
    943     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    944     if (!pBp)
    945         return VERR_DBGC_BP_NOT_FOUND;
    946 
    947     /*
    948      * Do we need to reallocate?
    949      */
    950     if (pszCmd)
    951         pszCmd = RTStrStripL(pszCmd);
    952     if (!pszCmd || !*pszCmd)
    953         pBp->szCmd[0] = '\0';
    954     else
    955     {
    956         size_t cchCmd = strlen(pszCmd);
    957         if (strlen(pBp->szCmd) >= cchCmd)
    958         {
    959             memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
    960             pBp->cchCmd = cchCmd;
    961         }
    962         else
    963         {
    964             /*
    965              * Yes, let's do it the simple way...
    966              */
    967             int rc = dbgcBpDelete(pDbgc, iBp);
    968             AssertRC(rc);
    969             return dbgcBpAdd(pDbgc, iBp, pszCmd);
    970         }
    971     }
    972     return VINF_SUCCESS;
    973 }
    974 
    975 
    976 /**
    977  * Deletes a breakpoint.
    978  *
    979  * @returns VBox status code.
    980  * @param   pDbgc       The DBGC instance.
    981  * @param   iBp         The breakpoint to delete.
    982  */
    983 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
    984 {
    985     /*
    986      * Search thru the list, when found unlink and free it.
    987      */
    988     PDBGCBP pBpPrev = NULL;
    989     PDBGCBP pBp = pDbgc->pFirstBp;
    990     for (; pBp; pBp = pBp->pNext)
    991     {
    992         if (pBp->iBp == iBp)
    993         {
    994             if (pBpPrev)
    995                 pBpPrev->pNext = pBp->pNext;
    996             else
    997                 pDbgc->pFirstBp = pBp->pNext;
    998             RTMemFree(pBp);
    999             return VINF_SUCCESS;
    1000         }
    1001         pBpPrev = pBp;
    1002     }
    1003 
    1004     return VERR_DBGC_BP_NOT_FOUND;
    1005 }
    1006 
    1007 
    1008 /**
    1009  * Get a breakpoint.
    1010  *
    1011  * @returns Pointer to the breakpoint.
    1012  * @returns NULL if the breakpoint wasn't found.
    1013  * @param   pDbgc       The DBGC instance.
    1014  * @param   iBp         The breakpoint to get.
    1015  */
    1016 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
    1017 {
    1018     /*
    1019      * Enumerate the list.
    1020      */
    1021     PDBGCBP pBp = pDbgc->pFirstBp;
    1022     for (; pBp; pBp = pBp->pNext)
    1023         if (pBp->iBp == iBp)
    1024             return pBp;
    1025     return NULL;
    1026 }
    1027 
    1028 
    1029 /**
    1030  * Executes the command of a breakpoint.
    1031  *
    1032  * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
    1033  * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
    1034  * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
    1035  * @returns VBox status code from dbgcProcessCommand() other wise.
    1036  * @param   pDbgc       The DBGC instance.
    1037  * @param   iBp         The breakpoint to execute.
    1038  */
    1039 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
    1040 {
    1041     /*
    1042      * Find the breakpoint.
    1043      */
    1044     PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
    1045     if (!pBp)
    1046         return VERR_DBGC_BP_NOT_FOUND;
    1047 
    1048     /*
    1049      * Anything to do?
    1050      */
    1051     if (!pBp->cchCmd)
    1052         return VINF_DBGC_BP_NO_COMMAND;
    1053 
    1054     /*
    1055      * Execute the command.
    1056      * This means copying it to the scratch buffer and process it as if it
    1057      * were user input. We must save and restore the state of the scratch buffer.
    1058      */
    1059     /* Save the scratch state. */
    1060     char       *pszScratch  = pDbgc->pszScratch;
    1061     unsigned    iArg        = pDbgc->iArg;
    1062 
    1063     /* Copy the command to the scratch buffer. */
    1064     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    1065     if (pBp->cchCmd >= cbScratch)
    1066         return VERR_BUFFER_OVERFLOW;
    1067     memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
    1068 
    1069     /* Execute the command. */
    1070     pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
    1071     int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
    1072 
    1073     /* Restore the scratch state. */
    1074     pDbgc->iArg         = iArg;
    1075     pDbgc->pszScratch   = pszScratch;
    1076 
    1077     return rc;
    1078 }
    1079 
    1080 
    1081 
    1082 
    1083 
    1084 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1085 //
    1086 //
    1087 //      I n p u t ,   p a r s i n g   a n d   l o g g i n g
    1088 //
    1089 //
    1090 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    1091 
    1092 
    1093 
    1094 /**
    1095  * Prints any log lines from the log buffer.
    1096  *
    1097  * The caller must not call function this unless pDbgc->fLog is set.
    1098  *
    1099  * @returns VBox status. (output related)
    1100  * @param   pDbgc   Debugger console instance data.
    1101  */
    1102 static int dbgcProcessLog(PDBGC pDbgc)
    1103 {
    1104     /** @todo */
    1105     NOREF(pDbgc);
    1106     return 0;
    1107 }
    1108 
    1109 
    1110 
    1111 /**
    1112  * Handle input buffer overflow.
    1113  *
    1114  * Will read any available input looking for a '\n' to reset the buffer on.
    1115  *
    1116  * @returns VBox status.
    1117  * @param   pDbgc   Debugger console instance data.
    1118  */
    1119 static int dbgcInputOverflow(PDBGC pDbgc)
    1120 {
    1121     /*
    1122      * Assert overflow status and reset the input buffer.
    1123      */
    1124     if (!pDbgc->fInputOverflow)
    1125     {
    1126         pDbgc->fInputOverflow = true;
    1127         pDbgc->iRead = pDbgc->iWrite = 0;
    1128         pDbgc->cInputLines = 0;
    1129         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
    1130     }
    1131 
    1132     /*
    1133      * Eat input till no more or there is a '\n'.
    1134      * When finding a '\n' we'll continue normal processing.
    1135      */
    1136     while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
    1137     {
    1138         size_t cbRead;
    1139         int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
    1140         if (VBOX_FAILURE(rc))
    1141             return rc;
    1142         char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
    1143         if (psz)
    1144         {
    1145             pDbgc->fInputOverflow = false;
    1146             pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
    1147             pDbgc->iWrite = (unsigned)cbRead;
    1148             pDbgc->cInputLines = 0;
    1149             break;
    1150         }
    1151     }
    1152 
    1153     return 0;
    1154 }
    1155 
    1156 
    1157 
    1158 /**
    1159  * Read input and do some preprocessing.
    1160  *
    1161  * @returns VBox status.
    1162  *          In addition to the iWrite and achInput, cInputLines is maintained.
    1163  *          In case of an input overflow the fInputOverflow flag will be set.
    1164  * @param   pDbgc   Debugger console instance data.
    1165  */
    1166 static int dbgcInputRead(PDBGC pDbgc)
    1167 {
    1168     /*
    1169      * We have ready input.
    1170      * Read it till we don't have any or we have a full input buffer.
    1171      */
    1172     int     rc = 0;
    1173     do
    1174     {
    1175         /*
    1176          * More available buffer space?
    1177          */
    1178         size_t cbLeft;
    1179         if (pDbgc->iWrite > pDbgc->iRead)
    1180             cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
    1181         else
    1182             cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
    1183         if (!cbLeft)
    1184         {
    1185             /* overflow? */
    1186             if (!pDbgc->cInputLines)
    1187                 rc = dbgcInputOverflow(pDbgc);
    1188             break;
    1189         }
    1190 
    1191         /*
    1192          * Read one char and interpret it.
    1193          */
    1194         char    achRead[128];
    1195         size_t  cbRead;
    1196         rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
    1197         if (VBOX_FAILURE(rc))
    1198             return rc;
    1199         char *psz = &achRead[0];
    1200         while (cbRead-- > 0)
    1201         {
    1202             char ch = *psz++;
    1203             switch (ch)
    1204             {
    1205                 /*
    1206                  * Ignore.
    1207                  */
    1208                 case '\0':
    1209                 case '\r':
    1210                 case '\a':
    1211                     break;
    1212 
    1213                 /*
    1214                  * Backspace.
    1215                  */
    1216                 case '\b':
    1217                     Log2(("DBGC: backspace\n"));
    1218                     if (pDbgc->iRead != pDbgc->iWrite)
    1219                     {
    1220                         unsigned iWriteUndo = pDbgc->iWrite;
    1221                         if (pDbgc->iWrite)
    1222                             pDbgc->iWrite--;
    1223                         else
    1224                             pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
    1225 
    1226                         if (pDbgc->achInput[pDbgc->iWrite] == '\n')
    1227                             pDbgc->iWrite = iWriteUndo;
    1228                     }
    1229                     break;
    1230 
    1231                 /*
    1232                  * Add char to buffer.
    1233                  */
    1234                 case '\t':
    1235                 case '\n':
    1236                 case ';':
    1237                     switch (ch)
    1238                     {
    1239                         case '\t': ch = ' '; break;
    1240                         case '\n': pDbgc->cInputLines++; break;
    1241                     }
    1242                 default:
    1243                     Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
    1244                     pDbgc->achInput[pDbgc->iWrite] = ch;
    1245                     if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
    1246                         pDbgc->iWrite = 0;
    1247                     break;
    1248             }
    1249         }
    1250 
    1251         /* Terminate it to make it easier to read in the debugger. */
    1252         pDbgc->achInput[pDbgc->iWrite] = '\0';
    1253     } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
    1254 
    1255     return rc;
    1256 }
    1257 
    1258 
    1259 
    1260 /**
    1261  * Resolves a symbol (or tries to do so at least).
    1262  *
    1263  * @returns 0 on success.
    1264  * @returns VBox status on failure.
    1265  * @param   pDbgc       The debug console instance.
    1266  * @param   pszSymbol   The symbol name.
    1267  * @param   enmType     The result type.
    1268  * @param   pResult     Where to store the result.
    1269  */
    1270 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
    1271 {
    1272     /*
    1273      * Builtin?
    1274      */
    1275     PCDBGCSYM   pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
    1276     if (pSymDesc)
    1277     {
    1278         if (!pSymDesc->pfnGet)
    1279             return VERR_PARSE_WRITEONLY_SYMBOL;
    1280         return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
    1281     }
    1282 
    1283 
    1284     /*
    1285      * Ask PDM.
    1286      */
    1287     /** @todo resolve symbols using PDM. */
    1288 
    1289 
    1290     /*
    1291      * Ask the debug info manager.
    1292      */
    1293     DBGFSYMBOL Symbol;
    1294     int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
    1295     if (VBOX_SUCCESS(rc))
    1296     {
    1297         /*
    1298          * Default return is a flat gc address.
    1299          */
    1300         memset(pResult, 0,  sizeof(*pResult));
    1301         pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
    1302         pResult->u64Range     = Symbol.cb;
    1303         pResult->enmType      = DBGCVAR_TYPE_GC_FLAT;
    1304         pResult->u.GCFlat     = Symbol.Value;
    1305         DBGCVAR VarTmp;
    1306         switch (enmType)
    1307         {
    1308             /* nothing to do. */
    1309             case DBGCVAR_TYPE_GC_FLAT:
    1310             case DBGCVAR_TYPE_GC_FAR:
    1311             case DBGCVAR_TYPE_ANY:
    1312                 return VINF_SUCCESS;
    1313 
    1314             /* simply make it numeric. */
    1315             case DBGCVAR_TYPE_NUMBER:
    1316                 pResult->enmType = DBGCVAR_TYPE_NUMBER;
    1317                 pResult->u.u64Number = Symbol.Value;
    1318                 return VINF_SUCCESS;
    1319 
    1320             /* cast it. */
    1321 
    1322             case DBGCVAR_TYPE_GC_PHYS:
    1323                 VarTmp = *pResult;
    1324                 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
    1325 
    1326             case DBGCVAR_TYPE_HC_FAR:
    1327             case DBGCVAR_TYPE_HC_FLAT:
    1328                 VarTmp = *pResult;
    1329                 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
    1330 
    1331             case DBGCVAR_TYPE_HC_PHYS:
    1332                 VarTmp = *pResult;
    1333                 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
    1334 
    1335             default:
    1336                 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
    1337                 return VERR_INVALID_PARAMETER;
    1338         }
    1339     }
    1340 
    1341     return VERR_PARSE_NOT_IMPLEMENTED;
    1342 }
    1343 
    1344 
    1345 /**
    1346  * Initalizes g_bmOperatorChars.
    1347  */
    1348 static void dbgcInitOpCharBitMap(void)
    1349 {
    1350     memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
    1351     for (unsigned iOp = 0; iOp < g_cOps; iOp++)
    1352         ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
    1353 }
    1354 
    1355 
    1356 /**
    1357  * Checks whether the character may be the start of an operator.
    1358  *
    1359  * @returns true/false.
    1360  * @param   ch      The character.
    1361  */
    1362 DECLINLINE(bool) dbgcIsOpChar(char ch)
    1363 {
    1364     return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
    1365 }
    1366 
    1367 
    1368 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
    1369 {
    1370     Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    1371 
    1372     /*
    1373      * Removing any quoting and escapings.
    1374      */
    1375     char ch = *pszExpr;
    1376     if (ch == '"' || ch == '\'' || ch == '`')
    1377     {
    1378         if (pszExpr[--cchExpr] != ch)
    1379             return VERR_PARSE_UNBALANCED_QUOTE;
    1380         cchExpr--;
    1381         pszExpr++;
    1382 
    1383         /** @todo string unescaping. */
    1384     }
    1385     pszExpr[cchExpr] = '\0';
    1386 
    1387     /*
    1388      * Make the argument.
    1389      */
    1390     pArg->pDesc         = NULL;
    1391     pArg->pNext         = NULL;
    1392     pArg->enmType       = DBGCVAR_TYPE_STRING;
    1393     pArg->u.pszString   = pszExpr;
    1394     pArg->enmRangeType  = DBGCVAR_RANGE_BYTES;
    1395     pArg->u64Range      = cchExpr;
    1396 
    1397     NOREF(pDbgc);
    1398     return 0;
    1399 }
    1400 
    1401 
    1402 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
    1403 {
    1404     Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
    1405     /*
    1406      * Convert to number.
    1407      */
    1408     uint64_t    u64 = 0;
    1409     char        ch;
    1410     while ((ch = *pszExpr) != '\0')
    1411     {
    1412         uint64_t    u64Prev = u64;
    1413         unsigned    u = ch - '0';
    1414         if (u < 10 && u < uBase)
    1415             u64 = u64 * uBase + u;
    1416         else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
    1417             u64 = u64 * uBase + u;
    1418         else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
    1419             u64 = u64 * uBase + u;
    1420         else
    1421             return VERR_PARSE_INVALID_NUMBER;
    1422 
    1423         /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
    1424         if (u64Prev != u64 / uBase)
    1425             return VERR_PARSE_NUMBER_TOO_BIG;
    1426 
    1427         /* next */
    1428         pszExpr++;
    1429     }
    1430 
    1431     /*
    1432      * Initialize the argument.
    1433      */
    1434     pArg->pDesc         = NULL;
    1435     pArg->pNext         = NULL;
    1436     pArg->enmType       = DBGCVAR_TYPE_NUMBER;
    1437     pArg->u.u64Number   = u64;
    1438     pArg->enmRangeType  = DBGCVAR_RANGE_NONE;
    1439     pArg->u64Range      = 0;
    1440 
    1441     return 0;
    1442 }
    1443 
    1444 
    1445 /**
    1446  * Match variable and variable descriptor, promoting the variable if necessary.
    1447  *
    1448  * @returns VBox status code.
    1449  * @param   pDbgc       Debug console instanace.
    1450  * @param   pVar        Variable.
    1451  * @param   pVarDesc    Variable descriptor.
    1452  */
    1453 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
    1454 {
    1455     /*
    1456      * (If match or promoted to match, return, else break.)
    1457      */
    1458     switch (pVarDesc->enmCategory)
    1459     {
    1460         /*
    1461          * Anything goes
    1462          */
    1463         case DBGCVAR_CAT_ANY:
    1464             return VINF_SUCCESS;
    1465 
    1466         /*
    1467          * Pointer with and without range.
    1468          * We can try resolve strings and symbols as symbols and
    1469          * promote numbers to flat GC pointers.
    1470          */
    1471         case DBGCVAR_CAT_POINTER_NO_RANGE:
    1472             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    1473                 return VERR_PARSE_NO_RANGE_ALLOWED;
    1474             /* fallthru */
    1475         case DBGCVAR_CAT_POINTER:
    1476             switch (pVar->enmType)
    1477             {
    1478                 case DBGCVAR_TYPE_GC_FLAT:
    1479                 case DBGCVAR_TYPE_GC_FAR:
    1480                 case DBGCVAR_TYPE_GC_PHYS:
    1481                 case DBGCVAR_TYPE_HC_FLAT:
    1482                 case DBGCVAR_TYPE_HC_FAR:
    1483                 case DBGCVAR_TYPE_HC_PHYS:
    1484                     return VINF_SUCCESS;
    1485 
    1486                 case DBGCVAR_TYPE_SYMBOL:
    1487                 case DBGCVAR_TYPE_STRING:
    1488                 {
    1489                     DBGCVAR Var;
    1490                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    1491                     if (VBOX_SUCCESS(rc))
    1492                     {
    1493                         /* deal with range */
    1494                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    1495                         {
    1496                             Var.enmRangeType = pVar->enmRangeType;
    1497                             Var.u64Range = pVar->u64Range;
    1498                         }
    1499                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    1500                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    1501                         *pVar = Var;
    1502                         return rc;
    1503                     }
    1504                     break;
    1505                 }
    1506 
    1507                 case DBGCVAR_TYPE_NUMBER:
    1508                 {
    1509                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    1510                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    1511                     pVar->u.GCFlat = GCPtr;
    1512                     return VINF_SUCCESS;
    1513                 }
    1514 
    1515                 default:
    1516                     break;
    1517             }
    1518             break;
    1519 
    1520         /*
    1521          * GC pointer with and without range.
    1522          * We can try resolve strings and symbols as symbols and
    1523          * promote numbers to flat GC pointers.
    1524          */
    1525         case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
    1526             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    1527                 return VERR_PARSE_NO_RANGE_ALLOWED;
    1528             /* fallthru */
    1529         case DBGCVAR_CAT_GC_POINTER:
    1530             switch (pVar->enmType)
    1531             {
    1532                 case DBGCVAR_TYPE_GC_FLAT:
    1533                 case DBGCVAR_TYPE_GC_FAR:
    1534                 case DBGCVAR_TYPE_GC_PHYS:
    1535                     return VINF_SUCCESS;
    1536 
    1537                 case DBGCVAR_TYPE_HC_FLAT:
    1538                 case DBGCVAR_TYPE_HC_FAR:
    1539                 case DBGCVAR_TYPE_HC_PHYS:
    1540                     return VERR_PARSE_CONVERSION_FAILED;
    1541 
    1542                 case DBGCVAR_TYPE_SYMBOL:
    1543                 case DBGCVAR_TYPE_STRING:
    1544                 {
    1545                     DBGCVAR Var;
    1546                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
    1547                     if (VBOX_SUCCESS(rc))
    1548                     {
    1549                         /* deal with range */
    1550                         if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    1551                         {
    1552                             Var.enmRangeType = pVar->enmRangeType;
    1553                             Var.u64Range = pVar->u64Range;
    1554                         }
    1555                         else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
    1556                             Var.enmRangeType = DBGCVAR_RANGE_NONE;
    1557                         *pVar = Var;
    1558                         return rc;
    1559                     }
    1560                     break;
    1561                 }
    1562 
    1563                 case DBGCVAR_TYPE_NUMBER:
    1564                 {
    1565                     RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
    1566                     pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
    1567                     pVar->u.GCFlat = GCPtr;
    1568                     return VINF_SUCCESS;
    1569                 }
    1570 
    1571                 default:
    1572                     break;
    1573             }
    1574             break;
    1575 
    1576         /*
    1577          * Number with or without a range.
    1578          * Numbers can be resolved from symbols, but we cannot demote a pointer
    1579          * to a number.
    1580          */
    1581         case DBGCVAR_CAT_NUMBER_NO_RANGE:
    1582             if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
    1583                 return VERR_PARSE_NO_RANGE_ALLOWED;
    1584             /* fallthru */
    1585         case DBGCVAR_CAT_NUMBER:
    1586             switch (pVar->enmType)
    1587             {
    1588                 case DBGCVAR_TYPE_NUMBER:
    1589                     return VINF_SUCCESS;
    1590 
    1591                 case DBGCVAR_TYPE_SYMBOL:
    1592                 case DBGCVAR_TYPE_STRING:
    1593                 {
    1594                     DBGCVAR Var;
    1595                     int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
    1596                     if (VBOX_SUCCESS(rc))
    1597                     {
    1598                         *pVar = Var;
    1599                         return rc;
    1600                     }
    1601                     break;
    1602                 }
    1603                 default:
    1604                     break;
    1605             }
    1606             break;
    1607 
    1608         /*
    1609          * Strings can easily be made from symbols (and of course strings).
    1610          * We could consider reformatting the addresses and numbers into strings later...
    1611          */
    1612         case DBGCVAR_CAT_STRING:
    1613             switch (pVar->enmType)
    1614             {
    1615                 case DBGCVAR_TYPE_SYMBOL:
    1616                     pVar->enmType = DBGCVAR_TYPE_STRING;
    1617                     /* fallthru */
    1618                 case DBGCVAR_TYPE_STRING:
    1619                     return VINF_SUCCESS;
    1620                 default:
    1621                     break;
    1622             }
    1623             break;
    1624 
    1625         /*
    1626          * Symol is pretty much the same thing as a string (at least until we actually implement it).
    1627          */
    1628         case DBGCVAR_CAT_SYMBOL:
    1629             switch (pVar->enmType)
    1630             {
    1631                 case DBGCVAR_TYPE_STRING:
    1632                     pVar->enmType = DBGCVAR_TYPE_SYMBOL;
    1633                     /* fallthru */
    1634                 case DBGCVAR_TYPE_SYMBOL:
    1635                     return VINF_SUCCESS;
    1636                 default:
    1637                     break;
    1638             }
    1639             break;
    1640 
    1641         /*
    1642          * Anything else is illegal.
    1643          */
    1644         default:
    1645             AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
    1646             break;
    1647     }
    1648 
    1649     return VERR_PARSE_NO_ARGUMENT_MATCH;
    1650 }
    1651 
    1652 
    1653 /**
    1654  * Matches a set of variables with a description set.
    1655  *
    1656  * This is typically used for routine arguments before a call. The effects in
    1657  * addition to the validation, is that some variables might be propagated to
    1658  * other types in order to match the description. The following transformations
    1659  * are supported:
    1660  *      - String reinterpreted as a symbol and resolved to a number or pointer.
    1661  *      - Number to a pointer.
    1662  *      - Pointer to a number.
    1663  * @returns 0 on success with paVars.
    1664  * @returns VBox error code for match errors.
    1665  */
    1666 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
    1667                                 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
    1668                                 PDBGCVAR paVars, unsigned cVars)
    1669 {
    1670     /*
    1671      * Just do basic min / max checks first.
    1672      */
    1673     if (cVars < cVarsMin)
    1674         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    1675     if (cVars > cVarsMax)
    1676         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1677 
    1678     /*
    1679      * Match the descriptors and actual variables.
    1680      */
    1681     PCDBGCVARDESC   pPrevDesc = NULL;
    1682     unsigned        cCurDesc = 0;
    1683     unsigned        iVar = 0;
    1684     unsigned        iVarDesc = 0;
    1685     while (iVar < cVars)
    1686     {
    1687         /* walk the descriptors */
    1688         if (iVarDesc >= cVarDescs)
    1689             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1690         if (    (    paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
    1691                 &&  &paVarDescs[iVarDesc - 1] != pPrevDesc)
    1692             ||  cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
    1693         {
    1694             iVarDesc++;
    1695             if (iVarDesc >= cVarDescs)
    1696                 return VERR_PARSE_TOO_MANY_ARGUMENTS;
    1697             cCurDesc = 0;
    1698         }
    1699 
    1700         /*
    1701          * Skip thru optional arguments until we find something which matches
    1702          * or can easily be promoted to what the descriptor want.
    1703          */
    1704         for (;;)
    1705         {
    1706             int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
    1707             if (VBOX_SUCCESS(rc))
    1708             {
    1709                 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
    1710                 cCurDesc++;
    1711                 break;
    1712             }
    1713 
    1714             /* can we advance? */
    1715             if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    1716                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1717             if (++iVarDesc >= cVarDescs)
    1718                 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
    1719             cCurDesc = 0;
    1720         }
    1721 
    1722         /* next var */
    1723         iVar++;
    1724     }
    1725 
    1726     /*
    1727      * Check that the rest of the descriptors are optional.
    1728      */
    1729     while (iVarDesc < cVarDescs)
    1730     {
    1731         if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
    1732             return VERR_PARSE_TOO_FEW_ARGUMENTS;
    1733         cCurDesc = 0;
    1734 
    1735         /* next */
    1736         iVarDesc++;
    1737     }
    1738 
    1739     return 0;
    1740 }
    1741 
    1742 
    1743 /**
    1744  * Evaluates one argument with respect to unary operators.
    1745  *
    1746  * @returns 0 on success. pResult contains the result.
    1747  * @returns VBox error code on parse or other evaluation error.
    1748  *
    1749  * @param   pDbgc       Debugger console instance data.
    1750  * @param   pszExpr     The expression string.
    1751  * @param   pResult     Where to store the result of the expression evaluation.
    1752  */
    1753 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    1754 {
    1755     Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    1756 
    1757     /*
    1758      * The state of the expression is now such that it will start by zero or more
    1759      * unary operators and being followed by an expression of some kind.
    1760      * The expression is either plain or in parenthesis.
    1761      *
    1762      * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
    1763      * ASSUME: unary operators are all of equal precedence.
    1764      */
    1765     int         rc = 0;
    1766     PCDBGCOP    pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
    1767     if (pOp)
    1768     {
    1769         /* binary operators means syntax error. */
    1770         if (pOp->fBinary)
    1771             return VERR_PARSE_UNEXPECTED_OPERATOR;
    1772 
    1773         /*
    1774          * If the next expression (the one following the unary operator) is in a
    1775          * parenthesis a full eval is needed. If not the unary eval will suffice.
    1776          */
    1777         /* calc and strip next expr. */
    1778         char *pszExpr2 = pszExpr + pOp->cchName;
    1779         while (isblank(*pszExpr2))
    1780             pszExpr2++;
    1781 
    1782         if (!*pszExpr2)
    1783             rc = VERR_PARSE_EMPTY_ARGUMENT;
    1784         else
    1785         {
    1786             DBGCVAR Arg;
    1787             if (*pszExpr2 == '(')
    1788                 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    1789             else
    1790                 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
    1791             if (VBOX_SUCCESS(rc))
    1792                 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
    1793         }
    1794     }
    1795     else
    1796     {
    1797         /*
    1798          * Didn't find any operators, so it we have to check if this can be an
    1799          * function call before assuming numeric or string expression.
    1800          *
    1801          * (ASSUMPTIONS:)
    1802          * A function name only contains alphanumerical chars and it can not start
    1803          * with a numerical character.
    1804          * Immediately following the name is a parenthesis which must over
    1805          * the remaining part of the expression.
    1806          */
    1807         bool    fExternal = *pszExpr == '.';
    1808         char   *pszFun    = fExternal ? pszExpr + 1 : pszExpr;
    1809         char   *pszFunEnd = NULL;
    1810         if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
    1811         {
    1812             pszFunEnd = pszExpr + 1;
    1813             while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
    1814                 pszFunEnd++;
    1815             if (*pszFunEnd != '(')
    1816                 pszFunEnd = NULL;
    1817         }
    1818 
    1819         if (pszFunEnd)
    1820         {
    1821             /*
    1822              * Ok, it's a function call.
    1823              */
    1824             if (fExternal)
    1825                 pszExpr++, cchExpr--;
    1826             PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
    1827             if (!pFun)
    1828                 return VERR_PARSE_FUNCTION_NOT_FOUND;
    1829             if (!pFun->pResultDesc)
    1830                 return VERR_PARSE_NOT_A_FUNCTION;
    1831 
    1832             /*
    1833              * Parse the expression in parenthesis.
    1834              */
    1835             cchExpr -= pszFunEnd - pszExpr;
    1836             pszExpr = pszFunEnd;
    1837             /** @todo implement multiple arguments. */
    1838             DBGCVAR     Arg;
    1839             rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
    1840             if (!rc)
    1841             {
    1842                 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
    1843                 if (!rc)
    1844                     rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
    1845             }
    1846             else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
    1847                 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
    1848         }
    1849         else
    1850         {
    1851             /*
    1852              * Didn't find any operators, so it must be a plain expression.
    1853              * This might be numeric or a string expression.
    1854              */
    1855             char ch  = pszExpr[0];
    1856             char ch2 = pszExpr[1];
    1857             if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
    1858                 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
    1859             else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
    1860                 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
    1861             else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
    1862                 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
    1863             /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
    1864             //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
    1865             //    rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
    1866             else
    1867             {
    1868                 /*
    1869                  * Hexadecimal number or a string?
    1870                  */
    1871                 char *psz = pszExpr;
    1872                 while (isxdigit(*psz))
    1873                     psz++;
    1874                 if (!*psz)
    1875                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    1876                 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
    1877                 {
    1878                     *psz = '\0';
    1879                     rc = dbgcEvalSubNum(pszExpr, 16, pResult);
    1880                 }
    1881                 else
    1882                     rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    1883             }
    1884         }
    1885     }
    1886 
    1887     return rc;
    1888 }
    1889 
    1890 
    1891 /**
    1892  * Evaluates one argument.
    1893  *
    1894  * @returns 0 on success. pResult contains the result.
    1895  * @returns VBox error code on parse or other evaluation error.
    1896  *
    1897  * @param   pDbgc       Debugger console instance data.
    1898  * @param   pszExpr     The expression string.
    1899  * @param   pResult     Where to store the result of the expression evaluation.
    1900  */
    1901 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    1902 {
    1903     Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
    1904     /*
    1905      * First we need to remove blanks in both ends.
    1906      * ASSUMES: There is no quoting unless the entire expression is a string.
    1907      */
    1908 
    1909     /* stripping. */
    1910     while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    1911         pszExpr[--cchExpr] = '\0';
    1912     while (isblank(*pszExpr))
    1913         pszExpr++, cchExpr--;
    1914     if (!*pszExpr)
    1915         return VERR_PARSE_EMPTY_ARGUMENT;
    1916 
    1917     /* it there is any kind of quoting in the expression, it's string meat. */
    1918     if (strpbrk(pszExpr, "\"'`"))
    1919         return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
    1920 
    1921     /*
    1922      * Check if there are any parenthesis which needs removing.
    1923      */
    1924     if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
    1925     {
    1926         do
    1927         {
    1928             unsigned cPar = 1;
    1929             char    *psz = pszExpr + 1;
    1930             char     ch;
    1931             while ((ch = *psz) != '\0')
    1932             {
    1933                 if (ch == '(')
    1934                     cPar++;
    1935                 else if (ch == ')')
    1936                 {
    1937                     if (cPar <= 0)
    1938                         return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1939                     cPar--;
    1940                     if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
    1941                         break;
    1942                 }
    1943                 /* next */
    1944                 psz++;
    1945             }
    1946             if (ch)
    1947                 break;
    1948 
    1949             /* remove the parenthesis. */
    1950             pszExpr++;
    1951             cchExpr -= 2;
    1952             pszExpr[cchExpr] = '\0';
    1953 
    1954             /* strip blanks. */
    1955             while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
    1956                 pszExpr[--cchExpr] = '\0';
    1957             while (isblank(*pszExpr))
    1958                 pszExpr++, cchExpr--;
    1959             if (!*pszExpr)
    1960                 return VERR_PARSE_EMPTY_ARGUMENT;
    1961         } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
    1962     }
    1963 
    1964     /* tabs to spaces. */
    1965     char *psz = pszExpr;
    1966     while ((psz = strchr(psz, '\t')) != NULL)
    1967         *psz = ' ';
    1968 
    1969     /*
    1970      * Now, we need to look for the binary operator with the lowest precedence.
    1971      *
    1972      * If there are no operators we're left with a simple expression which we
    1973      * evaluate with respect to unary operators
    1974      */
    1975     char       *pszOpSplit = NULL;
    1976     PCDBGCOP    pOpSplit = NULL;
    1977     unsigned    cBinaryOps = 0;
    1978     unsigned    cPar = 0;
    1979     char        ch;
    1980     char        chPrev = ' ';
    1981     bool        fBinary = false;
    1982     psz = pszExpr;
    1983 
    1984     while ((ch = *psz) != '\0')
    1985     {
    1986         //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
    1987         /*
    1988          * Parenthesis.
    1989          */
    1990         if (ch == '(')
    1991         {
    1992             cPar++;
    1993             fBinary = false;
    1994         }
    1995         else if (ch == ')')
    1996         {
    1997             if (cPar <= 0)
    1998                 return VERR_PARSE_UNBALANCED_PARENTHESIS;
    1999             cPar--;
    2000             fBinary = true;
    2001         }
    2002         /*
    2003          * Potential operator.
    2004          */
    2005         else if (cPar == 0 && !isblank(ch))
    2006         {
    2007             PCDBGCOP pOp = dbgcIsOpChar(ch)
    2008                          ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
    2009                          : NULL;
    2010             if (pOp)
    2011             {
    2012                 /* If not the right kind of operator we've got a syntax error. */
    2013                 if (pOp->fBinary != fBinary)
    2014                     return VERR_PARSE_UNEXPECTED_OPERATOR;
    2015 
    2016                 /*
    2017                  * Update the parse state and skip the operator.
    2018                  */
    2019                 if (!pOpSplit)
    2020                 {
    2021                     pOpSplit = pOp;
    2022                     pszOpSplit = psz;
    2023                     cBinaryOps = fBinary;
    2024                 }
    2025                 else if (fBinary)
    2026                 {
    2027                     cBinaryOps++;
    2028                     if (pOp->iPrecedence >= pOpSplit->iPrecedence)
    2029                     {
    2030                         pOpSplit = pOp;
    2031                         pszOpSplit = psz;
    2032                     }
    2033                 }
    2034 
    2035                 psz += pOp->cchName - 1;
    2036                 fBinary = false;
    2037             }
    2038             else
    2039                 fBinary = true;
    2040         }
    2041 
    2042         /* next */
    2043         psz++;
    2044         chPrev = ch;
    2045     } /* parse loop. */
    2046 
    2047 
    2048     /*
    2049      * Either we found an operator to divide the expression by
    2050      * or we didn't find any. In the first case it's divide and
    2051      * conquer. In the latter it's a single expression which
    2052      * needs dealing with its unary operators if any.
    2053      */
    2054     int rc;
    2055     if (    cBinaryOps
    2056         &&  pOpSplit->fBinary)
    2057     {
    2058         /* process 1st sub expression. */
    2059         *pszOpSplit = '\0';
    2060         DBGCVAR     Arg1;
    2061         rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
    2062         if (VBOX_SUCCESS(rc))
    2063         {
    2064             /* process 2nd sub expression. */
    2065             char       *psz2 = pszOpSplit + pOpSplit->cchName;
    2066             DBGCVAR     Arg2;
    2067             rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
    2068             if (VBOX_SUCCESS(rc))
    2069                 /* apply the operator. */
    2070                 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
    2071         }
    2072     }
    2073     else if (cBinaryOps)
    2074     {
    2075         /* process sub expression. */
    2076         pszOpSplit += pOpSplit->cchName;
    2077         DBGCVAR     Arg;
    2078         rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
    2079         if (VBOX_SUCCESS(rc))
    2080             /* apply the operator. */
    2081             rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
    2082     }
    2083     else
    2084         /* plain expression or using unary operators perhaps with paratheses. */
    2085         rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
    2086 
    2087     return rc;
    2088 }
    2089 
    2090 
    2091 /**
    2092  * Parses the arguments of one command.
    2093  *
    2094  * @returns 0 on success.
    2095  * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
    2096  * @param   pDbgc       Debugger console instance data.
    2097  * @param   pCmd        Pointer to the command descriptor.
    2098  * @param   pszArg      Pointer to the arguments to parse.
    2099  * @param   paArgs      Where to store the parsed arguments.
    2100  * @param   cArgs       Size of the paArgs array.
    2101  * @param   pcArgs      Where to store the number of arguments.
    2102  *                      In the event of an error this is used to store the index of the offending argument.
    2103  */
    2104 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
    2105 {
    2106     Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
    2107     /*
    2108      * Check if we have any argument and if the command takes any.
    2109      */
    2110     *pcArgs = 0;
    2111     /* strip leading blanks. */
    2112     while (*pszArgs && isblank(*pszArgs))
    2113         pszArgs++;
    2114     if (!*pszArgs)
    2115     {
    2116         if (!pCmd->cArgsMin)
    2117             return 0;
    2118         return VERR_PARSE_TOO_FEW_ARGUMENTS;
    2119     }
    2120     /** @todo fixme - foo() doesn't work. */
    2121     if (!pCmd->cArgsMax)
    2122         return VERR_PARSE_TOO_MANY_ARGUMENTS;
    2123 
    2124     /*
    2125      * This is a hack, it's "temporary" and should go away "when" the parser is
    2126      * modified to match arguments while parsing.
    2127      */
    2128     if (    pCmd->cArgsMax == 1
    2129         &&  pCmd->cArgsMin == 1
    2130         &&  pCmd->cArgDescs == 1
    2131         &&  pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
    2132         &&  cArgs >= 1)
    2133     {
    2134         *pcArgs = 1;
    2135         RTStrStripR(pszArgs);
    2136         return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
    2137     }
    2138 
    2139 
    2140     /*
    2141      * The parse loop.
    2142      */
    2143     PDBGCVAR        pArg0 = &paArgs[0];
    2144     PDBGCVAR        pArg = pArg0;
    2145     *pcArgs = 0;
    2146     do
    2147     {
    2148         /*
    2149          * Can we have another argument?
    2150          */
    2151         if (*pcArgs >= pCmd->cArgsMax)
    2152             return VERR_PARSE_TOO_MANY_ARGUMENTS;
    2153         if (pArg >= &paArgs[cArgs])
    2154             return VERR_PARSE_ARGUMENT_OVERFLOW;
    2155 
    2156         /*
    2157          * Find the end of the argument.
    2158          */
    2159         int     cPar    = 0;
    2160         char    chQuote = '\0';
    2161         char   *pszEnd  = NULL;
    2162         char   *psz     = pszArgs;
    2163         char    ch;
    2164         bool    fBinary = false;
    2165         for (;;)
    2166         {
    2167             /*
    2168              * Check for the end.
    2169              */
    2170             if ((ch = *psz) == '\0')
    2171             {
    2172                 if (chQuote)
    2173                     return VERR_PARSE_UNBALANCED_QUOTE;
    2174                 if (cPar)
    2175                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    2176                 pszEnd = psz;
    2177                 break;
    2178             }
    2179             /*
    2180              * When quoted we ignore everything but the quotation char.
    2181              * We use the REXX way of escaping the quotation char, i.e. double occurence.
    2182              */
    2183             else if (ch == '\'' || ch == '"' || ch == '`')
    2184             {
    2185                 if (chQuote)
    2186                 {
    2187                     /* end quote? */
    2188                     if (ch == chQuote)
    2189                     {
    2190                         if (psz[1] == ch)
    2191                             psz++;          /* skip the escaped quote char */
    2192                         else
    2193                             chQuote = '\0'; /* end of quoted string. */
    2194                     }
    2195                 }
    2196                 else
    2197                     chQuote = ch;           /* open new quote */
    2198             }
    2199             /*
    2200              * Parenthesis can of course be nested.
    2201              */
    2202             else if (ch == '(')
    2203             {
    2204                 cPar++;
    2205                 fBinary = false;
    2206             }
    2207             else if (ch == ')')
    2208             {
    2209                 if (!cPar)
    2210                     return VERR_PARSE_UNBALANCED_PARENTHESIS;
    2211                 cPar--;
    2212                 fBinary = true;
    2213             }
    2214             else if (!chQuote && !cPar)
    2215             {
    2216                 /*
    2217                  * Encountering blanks may mean the end of it all. A binary operator
    2218                  * will force continued parsing.
    2219                  */
    2220                 if (isblank(*psz))
    2221                 {
    2222                     pszEnd = psz++;         /* just in case. */
    2223                     while (isblank(*psz))
    2224                         psz++;
    2225                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    2226                     if (!pOp || pOp->fBinary != fBinary)
    2227                         break;              /* the end. */
    2228                     psz += pOp->cchName;
    2229                     while (isblank(*psz))   /* skip blanks so we don't get here again */
    2230                         psz++;
    2231                     fBinary = false;
    2232                     continue;
    2233                 }
    2234 
    2235                 /*
    2236                  * Look for operators without a space up front.
    2237                  */
    2238                 if (dbgcIsOpChar(*psz))
    2239                 {
    2240                     PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
    2241                     if (pOp)
    2242                     {
    2243                         if (pOp->fBinary != fBinary)
    2244                         {
    2245                             pszEnd = psz;
    2246                             /** @todo this is a parsing error really. */
    2247                             break;              /* the end. */
    2248                         }
    2249                         psz += pOp->cchName;
    2250                         while (isblank(*psz))   /* skip blanks so we don't get here again */
    2251                             psz++;
    2252                         fBinary = false;
    2253                         continue;
    2254                     }
    2255                 }
    2256                 fBinary = true;
    2257             }
    2258 
    2259             /* next char */
    2260             psz++;
    2261         }
    2262         *pszEnd = '\0';
    2263         /* (psz = next char to process) */
    2264 
    2265         /*
    2266          * Parse and evaluate the argument.
    2267          */
    2268         int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
    2269         if (VBOX_FAILURE(rc))
    2270             return rc;
    2271 
    2272         /*
    2273          * Next.
    2274          */
    2275         pArg++;
    2276         (*pcArgs)++;
    2277         pszArgs = psz;
    2278         while (*pszArgs && isblank(*pszArgs))
    2279             pszArgs++;
    2280     } while (*pszArgs);
    2281 
    2282     /*
    2283      * Match the arguments.
    2284      */
    2285     return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
    2286 }
    2287 
    2288 
    2289 /**
    2290  * Process one command.
    2291  *
    2292  * @returns VBox status code. Any error indicates the termination of the console session.
    2293  * @param   pDbgc   Debugger console instance data.
    2294  * @param   pszCmd  Pointer to the command.
    2295  * @param   cchCmd  Length of the command.
    2296  */
    2297 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    2298 {
    2299     char *pszCmdInput = pszCmd;
    2300 
    2301     /*
    2302      * Skip blanks.
    2303      */
    2304     while (isblank(*pszCmd))
    2305         pszCmd++, cchCmd--;
    2306 
    2307     /* external command? */
    2308     bool fExternal = *pszCmd == '.';
    2309     if (fExternal)
    2310         pszCmd++, cchCmd--;
    2311 
    2312     /*
    2313      * Find arguments.
    2314      */
    2315     char *pszArgs = pszCmd;
    2316     while (isalnum(*pszArgs))
    2317         pszArgs++;
    2318     if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
    2319     {
    2320         pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
    2321         return 0;
    2322     }
    2323 
    2324     /*
    2325      * Find the command.
    2326      */
    2327     PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
    2328     if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
    2329         return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
    2330 
    2331     /*
    2332      * Parse arguments (if any).
    2333      */
    2334     unsigned    cArgs;
    2335     int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
    2336 
    2337     /*
    2338      * Execute the command.
    2339      */
    2340     if (!rc)
    2341     {
    2342         rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
    2343     }
    2344     else
    2345     {
    2346         /* report parse / eval error. */
    2347         switch (rc)
    2348         {
    2349             case VERR_PARSE_TOO_FEW_ARGUMENTS:
    2350                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2351                     "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
    2352                 break;
    2353             case VERR_PARSE_TOO_MANY_ARGUMENTS:
    2354                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2355                     "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
    2356                 break;
    2357             case VERR_PARSE_ARGUMENT_OVERFLOW:
    2358                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2359                     "Syntax error: Too many arguments.\n");
    2360                 break;
    2361             case VERR_PARSE_UNBALANCED_QUOTE:
    2362                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2363                     "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
    2364                 break;
    2365             case VERR_PARSE_UNBALANCED_PARENTHESIS:
    2366                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2367                     "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
    2368                 break;
    2369             case VERR_PARSE_EMPTY_ARGUMENT:
    2370                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2371                     "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
    2372                 break;
    2373             case VERR_PARSE_UNEXPECTED_OPERATOR:
    2374                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2375                     "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
    2376                 break;
    2377             case VERR_PARSE_INVALID_NUMBER:
    2378                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2379                     "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
    2380                 break;
    2381             case VERR_PARSE_NUMBER_TOO_BIG:
    2382                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2383                     "Error: Numeric overflow (argument %d).\n", cArgs);
    2384                 break;
    2385             case VERR_PARSE_INVALID_OPERATION:
    2386                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2387                     "Error: Invalid operation attempted (argument %d).\n", cArgs);
    2388                 break;
    2389             case VERR_PARSE_FUNCTION_NOT_FOUND:
    2390                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2391                     "Error: Function not found (argument %d).\n", cArgs);
    2392                 break;
    2393             case VERR_PARSE_NOT_A_FUNCTION:
    2394                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2395                     "Error: The function specified is not a function (argument %d).\n", cArgs);
    2396                 break;
    2397             case VERR_PARSE_NO_MEMORY:
    2398                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2399                     "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
    2400                 break;
    2401             case VERR_PARSE_INCORRECT_ARG_TYPE:
    2402                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2403                     "Error: Incorrect argument type (argument %d?).\n", cArgs);
    2404                 break;
    2405             case VERR_PARSE_VARIABLE_NOT_FOUND:
    2406                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2407                     "Error: An undefined variable was referenced (argument %d).\n", cArgs);
    2408                 break;
    2409             case VERR_PARSE_CONVERSION_FAILED:
    2410                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2411                     "Error: A conversion between two types failed (argument %d).\n", cArgs);
    2412                 break;
    2413             case VERR_PARSE_NOT_IMPLEMENTED:
    2414                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2415                     "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
    2416                 break;
    2417             case VERR_PARSE_BAD_RESULT_TYPE:
    2418                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2419                     "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
    2420                 break;
    2421             case VERR_PARSE_WRITEONLY_SYMBOL:
    2422                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2423                     "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
    2424                 break;
    2425 
    2426             default:
    2427                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2428                     "Error: Unknown error %d!\n", rc);
    2429                 return rc;
    2430         }
    2431 
    2432         /*
    2433          * Parse errors are non fatal.
    2434          */
    2435         if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
    2436             rc = 0;
    2437     }
    2438 
    2439     return rc;
    2440 }
    2441 
    2442 
    2443 /**
    2444  * Process all commands current in the buffer.
    2445  *
    2446  * @returns VBox status code. Any error indicates the termination of the console session.
    2447  * @param   pDbgc   Debugger console instance data.
    2448  */
    2449 static int dbgcProcessCommands(PDBGC pDbgc)
    2450 {
    2451     int rc = 0;
    2452     while (pDbgc->cInputLines)
    2453     {
    2454         /*
    2455          * Empty the log buffer if we're hooking the log.
    2456          */
    2457         if (pDbgc->fLog)
    2458         {
    2459             rc = dbgcProcessLog(pDbgc);
    2460             if (VBOX_FAILURE(rc))
    2461                 break;
    2462         }
    2463 
    2464         if (pDbgc->iRead == pDbgc->iWrite)
    2465         {
    2466             AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
    2467             pDbgc->cInputLines = 0;
    2468             return 0;
    2469         }
    2470 
    2471         /*
    2472          * Copy the command to the parse buffer.
    2473          */
    2474         char    ch;
    2475         char   *psz = &pDbgc->achInput[pDbgc->iRead];
    2476         char   *pszTrg = &pDbgc->achScratch[0];
    2477         while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
    2478         {
    2479             if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
    2480                 psz = &pDbgc->achInput[0];
    2481 
    2482             if (psz == &pDbgc->achInput[pDbgc->iWrite])
    2483             {
    2484                 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
    2485                 pDbgc->cInputLines = 0;
    2486                 return 0;
    2487             }
    2488 
    2489             pszTrg++;
    2490         }
    2491         *pszTrg = '\0';
    2492 
    2493         /*
    2494          * Advance the buffer.
    2495          */
    2496         pDbgc->iRead = psz - &pDbgc->achInput[0];
    2497         if (ch == '\n')
    2498             pDbgc->cInputLines--;
    2499 
    2500         /*
    2501          * Parse and execute this command.
    2502          */
    2503         pDbgc->pszScratch = psz;
    2504         pDbgc->iArg       = 0;
    2505         rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
    2506         if (rc)
    2507             break;
    2508     }
    2509 
    2510     return rc;
    2511 }
    2512 
    2513 
    2514 /**
    2515  * Reads input, parses it and executes commands on '\n'.
    2516  *
    2517  * @returns VBox status.
    2518  * @param   pDbgc   Debugger console instance data.
    2519  */
    2520 static int dbgcProcessInput(PDBGC pDbgc)
    2521 {
    2522     /*
    2523      * We know there's input ready, so let's read it first.
    2524      */
    2525     int rc = dbgcInputRead(pDbgc);
    2526     if (VBOX_FAILURE(rc))
    2527         return rc;
    2528 
    2529     /*
    2530      * Now execute any ready commands.
    2531      */
    2532     if (pDbgc->cInputLines)
    2533     {
    2534         /** @todo this fReady stuff is broken. */
    2535         pDbgc->fReady = false;
    2536         rc = dbgcProcessCommands(pDbgc);
    2537         if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
    2538             pDbgc->fReady = true;
    2539         if (    VBOX_SUCCESS(rc)
    2540             &&  pDbgc->iRead == pDbgc->iWrite
    2541             &&  pDbgc->fReady)
    2542             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    2543     }
    2544 
    2545     return rc;
    2546 }
    2547 
    2548 
    2549 /**
    2550  * Gets the event context identifier string.
    2551  * @returns Read only string.
    2552  * @param   enmCtx          The context.
    2553  */
    2554 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
    2555 {
    2556     switch (enmCtx)
    2557     {
    2558         case DBGFEVENTCTX_RAW:      return "raw";
    2559         case DBGFEVENTCTX_REM:      return "rem";
    2560         case DBGFEVENTCTX_HWACCL:   return "hwaccl";
    2561         case DBGFEVENTCTX_HYPER:    return "hyper";
    2562         case DBGFEVENTCTX_OTHER:    return "other";
    2563 
    2564         case DBGFEVENTCTX_INVALID:  return "!Invalid Event Ctx!";
    2565         default:
    2566             AssertMsgFailed(("enmCtx=%d\n", enmCtx));
    2567             return "!Unknown Event Ctx!";
    2568     }
    2569 }
    2570 
    2571 
    2572 /**
    2573  * Processes debugger events.
    2574  *
    2575  * @returns VBox status.
    2576  * @param   pDbgc   DBGC Instance data.
    2577  * @param   pEvent  Pointer to event data.
    2578  */
    2579 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
    2580 {
    2581     /*
    2582      * Flush log first.
    2583      */
    2584     if (pDbgc->fLog)
    2585     {
    2586         int rc = dbgcProcessLog(pDbgc);
    2587         if (VBOX_FAILURE(rc))
    2588             return rc;
    2589     }
    2590 
    2591     /*
    2592      * Process the event.
    2593      */
    2594     pDbgc->pszScratch = &pDbgc->achInput[0];
    2595     pDbgc->iArg       = 0;
    2596     bool fPrintPrompt = true;
    2597     int rc = VINF_SUCCESS;
    2598     switch (pEvent->enmType)
    2599     {
    2600         /*
    2601          * The first part is events we have initiated with commands.
    2602          */
    2603         case DBGFEVENT_HALT_DONE:
    2604         {
    2605             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
    2606                                          pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
    2607             pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
    2608             if (VBOX_SUCCESS(rc))
    2609                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2610             break;
    2611         }
    2612 
    2613 
    2614         /*
    2615          * The second part is events which can occur at any time.
    2616          */
    2617         case DBGFEVENT_FATAL_ERROR:
    2618         {
    2619             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
    2620                                          dbgcGetEventCtx(pEvent->enmCtx));
    2621             pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
    2622             if (VBOX_SUCCESS(rc))
    2623                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2624             break;
    2625         }
    2626 
    2627         case DBGFEVENT_BREAKPOINT:
    2628         case DBGFEVENT_BREAKPOINT_HYPER:
    2629         {
    2630             bool fRegCtxGuest = pDbgc->fRegCtxGuest;
    2631             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
    2632 
    2633             rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
    2634             switch (rc)
    2635             {
    2636                 case VERR_DBGC_BP_NOT_FOUND:
    2637                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
    2638                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2639                     break;
    2640 
    2641                 case VINF_DBGC_BP_NO_COMMAND:
    2642                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
    2643                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2644                     break;
    2645 
    2646                 case VINF_BUFFER_OVERFLOW:
    2647                     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
    2648                                                  pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
    2649                     break;
    2650 
    2651                 default:
    2652                     break;
    2653             }
    2654             if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
    2655                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2656             else
    2657                 pDbgc->fRegCtxGuest = fRegCtxGuest;
    2658             break;
    2659         }
    2660 
    2661         case DBGFEVENT_STEPPED:
    2662         case DBGFEVENT_STEPPED_HYPER:
    2663         {
    2664             pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
    2665 
    2666             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
    2667             if (VBOX_SUCCESS(rc))
    2668                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2669             break;
    2670         }
    2671 
    2672         case DBGFEVENT_ASSERTION_HYPER:
    2673         {
    2674             pDbgc->fRegCtxGuest = false;
    2675 
    2676             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2677                                          "\ndbgf event: Hypervisor Assertion! (%s)\n"
    2678                                          "%s"
    2679                                          "%s"
    2680                                          "\n",
    2681                                          dbgcGetEventCtx(pEvent->enmCtx),
    2682                                          pEvent->u.Assert.pszMsg1,
    2683                                          pEvent->u.Assert.pszMsg2);
    2684             if (VBOX_SUCCESS(rc))
    2685                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2686             break;
    2687         }
    2688 
    2689         case DBGFEVENT_DEV_STOP:
    2690         {
    2691             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2692                                          "\n"
    2693                                          "dbgf event: DBGFSTOP (%s)\n"
    2694                                          "File:     %s\n"
    2695                                          "Line:     %d\n"
    2696                                          "Function: %s\n",
    2697                                          dbgcGetEventCtx(pEvent->enmCtx),
    2698                                          pEvent->u.Src.pszFile,
    2699                                          pEvent->u.Src.uLine,
    2700                                          pEvent->u.Src.pszFunction);
    2701             if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
    2702                 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2703                                          "Message:  %s\n",
    2704                                              pEvent->u.Src.pszMessage);
    2705             if (VBOX_SUCCESS(rc))
    2706                 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
    2707             break;
    2708         }
    2709 
    2710 
    2711         case DBGFEVENT_INVALID_COMMAND:
    2712         {
    2713             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
    2714             fPrintPrompt = !pDbgc->fReady;
    2715             break;
    2716         }
    2717 
    2718         case DBGFEVENT_TERMINATING:
    2719         {
    2720             pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
    2721             rc = VERR_GENERAL_FAILURE;
    2722             break;
    2723         }
    2724 
    2725 
    2726         default:
    2727         {
    2728             rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
    2729             fPrintPrompt = !pDbgc->fReady;
    2730             break;
    2731         }
    2732     }
    2733 
    2734     /*
    2735      * Prompt, anyone?
    2736      */
    2737     if (fPrintPrompt && VBOX_SUCCESS(rc))
    2738     {
    2739         rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
    2740     }
    2741 
    2742     return rc;
    2743 }
    2744 
    2745 
    2746 
    2747 
    2748 
    2749 /**
    2750  * Make a console instance.
    2751  *
    2752  * This will not return until either an 'exit' command is issued or a error code
    2753  * indicating connection loss is encountered.
    2754  *
    2755  * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
    2756  * @returns The VBox status code causing the console termination.
    2757  *
    2758  * @param   pVM         VM Handle.
    2759  * @param   pBack       Pointer to the backend structure. This must contain
    2760  *                      a full set of function pointers to service the console.
    2761  * @param   fFlags      Reserved, must be zero.
    2762  * @remark  A forced termination of the console is easiest done by forcing the
    2763  *          callbacks to return fatal failures.
    2764  */
    2765 DBGDECL(int)    DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
    2766 {
    2767     /*
    2768      * Validate input.
    2769      */
    2770     AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
    2771     AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
    2772     AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
    2773 
    2774     /*
    2775      * Allocate and initialize instance data
    2776      */
    2777     PDBGC   pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
    2778     if (!pDbgc)
    2779         return VERR_NO_MEMORY;
    2780 
     649/**
     650 * Initializes the Command Helpers for a DBGC instance.
     651 *
     652 * @param   pDbgc   Pointer to the DBGC instance.
     653 */
     654void dbgcInitCmdHlp(PDBGC pDbgc)
     655{
    2781656    pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    2782657    pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
     
    2790665    pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    2791666    pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
    2792     pDbgc->pBack            = pBack;
    2793     pDbgc->pVM              = NULL;
    2794     pDbgc->pszEmulation     = "CodeView/WinDbg";
    2795     pDbgc->paEmulationCmds  = &g_aCmdsCodeView[0];
    2796     pDbgc->cEmulationCmds   = g_cCmdsCodeView;
    2797     //pDbgc->fLog             = false;
    2798     pDbgc->fRegCtxGuest     = true;
    2799     pDbgc->fRegTerse        = true;
    2800     //pDbgc->DisasmPos        = {0};
    2801     //pDbgc->SourcePos        = {0};
    2802     //pDbgc->DumpPos          = {0};
    2803     //pDbgc->cbDumpElement    = 0;
    2804     //pDbgc->cVars            = 0;
    2805     //pDbgc->paVars           = NULL;
    2806     //pDbgc->pFirstBp         = NULL;
    2807     //pDbgc->uInputZero       = 0;
    2808     //pDbgc->iRead            = 0;
    2809     //pDbgc->iWrite           = 0;
    2810     //pDbgc->cInputLines      = 0;
    2811     //pDbgc->fInputOverflow   = false;
    2812     pDbgc->fReady           = true;
    2813     pDbgc->pszScratch       = &pDbgc->achScratch[0];
    2814     //pDbgc->iArg             = 0;
    2815     //pDbgc->rcOutput         = 0;
    2816 
    2817     dbgcInitOpCharBitMap();
    2818 
    2819     /*
    2820      * Print welcome message.
    2821      */
    2822     int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2823         "Welcome to the VirtualBox Debugger!\n");
    2824     if (VBOX_FAILURE(rc))
    2825         goto l_failure;
    2826 
    2827     /*
    2828      * Attach to the VM.
    2829      */
    2830     rc = DBGFR3Attach(pVM);
    2831     if (VBOX_FAILURE(rc))
    2832     {
    2833         rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
    2834         goto l_failure;
    2835     }
    2836     pDbgc->pVM = pVM;
    2837 
    2838     /*
    2839      * Print commandline and auto select result.
    2840      */
    2841     rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
    2842         "Current VM is %08x\n" /** @todo get and print the VM name! */
    2843         "VBoxDbg> ",
    2844         pDbgc->pVM);
    2845     if (VBOX_FAILURE(rc))
    2846         goto l_failure;
    2847 
    2848     /*
    2849      * Main Debugger Loop.
    2850      *
    2851      * This loop will either block on waiting for input or on waiting on
    2852      * debug events. If we're forwarding the log we cannot wait for long
    2853      * before we must flush the log.
    2854      */
    2855     for (rc = 0;;)
    2856     {
    2857         if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
    2858         {
    2859             /*
    2860              * Wait for a debug event.
    2861              */
    2862             PCDBGFEVENT pEvent;
    2863             rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
    2864             if (VBOX_SUCCESS(rc))
    2865             {
    2866                 rc = dbgcProcessEvent(pDbgc, pEvent);
    2867                 if (VBOX_FAILURE(rc))
    2868                     break;
    2869             }
    2870             else if (rc != VERR_TIMEOUT)
    2871                 break;
    2872 
    2873             /*
    2874              * Check for input.
    2875              */
    2876             if (pBack->pfnInput(pDbgc->pBack, 0))
    2877             {
    2878                 rc = dbgcProcessInput(pDbgc);
    2879                 if (VBOX_FAILURE(rc))
    2880                     break;
    2881             }
    2882         }
    2883         else
    2884         {
    2885             /*
    2886              * Wait for input. If Logging is enabled we'll only wait very briefly.
    2887              */
    2888             if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
    2889             {
    2890                 rc = dbgcProcessInput(pDbgc);
    2891                 if (VBOX_FAILURE(rc))
    2892                     break;
    2893             }
    2894         }
    2895 
    2896         /*
    2897          * Forward log output.
    2898          */
    2899         if (pDbgc->fLog)
    2900         {
    2901             rc = dbgcProcessLog(pDbgc);
    2902             if (VBOX_FAILURE(rc))
    2903                 break;
    2904         }
    2905     }
    2906 
    2907 
    2908 l_failure:
    2909     /*
    2910      * Cleanup console debugger session.
    2911      */
    2912     /* Disable log hook. */
    2913     if (pDbgc->fLog)
    2914     {
    2915 
    2916     }
    2917 
    2918     /* Detach from the VM. */
    2919     if (pDbgc->pVM)
    2920         DBGFR3Detach(pDbgc->pVM);
    2921 
    2922     /* finally, free the instance memory. */
    2923     RTMemFree(pDbgc);
    2924 
    2925     return rc;
    2926 }
    2927 
     667}
     668
  • trunk/src/VBox/Debugger/DBGCInternal.h

    r5675 r5676  
    341341int     dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress);
    342342
    343 int         dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
     343int     dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
     344int     dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
     345
     346int     dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
    344347PCDBGCSYM   dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol);
    345348PCDBGCOP    dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev);
     
    350353DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
    351354DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
     355
     356void    dbgcInitCmdHlp(PDBGC pDbgc);
    352357
    353358
  • trunk/src/VBox/Debugger/DBGConsole.cpp

    r5675 r5676  
    129129
    130130/*******************************************************************************
    131 *   Internal Functions                                                         *
    132 *******************************************************************************/
    133 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);
    134 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);
    135 
    136 
    137 /*******************************************************************************
    138131*   Global Variables                                                           *
    139132*******************************************************************************/
     
    142135
    143136
    144 
    145 
    146 
    147 
    148 
    149 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    150 //
    151 //
    152 //      C a l l b a c k   H e l p e r s
    153 //
    154 //
    155 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
    156 
    157 
    158 
    159 /**
    160  * Command helper for writing text to the debug console.
    161  *
    162  * @returns VBox status.
    163  * @param   pCmdHlp     Pointer to the command callback structure.
    164  * @param   pvBuf       What to write.
    165  * @param   cbBuf       Number of bytes to write.
    166  * @param   pcbWritten  Where to store the number of bytes actually written.
    167  *                      If NULL the entire buffer must be successfully written.
    168  */
    169 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
    170 {
    171     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    172     return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
    173 }
    174 
    175 
    176 /**
    177  * Command helper for writing formatted text to the debug console.
    178  *
    179  * @returns VBox status.
    180  * @param   pCmdHlp     Pointer to the command callback structure.
    181  * @param   pcb         Where to store the number of bytes written.
    182  * @param   pszFormat   The format string.
    183  *                      This is using the log formatter, so it's format extensions can be used.
    184  * @param   ...         Arguments specified in the format string.
    185  */
    186 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
    187 {
    188     /*
    189      * Do the formatting and output.
    190      */
    191     va_list args;
    192     va_start(args, pszFormat);
    193     int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
    194     va_end(args);
    195 
    196     return rc;
    197 }
    198 
    199 /**
    200  * Callback to format non-standard format specifiers.
    201  *
    202  * @returns The number of bytes formatted.
    203  * @param   pvArg           Formatter argument.
    204  * @param   pfnOutput       Pointer to output function.
    205  * @param   pvArgOutput     Argument for the output function.
    206  * @param   ppszFormat      Pointer to the format string pointer. Advance this till the char
    207  *                          after the format specifier.
    208  * @param   pArgs           Pointer to the argument list. Use this to fetch the arguments.
    209  * @param   cchWidth        Format Width. -1 if not specified.
    210  * @param   cchPrecision    Format Precision. -1 if not specified.
    211  * @param   fFlags          Flags (RTSTR_NTFS_*).
    212  * @param   chArgSize       The argument size specifier, 'l' or 'L'.
    213  */
    214 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
    215                                                 const char **ppszFormat, va_list *pArgs, int cchWidth,
    216                                                 int cchPrecision, unsigned fFlags, char chArgSize)
    217 {
    218     NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
    219     if (**ppszFormat != 'D')
    220     {
    221         (*ppszFormat)++;
    222         return 0;
    223     }
    224 
    225     (*ppszFormat)++;
    226     switch (**ppszFormat)
    227     {
    228         /*
    229          * Print variable without range.
    230          * The argument is a const pointer to the variable.
    231          */
    232         case 'V':
    233         {
    234             (*ppszFormat)++;
    235             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    236             switch (pVar->enmType)
    237             {
    238                 case DBGCVAR_TYPE_GC_FLAT:
    239                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
    240                 case DBGCVAR_TYPE_GC_FAR:
    241                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
    242                 case DBGCVAR_TYPE_GC_PHYS:
    243                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
    244                 case DBGCVAR_TYPE_HC_FLAT:
    245                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
    246                 case DBGCVAR_TYPE_HC_FAR:
    247                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
    248                 case DBGCVAR_TYPE_HC_PHYS:
    249                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
    250                 case DBGCVAR_TYPE_STRING:
    251                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    252                 case DBGCVAR_TYPE_NUMBER:
    253                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
    254 
    255                 case DBGCVAR_TYPE_UNKNOWN:
    256                 default:
    257                     return pfnOutput(pvArgOutput, "??", 2);
    258             }
    259         }
    260 
    261         /*
    262          * Print variable with range.
    263          * The argument is a const pointer to the variable.
    264          */
    265         case 'v':
    266         {
    267             (*ppszFormat)++;
    268             PCDBGCVAR   pVar = va_arg(*pArgs, PCDBGCVAR);
    269 
    270             char szRange[32];
    271             switch (pVar->enmRangeType)
    272             {
    273                 case DBGCVAR_RANGE_NONE:
    274                     szRange[0] = '\0';
    275                     break;
    276                 case DBGCVAR_RANGE_ELEMENTS:
    277                     RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
    278                     break;
    279                 case DBGCVAR_RANGE_BYTES:
    280                     RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
    281                     break;
    282             }
    283 
    284             switch (pVar->enmType)
    285             {
    286                 case DBGCVAR_TYPE_GC_FLAT:
    287                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
    288                 case DBGCVAR_TYPE_GC_FAR:
    289                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
    290                 case DBGCVAR_TYPE_GC_PHYS:
    291                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
    292                 case DBGCVAR_TYPE_HC_FLAT:
    293                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
    294                 case DBGCVAR_TYPE_HC_FAR:
    295                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
    296                 case DBGCVAR_TYPE_HC_PHYS:
    297                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
    298                 case DBGCVAR_TYPE_STRING:
    299                     return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
    300                 case DBGCVAR_TYPE_NUMBER:
    301                     return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
    302 
    303                 case DBGCVAR_TYPE_UNKNOWN:
    304                 default:
    305                     return pfnOutput(pvArgOutput, "??", 2);
    306             }
    307         }
    308 
    309         default:
    310             AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
    311             return 0;
    312     }
    313 }
    314 
    315 
    316 /**
    317  * Output callback.
    318  *
    319  * @returns number of bytes written.
    320  * @param   pvArg       User argument.
    321  * @param   pachChars   Pointer to an array of utf-8 characters.
    322  * @param   cbChars     Number of bytes in the character array pointed to by pachChars.
    323  */
    324 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
    325 {
    326     PDBGC   pDbgc = (PDBGC)pvArg;
    327     if (cbChars)
    328     {
    329         int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
    330         if (VBOX_FAILURE(rc))
    331         {
    332             pDbgc->rcOutput = rc;
    333             cbChars = 0;
    334         }
    335     }
    336 
    337     return cbChars;
    338 }
    339 
    340 
    341 
    342 /**
    343  * Command helper for writing formatted text to the debug console.
    344  *
    345  * @returns VBox status.
    346  * @param   pCmdHlp     Pointer to the command callback structure.
    347  * @param   pcb         Where to store the number of bytes written.
    348  * @param   pszFormat   The format string.
    349  *                      This is using the log formatter, so it's format extensions can be used.
    350  * @param   args        Arguments specified in the format string.
    351  */
    352 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
    353 {
    354     PDBGC   pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    355 
    356     /*
    357      * Do the formatting and output.
    358      */
    359     pDbgc->rcOutput = 0;
    360     size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
    361 
    362     if (pcbWritten)
    363         *pcbWritten = cb;
    364 
    365     return pDbgc->rcOutput;
    366 }
    367 
    368 
    369 /**
    370  * Reports an error from a DBGF call.
    371  *
    372  * @returns VBox status code appropriate to return from a command.
    373  * @param   pCmdHlp     Pointer to command helpers.
    374  * @param   rc          The VBox status code returned by a DBGF call.
    375  * @param   pszFormat   Format string for additional messages. Can be NULL.
    376  * @param   ...         Format arguments, optional.
    377  */
    378 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
    379 {
    380     switch (rc)
    381     {
    382         case VINF_SUCCESS:
    383             break;
    384 
    385         default:
    386             rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
    387             if (VBOX_SUCCESS(rc) && pszFormat)
    388                 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
    389             break;
    390     }
    391     return rc;
    392 }
    393 
    394 
    395 /**
    396  * Reports an error from a DBGF call.
    397  *
    398  * @returns VBox status code appropriate to return from a command.
    399  * @param   pCmdHlp     Pointer to command helpers.
    400  * @param   rc          The VBox status code returned by a DBGF call.
    401  * @param   pszFormat   Format string for additional messages. Can be NULL.
    402  * @param   ...         Format arguments, optional.
    403  */
    404 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
    405 {
    406     va_list args;
    407     va_start(args, pszFormat);
    408     int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
    409     va_end(args);
    410     return rcRet;
    411 }
    412 
    413 
    414 /**
    415  * Command helper for reading memory specified by a DBGC variable.
    416  *
    417  * @returns VBox status code appropriate to return from a command.
    418  * @param   pCmdHlp     Pointer to the command callback structure.
    419  * @param   pVM         VM handle if GC or physical HC address.
    420  * @param   pvBuffer    Where to store the read data.
    421  * @param   cbRead      Number of bytes to read.
    422  * @param   pVarPointer DBGC variable specifying where to start reading.
    423  * @param   pcbRead     Where to store the number of bytes actually read.
    424  *                      This optional, but it's useful when read GC virtual memory where a
    425  *                      page in the requested range might not be present.
    426  *                      If not specified not-present failure or end of a HC physical page
    427  *                      will cause failure.
    428  */
    429 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
    430 {
    431     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    432 
    433     /*
    434      * Dummy check.
    435      */
    436     if (cbRead == 0)
    437     {
    438         if (*pcbRead)
    439             *pcbRead = 0;
    440         return VINF_SUCCESS;
    441     }
    442 
    443     /*
    444      * Convert Far addresses getting size and the correct base address.
    445      * Getting and checking the size is what makes this messy and slow.
    446      */
    447     DBGCVAR Var = *pVarPointer;
    448     switch (pVarPointer->enmType)
    449     {
    450         case DBGCVAR_TYPE_GC_FAR:
    451         {
    452             /* Use DBGFR3AddrFromSelOff for the conversion. */
    453             Assert(pDbgc->pVM);
    454             DBGFADDRESS Address;
    455             int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
    456             if (VBOX_FAILURE(rc))
    457                 return rc;
    458 
    459             /* don't bother with flat selectors (for now). */
    460             if (!DBGFADDRESS_IS_FLAT(&Address))
    461             {
    462                 SELMSELINFO SelInfo;
    463                 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
    464                 if (VBOX_SUCCESS(rc))
    465                 {
    466                     RTGCUINTPTR cb; /* -1 byte */
    467                     if (SELMSelInfoIsExpandDown(&SelInfo))
    468                     {
    469                         if (    !SelInfo.Raw.Gen.u1Granularity
    470                             &&  Address.off > UINT16_C(0xffff))
    471                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    472                         if (Address.off <= SelInfo.cbLimit)
    473                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    474                         cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
    475                     }
    476                     else
    477                     {
    478                         if (Address.off > SelInfo.cbLimit)
    479                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    480                         cb = SelInfo.cbLimit - Address.off;
    481                     }
    482                     if (cbRead - 1 > cb)
    483                     {
    484                         if (!pcbRead)
    485                             return VERR_OUT_OF_SELECTOR_BOUNDS;
    486                         cbRead = cb + 1;
    487                     }
    488                 }
    489 
    490                 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
    491                 Var.u.GCFlat = Address.FlatPtr;
    492             }
    493             break;
    494         }
    495 
    496         case DBGCVAR_TYPE_GC_FLAT:
    497         case DBGCVAR_TYPE_GC_PHYS:
    498         case DBGCVAR_TYPE_HC_FLAT:
    499         case DBGCVAR_TYPE_HC_PHYS:
    500             break;
    501 
    502         case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
    503         default:
    504             return VERR_NOT_IMPLEMENTED;
    505     }
    506 
    507 
    508 
    509     /*
    510      * Copy page by page.
    511      */
    512     size_t cbLeft = cbRead;
    513     for (;;)
    514     {
    515         /*
    516          * Calc read size.
    517          */
    518         size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
    519         switch (pVarPointer->enmType)
    520         {
    521             case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
    522             case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
    523             case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
    524             case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */
    525             default: break;
    526         }
    527 
    528         /*
    529          * Perform read.
    530          */
    531         int rc;
    532         switch (Var.enmType)
    533         {
    534             case DBGCVAR_TYPE_GC_FLAT:
    535                 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
    536                 break;
    537             case DBGCVAR_TYPE_GC_PHYS:
    538                 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
    539                 break;
    540 
    541             case DBGCVAR_TYPE_HC_PHYS:
    542             case DBGCVAR_TYPE_HC_FLAT:
    543             case DBGCVAR_TYPE_HC_FAR:
    544             {
    545                 DBGCVAR Var2;
    546                 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
    547                 if (VBOX_SUCCESS(rc))
    548                 {
    549                     /** @todo protect this!!! */
    550                     memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
    551                     rc = 0;
    552                 }
    553                 else
    554                     rc = VERR_INVALID_POINTER;
    555                 break;
    556             }
    557 
    558             default:
    559                 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
    560         }
    561 
    562         /*
    563          * Check for failure.
    564          */
    565         if (VBOX_FAILURE(rc))
    566         {
    567             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    568                 return VINF_SUCCESS;
    569             return rc;
    570         }
    571 
    572         /*
    573          * Next.
    574          */
    575         cbLeft -= cb;
    576         if (!cbLeft)
    577             break;
    578         pvBuffer = (char *)pvBuffer + cb;
    579         rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
    580         if (VBOX_FAILURE(rc))
    581         {
    582             if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
    583                 return VINF_SUCCESS;
    584             return rc;
    585         }
    586     }
    587 
    588     /*
    589      * Done
    590      */
    591     if (pcbRead)
    592         *pcbRead = cbRead;
    593     return 0;
    594 }
    595 
    596 /**
    597  * Command helper for writing memory specified by a DBGC variable.
    598  *
    599  * @returns VBox status code appropriate to return from a command.
    600  * @param   pCmdHlp     Pointer to the command callback structure.
    601  * @param   pVM         VM handle if GC or physical HC address.
    602  * @param   pvBuffer    What to write.
    603  * @param   cbWrite     Number of bytes to write.
    604  * @param   pVarPointer DBGC variable specifying where to start reading.
    605  * @param   pcbWritten  Where to store the number of bytes written.
    606  *                      This is optional. If NULL be aware that some of the buffer
    607  *                      might have been written to the specified address.
    608  */
    609 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
    610 {
    611     NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
    612     return VERR_NOT_IMPLEMENTED;
    613 }
    614 
    615 
    616 /**
    617  * Evaluates an expression.
    618  * (Hopefully the parser and functions are fully reentrant.)
    619  *
    620  * @returns VBox status code appropriate to return from a command.
    621  * @param   pCmdHlp     Pointer to the command callback structure.
    622  * @param   pResult     Where to store the result.
    623  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    624  * @param   ...         Format arguments.
    625  */
    626 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
    627 {
    628     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    629 
    630     /*
    631      * Format the expression.
    632      */
    633     char szExprFormatted[2048];
    634     va_list args;
    635     va_start(args, pszExpr);
    636     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
    637     va_end(args);
    638     /* ignore overflows. */
    639 
    640     return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
    641 }
    642 
    643 
    644 /**
    645  * Executes one command expression.
    646  * (Hopefully the parser and functions are fully reentrant.)
    647  *
    648  * @returns VBox status code appropriate to return from a command.
    649  * @param   pCmdHlp     Pointer to the command callback structure.
    650  * @param   pszExpr     The expression. Format string with the format DBGC extensions.
    651  * @param   ...         Format arguments.
    652  */
    653 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
    654 {
    655     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    656     /* Save the scratch state. */
    657     char       *pszScratch  = pDbgc->pszScratch;
    658     unsigned    iArg        = pDbgc->iArg;
    659 
    660     /*
    661      * Format the expression.
    662      */
    663     va_list args;
    664     va_start(args, pszExpr);
    665     size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
    666     size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
    667     va_end(args);
    668     if (cb >= cbScratch)
    669         return VERR_BUFFER_OVERFLOW;
    670 
    671     /*
    672      * Execute the command.
    673      * We save and restore the arg index and scratch buffer pointer.
    674      */
    675     pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
    676     int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
    677 
    678     /* Restore the scratch state. */
    679     pDbgc->iArg         = iArg;
    680     pDbgc->pszScratch   = pszScratch;
    681 
    682     return rc;
    683 }
    684 
    685 
    686 /**
    687  * Converts a DBGC variable to a DBGF address structure.
    688  *
    689  * @returns VBox status code.
    690  * @param   pCmdHlp     Pointer to the command callback structure.
    691  * @param   pVar        The variable to convert.
    692  * @param   pAddress    The target address.
    693  */
    694 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
    695 {
    696     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    697     return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
    698 }
    699 
    700 
    701 /**
    702  * Converts a DBGC variable to a boolean.
    703  *
    704  * @returns VBox status code.
    705  * @param   pCmdHlp     Pointer to the command callback structure.
    706  * @param   pVar        The variable to convert.
    707  * @param   pf          Where to store the boolean.
    708  */
    709 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
    710 {
    711     PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
    712     NOREF(pDbgc);
    713 
    714     switch (pVar->enmType)
    715     {
    716         case DBGCVAR_TYPE_STRING:
    717             /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
    718             if (    !strcmp(pVar->u.pszString, "true")
    719                 ||  !strcmp(pVar->u.pszString, "True")
    720                 ||  !strcmp(pVar->u.pszString, "TRUE")
    721                 ||  !strcmp(pVar->u.pszString, "on")
    722                 ||  !strcmp(pVar->u.pszString, "On")
    723                 ||  !strcmp(pVar->u.pszString, "oN")
    724                 ||  !strcmp(pVar->u.pszString, "ON")
    725                 ||  !strcmp(pVar->u.pszString, "enabled")
    726                 ||  !strcmp(pVar->u.pszString, "Enabled")
    727                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    728             {
    729                 *pf = true;
    730                 return VINF_SUCCESS;
    731             }
    732             if (    !strcmp(pVar->u.pszString, "false")
    733                 ||  !strcmp(pVar->u.pszString, "False")
    734                 ||  !strcmp(pVar->u.pszString, "FALSE")
    735                 ||  !strcmp(pVar->u.pszString, "off")
    736                 ||  !strcmp(pVar->u.pszString, "Off")
    737                 ||  !strcmp(pVar->u.pszString, "OFF")
    738                 ||  !strcmp(pVar->u.pszString, "disabled")
    739                 ||  !strcmp(pVar->u.pszString, "Disabled")
    740                 ||  !strcmp(pVar->u.pszString, "DISABLED"))
    741             {
    742                 *pf = false;
    743                 return VINF_SUCCESS;
    744             }
    745             return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
    746 
    747         case DBGCVAR_TYPE_GC_FLAT:
    748         case DBGCVAR_TYPE_GC_PHYS:
    749         case DBGCVAR_TYPE_HC_FLAT:
    750         case DBGCVAR_TYPE_HC_PHYS:
    751         case DBGCVAR_TYPE_NUMBER:
    752             *pf = pVar->u.u64Number != 0;
    753             return VINF_SUCCESS;
    754 
    755         case DBGCVAR_TYPE_HC_FAR:
    756         case DBGCVAR_TYPE_GC_FAR:
    757         case DBGCVAR_TYPE_SYMBOL:
    758         default:
    759             return VERR_PARSE_INCORRECT_ARG_TYPE;
    760     }
    761 }
    762137
    763138
     
    18991274 * @param   pResult     Where to store the result of the expression evaluation.
    19001275 */
    1901 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
     1276int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
    19021277{
    19031278    Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
     
    22951670 * @param   cchCmd  Length of the command.
    22961671 */
    2297 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
     1672int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
    22981673{
    22991674    char *pszCmdInput = pszCmd;
     
    27792154        return VERR_NO_MEMORY;
    27802155
    2781     pDbgc->CmdHlp.pfnWrite      = dbgcHlpWrite;
    2782     pDbgc->CmdHlp.pfnPrintfV    = dbgcHlpPrintfV;
    2783     pDbgc->CmdHlp.pfnPrintf     = dbgcHlpPrintf;
    2784     pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
    2785     pDbgc->CmdHlp.pfnVBoxError  = dbgcHlpVBoxError;
    2786     pDbgc->CmdHlp.pfnMemRead    = dbgcHlpMemRead;
    2787     pDbgc->CmdHlp.pfnMemWrite   = dbgcHlpMemWrite;
    2788     pDbgc->CmdHlp.pfnEval       = dbgcHlpEval;
    2789     pDbgc->CmdHlp.pfnExec       = dbgcHlpExec;
    2790     pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
    2791     pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
     2156    dbgcInitCmdHlp(pDbgc);
    27922157    pDbgc->pBack            = pBack;
    27932158    pDbgc->pVM              = NULL;
  • trunk/src/VBox/Debugger/Makefile.kmk

    r5675 r5676  
    3737        DBGConsole.cpp \
    3838        DBGCBuiltInSymbols.cpp \
     39        DBGCCmdHlp.cpp \
    3940        DBGCCommands.cpp \
    4041        DBGCEmulateCodeView.cpp \
     
    102103        DBGConsole.cpp \
    103104        DBGCBuiltInSymbols.cpp \
     105        DBGCCmdHlp.cpp \
    104106        DBGCCommands.cpp \
    105107        DBGCEmulateCodeView.cpp \
Note: See TracChangeset for help on using the changeset viewer.

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