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