- Timestamp:
- Nov 11, 2007 5:28:37 AM (17 years ago)
- Location:
- trunk/src/VBox/Debugger
- Files:
-
- 3 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCInternal.h
r5671 r5673 341 341 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress); 342 342 343 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol); 343 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult); 344 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol); 345 PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev); 346 347 DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 348 DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 349 DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 350 DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 344 351 345 352 … … 349 356 extern const DBGCCMD g_aCmdsCodeView[]; 350 357 extern const unsigned g_cCmdsCodeView; 358 extern const DBGCOP g_aOps[]; 359 extern const unsigned g_cOps; 360 351 361 352 362 #endif -
trunk/src/VBox/Debugger/DBGCOps.cpp
r5672 r5673 1 1 /** $Id$ */ 2 2 /** @file 3 * DBGC - Debugger Console .3 * DBGC - Debugger Console, Operators. 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 101 17 102 18 /******************************************************************************* … … 131 47 * Internal Functions * 132 48 *******************************************************************************/ 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 49 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 151 50 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 152 51 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 153 52 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 154 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);155 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);156 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);157 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);158 53 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); 159 54 … … 175 70 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult); 176 71 177 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);178 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);179 180 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);181 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);182 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);183 184 72 185 73 /******************************************************************************* 186 74 * Global Variables * 187 75 *******************************************************************************/ 188 /**189 * Pointer to head of the list of external commands.190 */191 static PDBGCEXTCMDS g_pExtCmdsHead; /** @todo rw protect g_pExtCmdsHead! */192 /** Locks the g_pExtCmdsHead list for reading. */193 #define DBGCEXTCMDS_LOCK_RD() do { } while (0)194 /** Locks the g_pExtCmdsHead list for writing. */195 #define DBGCEXTCMDS_LOCK_WR() do { } while (0)196 /** UnLocks the g_pExtCmdsHead list after reading. */197 #define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)198 /** UnLocks the g_pExtCmdsHead list after writing. */199 #define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)200 201 202 /** One argument of any kind. */203 static const DBGCVARDESC g_aArgAny[] =204 {205 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */206 { 0, 1, DBGCVAR_CAT_ANY, 0, "var", "Any type of argument." },207 };208 209 /** Multiple string arguments (min 1). */210 static const DBGCVARDESC g_aArgMultiStr[] =211 {212 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */213 { 1, ~0, DBGCVAR_CAT_STRING, 0, "strings", "One or more strings." },214 };215 216 /** Filename string. */217 static const DBGCVARDESC g_aArgFilename[] =218 {219 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */220 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },221 };222 223 224 /** 'help' arguments. */225 static const DBGCVARDESC g_aArgHelp[] =226 {227 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */228 { 0, ~0, DBGCVAR_CAT_STRING, 0, "cmd/op", "Zero or more command or operator names." },229 };230 231 232 /** 'info' arguments. */233 static const DBGCVARDESC g_aArgInfo[] =234 {235 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */236 { 1, 1, DBGCVAR_CAT_STRING, 0, "info", "The name of the info to display." },237 { 0, 1, DBGCVAR_CAT_STRING, 0, "args", "String arguments to the handler." },238 };239 240 241 /** loadsyms arguments. */242 static const DBGCVARDESC g_aArgLoadSyms[] =243 {244 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */245 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },246 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "delta", "Delta to add to the loaded symbols. (optional)" },247 { 0, 1, DBGCVAR_CAT_STRING, 0, "module name", "Module name." },248 { 0, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "module address", "Module address." },249 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "module size", "The module size. (optional)" },250 };251 252 253 /** log arguments. */254 static const DBGCVARDESC g_aArgLog[] =255 {256 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */257 { 1, 1, DBGCVAR_CAT_STRING, 0, "groups", "Group modifier string (quote it!)." }258 };259 260 261 /** logdest arguments. */262 static const DBGCVARDESC g_aArgLogDest[] =263 {264 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */265 { 1, 1, DBGCVAR_CAT_STRING, 0, "dests", "Destination modifier string (quote it!)." }266 };267 268 269 /** logflags arguments. */270 static const DBGCVARDESC g_aArgLogFlags[] =271 {272 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */273 { 1, 1, DBGCVAR_CAT_STRING, 0, "flags", "Flag modifier string (quote it!)." }274 };275 276 277 /** 'set' arguments */278 static const DBGCVARDESC g_aArgSet[] =279 {280 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */281 { 1, 1, DBGCVAR_CAT_STRING, 0, "var", "Variable name." },282 { 1, 1, DBGCVAR_CAT_ANY, 0, "value", "Value to assign to the variable." },283 };284 285 286 287 288 289 /** Command descriptors for the basic commands. */290 static const DBGCCMD g_aCmds[] =291 {292 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */293 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },294 { "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." },295 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },296 { "format", 1, 1, &g_aArgAny[0], ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },297 { "harakiri", 0, 0, NULL, 0, NULL, 0, dbgcCmdHarakiri, "", "Kills debugger process." },298 { "help", 0, ~0, &g_aArgHelp[0], ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'info help'." },299 { "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'." },300 { "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." },301 { "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." },302 { "log", 1, 1, &g_aArgLog[0], ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },303 { "logdest", 1, 1, &g_aArgLogDest[0], ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },304 { "logflags", 1, 1, &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags), NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },305 { "quit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },306 { "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." },307 { "set", 2, 2, &g_aArgSet[0], ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },308 { "showvars", 0, 0, NULL, 0, NULL, 0, dbgcCmdShowVars, "", "List all the defined variables." },309 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." },310 { "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },311 };312 313 314 76 /** Operators. */ 315 staticconst DBGCOP g_aOps[] =77 const DBGCOP g_aOps[] = 316 78 { 317 79 /* szName is initialized as a 4 char array because of M$C elsewise optimizing it away in /Ox mode (the 'const char' vs 'char' problem). */ … … 344 106 }; 345 107 346 /** Bitmap where set bits indicates the characters the may start an operator name. */ 347 static uint32_t g_bmOperatorChars[256 / (4*8)]; 348 349 /** Register symbol uUser value. 350 * @{ 351 */ 352 /** If set the register set is the hypervisor and not the guest one. */ 353 #define SYMREG_FLAGS_HYPER RT_BIT(20) 354 /** If set a far conversion of the value will use the high 16 bit for the selector. 355 * If clear the low 16 bit will be used. */ 356 #define SYMREG_FLAGS_HIGH_SEL RT_BIT(21) 357 /** The shift value to calc the size of a register symbol from the uUser value. */ 358 #define SYMREG_SIZE_SHIFT (24) 359 /** Get the offset */ 360 #define SYMREG_OFFSET(uUser) (uUser & ((1 << 20) - 1)) 361 /** Get the size. */ 362 #define SYMREG_SIZE(uUser) ((uUser >> SYMREG_SIZE_SHIFT) & 0xff) 363 /** 1 byte. */ 364 #define SYMREG_SIZE_1 ( 1 << SYMREG_SIZE_SHIFT) 365 /** 2 byte. */ 366 #define SYMREG_SIZE_2 ( 2 << SYMREG_SIZE_SHIFT) 367 /** 4 byte. */ 368 #define SYMREG_SIZE_4 ( 4 << SYMREG_SIZE_SHIFT) 369 /** 6 byte. */ 370 #define SYMREG_SIZE_6 ( 6 << SYMREG_SIZE_SHIFT) 371 /** 8 byte. */ 372 #define SYMREG_SIZE_8 ( 8 << SYMREG_SIZE_SHIFT) 373 /** 12 byte. */ 374 #define SYMREG_SIZE_12 (12 << SYMREG_SIZE_SHIFT) 375 /** 16 byte. */ 376 #define SYMREG_SIZE_16 (16 << SYMREG_SIZE_SHIFT) 377 /** @} */ 378 379 /** Builtin Symbols. 380 * ASSUMES little endian register representation! 381 */ 382 static const DBGCSYM g_aSyms[] = 383 { 384 { "eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 }, 385 { "ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 }, 386 { "al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 }, 387 { "ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 }, 388 389 { "ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 }, 390 { "bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 }, 391 { "bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 }, 392 { "bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 }, 393 394 { "ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 }, 395 { "cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 }, 396 { "cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 }, 397 { "ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 }, 398 399 { "edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 }, 400 { "dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 }, 401 { "dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 }, 402 { "dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 }, 403 404 { "edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 }, 405 { "di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 }, 406 407 { "esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 }, 408 { "si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 }, 409 410 { "ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 }, 411 { "bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 }, 412 413 { "esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 }, 414 { "sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 }, 415 416 { "eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 }, 417 { "ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 }, 418 419 { "efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 420 { "eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 421 { "fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 422 { "flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 423 424 { "cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 }, 425 { "ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 }, 426 { "es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 }, 427 { "fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 }, 428 { "gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 }, 429 { "ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 }, 430 431 { "cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 }, 432 { "cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 }, 433 { "cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 }, 434 { "cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 }, 435 436 { "tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 }, 437 { "ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 }, 438 439 { "gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 }, 440 { "gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 }, 441 { "gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 }, 442 443 { "idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 }, 444 { "idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 }, 445 { "idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 }, 446 447 /* hypervisor */ 448 449 {".eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 450 {".ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 451 {".al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 452 {".ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 453 454 {".ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 455 {".bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 456 {".bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 457 {".bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 458 459 {".ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 460 {".cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 461 {".cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 462 {".ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 463 464 {".edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 465 {".dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 466 {".dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 467 {".dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 468 469 {".edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 470 {".di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 471 472 {".esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 473 {".si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 474 475 {".ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 476 {".bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 477 478 {".esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 479 {".sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 480 481 {".eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 482 {".ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 483 484 {".efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 485 {".eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 486 {".fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 487 {".flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 488 489 {".cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 490 {".ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 491 {".es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 492 {".fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 493 {".gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 494 {".ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 495 496 {".cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 497 {".cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 498 {".cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 499 {".cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 500 501 {".tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 502 {".ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 503 504 {".gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 505 {".gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 506 {".gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 507 508 {".idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 509 {".idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 510 {".idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 511 512 }; 513 514 515 /** 516 * Prints full command help. 517 */ 518 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal) 519 { 520 int rc; 521 522 /* the command */ 523 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 524 "%s%-*s %-30s %s", 525 fExternal ? "." : "", 526 fExternal ? 10 : 11, 527 pCmd->pszCmd, 528 pCmd->pszSyntax, 529 pCmd->pszDescription); 530 if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax) 531 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n"); 532 else if (pCmd->cArgsMin == pCmd->cArgsMax) 533 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin); 534 else if (pCmd->cArgsMax == ~0U) 535 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin); 536 else 537 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax); 538 539 /* argument descriptions. */ 540 for (unsigned i = 0; i < pCmd->cArgDescs; i++) 541 { 542 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 543 " %-12s %s", 544 pCmd->paArgDescs[i].pszName, 545 pCmd->paArgDescs[i].pszDescription); 546 if (!pCmd->paArgDescs[i].cTimesMin) 547 { 548 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 549 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n"); 550 else 551 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax); 552 } 553 else 554 { 555 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 556 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin); 557 else 558 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax); 559 } 560 } 561 return rc; 562 } 563 564 565 /** 566 * The 'help' command. 567 * 568 * @returns VBox status. 569 * @param pCmd Pointer to the command descriptor (as registered). 570 * @param pCmdHlp Pointer to command helper functions. 571 * @param pVM Pointer to the current VM (if any). 572 * @param paArgs Pointer to (readonly) array of arguments. 573 * @param cArgs Number of arguments in the array. 574 */ 575 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 576 { 577 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 578 int rc = VINF_SUCCESS; 579 unsigned i; 580 581 if (!cArgs) 582 { 583 /* 584 * All the stuff. 585 */ 586 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 587 "VirtualBox Debugger\n" 588 "-------------------\n" 589 "\n" 590 "Commands and Functions:\n"); 591 for (i = 0; i < ELEMENTS(g_aCmds); i++) 592 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 593 "%-11s %-30s %s\n", 594 g_aCmds[i].pszCmd, 595 g_aCmds[i].pszSyntax, 596 g_aCmds[i].pszDescription); 597 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 598 "\n" 599 "Emulation: %s\n", pDbgc->pszEmulation); 600 PCDBGCCMD pCmd = pDbgc->paEmulationCmds; 601 for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++) 602 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 603 "%-11s %-30s %s\n", 604 pCmd->pszCmd, 605 pCmd->pszSyntax, 606 pCmd->pszDescription); 607 608 if (g_pExtCmdsHead) 609 { 610 DBGCEXTCMDS_LOCK_RD(); 611 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 612 "\n" 613 "External Commands and Functions:\n"); 614 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext) 615 for (i = 0; i < pExtCmd->cCmds; i++) 616 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 617 ".%-10s %-30s %s\n", 618 pExtCmd->paCmds[i].pszCmd, 619 pExtCmd->paCmds[i].pszSyntax, 620 pExtCmd->paCmds[i].pszDescription); 621 DBGCEXTCMDS_UNLOCK_RD(); 622 } 623 624 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 625 "\n" 626 "Operators:\n"); 627 unsigned iPrecedence = 0; 628 unsigned cLeft = ELEMENTS(g_aOps); 629 while (cLeft > 0) 630 { 631 for (i = 0; i < ELEMENTS(g_aOps); i++) 632 if (g_aOps[i].iPrecedence == iPrecedence) 633 { 634 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 635 "%-10s %s %s\n", 636 g_aOps[i].szName, 637 g_aOps[i].fBinary ? "Binary" : "Unary ", 638 g_aOps[i].pszDescription); 639 cLeft--; 640 } 641 iPrecedence++; 642 } 643 } 644 else 645 { 646 /* 647 * Search for the arguments (strings). 648 */ 649 for (unsigned iArg = 0; iArg < cArgs; iArg++) 650 { 651 Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING); 652 bool fFound = false; 653 654 /* lookup in the emulation command list first */ 655 for (i = 0; i < pDbgc->cEmulationCmds; i++) 656 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString)) 657 { 658 rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false); 659 fFound = true; 660 break; 661 } 662 663 /* lookup in the command list (even when found in the emulation) */ 664 for (i = 0; i < ELEMENTS(g_aCmds); i++) 665 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString)) 666 { 667 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false); 668 fFound = true; 669 break; 670 } 671 672 /* external commands */ 673 if ( !fFound 674 && g_pExtCmdsHead 675 && paArgs[iArg].u.pszString[0] == '.') 676 { 677 DBGCEXTCMDS_LOCK_RD(); 678 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext) 679 for (i = 0; i < pExtCmd->cCmds; i++) 680 if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1)) 681 { 682 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true); 683 fFound = true; 684 break; 685 } 686 DBGCEXTCMDS_UNLOCK_RD(); 687 } 688 689 /* operators */ 690 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName)) 691 { 692 for (i = 0; i < ELEMENTS(g_aOps); i++) 693 if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString)) 694 { 695 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 696 "%-10s %s %s\n", 697 g_aOps[i].szName, 698 g_aOps[i].fBinary ? "Binary" : "Unary ", 699 g_aOps[i].pszDescription); 700 fFound = true; 701 break; 702 } 703 } 704 705 /* found? */ 706 if (!fFound) 707 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 708 "error: '%s' was not found!\n", 709 paArgs[iArg].u.pszString); 710 } /* foreach argument */ 711 } 712 713 NOREF(pCmd); 714 NOREF(pVM); 715 NOREF(pResult); 716 return rc; 717 } 718 719 720 /** 721 * The 'quit', 'exit' and 'bye' commands. 722 * 723 * @returns VBox status. 724 * @param pCmd Pointer to the command descriptor (as registered). 725 * @param pCmdHlp Pointer to command helper functions. 726 * @param pVM Pointer to the current VM (if any). 727 * @param paArgs Pointer to (readonly) array of arguments. 728 * @param cArgs Number of arguments in the array. 729 */ 730 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 731 { 732 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n"); 733 NOREF(pCmd); 734 NOREF(pVM); 735 NOREF(paArgs); 736 NOREF(cArgs); 737 NOREF(pResult); 738 return VERR_DBGC_QUIT; 739 } 740 741 742 /** 743 * The 'stop' command. 744 * 745 * @returns VBox status. 746 * @param pCmd Pointer to the command descriptor (as registered). 747 * @param pCmdHlp Pointer to command helper functions. 748 * @param pVM Pointer to the current VM (if any). 749 * @param paArgs Pointer to (readonly) array of arguments. 750 * @param cArgs Number of arguments in the array. 751 */ 752 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 753 { 754 /* 755 * Check if the VM is halted or not before trying to halt it. 756 */ 757 int rc; 758 if (DBGFR3IsHalted(pVM)) 759 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n"); 760 else 761 { 762 rc = DBGFR3Halt(pVM); 763 if (VBOX_SUCCESS(rc)) 764 rc = VWRN_DBGC_CMD_PENDING; 765 else 766 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt()."); 767 } 768 769 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult); 770 return rc; 771 } 772 773 774 /** 775 * The 'echo' command. 776 * 777 * @returns VBox status. 778 * @param pCmd Pointer to the command descriptor (as registered). 779 * @param pCmdHlp Pointer to command helper functions. 780 * @param pVM Pointer to the current VM (if any). 781 * @param paArgs Pointer to (readonly) array of arguments. 782 * @param cArgs Number of arguments in the array. 783 */ 784 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 785 { 786 /* 787 * Loop thru the arguments and print them with one space between. 788 */ 789 int rc = 0; 790 for (unsigned i = 0; i < cArgs; i++) 791 { 792 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING) 793 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString); 794 else 795 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>"); 796 if (VBOX_FAILURE(rc)) 797 return rc; 798 } 799 NOREF(pCmd); NOREF(pResult); NOREF(pVM); 800 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n"); 801 } 802 803 804 /** 805 * The 'runscript' command. 806 * 807 * @returns VBox status. 808 * @param pCmd Pointer to the command descriptor (as registered). 809 * @param pCmdHlp Pointer to command helper functions. 810 * @param pVM Pointer to the current VM (if any). 811 * @param paArgs Pointer to (readonly) array of arguments. 812 * @param cArgs Number of arguments in the array. 813 */ 814 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 815 { 816 /* check that the parser did what it's supposed to do. */ 817 if ( cArgs != 1 818 || paArgs[0].enmType != DBGCVAR_TYPE_STRING) 819 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n"); 820 821 /* 822 * Try open the script. 823 */ 824 const char *pszFilename = paArgs[0].u.pszString; 825 FILE *pFile = fopen(pszFilename, "r"); 826 if (!pFile) 827 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename); 828 829 /* 830 * Execute it line by line. 831 */ 832 int rc = 0; 833 unsigned iLine = 0; 834 char szLine[8192]; 835 while (fgets(szLine, sizeof(szLine), pFile)) 836 { 837 /* check that the line isn't too long. */ 838 char *pszEnd = strchr(szLine, '\0'); 839 if (pszEnd == &szLine[sizeof(szLine) - 1]) 840 { 841 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine); 842 break; 843 } 844 iLine++; 845 846 /* strip leading blanks and check for comment / blank line. */ 847 char *psz = RTStrStripL(szLine); 848 if ( *psz == '\0' 849 || *psz == '\n' 850 || *psz == '#') 851 continue; 852 853 /* strip trailing blanks and check for empty line (\r case). */ 854 while ( pszEnd > psz 855 && isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */ 856 *--pszEnd = '\0'; 857 858 /** @todo check for Control-C / Cancel at this point... */ 859 860 /* 861 * Execute the command. 862 * 863 * This is a bit wasteful with scratch space btw., can fix it later. 864 * The whole return code crap should be fixed too, so that it's possible 865 * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and 866 * more importantly why it failed. 867 */ 868 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz); 869 if (VBOX_FAILURE(rc)) 870 { 871 if (rc == VERR_BUFFER_OVERFLOW) 872 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine); 873 break; 874 } 875 if (rc == VWRN_DBGC_CMD_PENDING) 876 { 877 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine); 878 break; 879 } 880 } 881 882 fclose(pFile); 883 884 NOREF(pCmd); NOREF(pResult); NOREF(pVM); 885 return rc; 886 } 887 888 889 /** 890 * Print formatted string. 891 * 892 * @param pHlp Pointer to this structure. 893 * @param pszFormat The format string. 894 * @param ... Arguments. 895 */ 896 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...) 897 { 898 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1); 899 va_list args; 900 va_start(args, pszFormat); 901 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args); 902 va_end(args); 903 } 904 905 906 /** 907 * Print formatted string. 908 * 909 * @param pHlp Pointer to this structure. 910 * @param pszFormat The format string. 911 * @param args Argument list. 912 */ 913 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args) 914 { 915 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1); 916 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args); 917 } 918 919 920 /** 921 * The 'info' command. 922 * 923 * @returns VBox status. 924 * @param pCmd Pointer to the command descriptor (as registered). 925 * @param pCmdHlp Pointer to command helper functions. 926 * @param pVM Pointer to the current VM (if any). 927 * @param paArgs Pointer to (readonly) array of arguments. 928 * @param cArgs Number of arguments in the array. 929 */ 930 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 931 { 932 /* 933 * Validate input. 934 */ 935 if ( cArgs < 1 936 || cArgs > 2 937 || paArgs[0].enmType != DBGCVAR_TYPE_STRING 938 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING) 939 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n"); 940 if (!pVM) 941 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n"); 942 943 /* 944 * Dump it. 945 */ 946 struct 947 { 948 DBGFINFOHLP Hlp; 949 PDBGCCMDHLP pCmdHlp; 950 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp }; 951 int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp); 952 if (VBOX_FAILURE(rc)) 953 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n"); 954 955 NOREF(pCmd); NOREF(pResult); 956 return 0; 957 } 958 959 960 /** 961 * The 'log' command. 962 * 963 * @returns VBox status. 964 * @param pCmd Pointer to the command descriptor (as registered). 965 * @param pCmdHlp Pointer to command helper functions. 966 * @param pVM Pointer to the current VM (if any). 967 * @param paArgs Pointer to (readonly) array of arguments. 968 * @param cArgs Number of arguments in the array. 969 */ 970 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 971 { 972 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString); 973 if (VBOX_SUCCESS(rc)) 974 return VINF_SUCCESS; 975 NOREF(pCmd); NOREF(cArgs); NOREF(pResult); 976 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString); 977 } 978 979 980 /** 981 * The 'logdest' command. 982 * 983 * @returns VBox status. 984 * @param pCmd Pointer to the command descriptor (as registered). 985 * @param pCmdHlp Pointer to command helper functions. 986 * @param pVM Pointer to the current VM (if any). 987 * @param paArgs Pointer to (readonly) array of arguments. 988 * @param cArgs Number of arguments in the array. 989 */ 990 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 991 { 992 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString); 993 if (VBOX_SUCCESS(rc)) 994 return VINF_SUCCESS; 995 NOREF(pCmd); NOREF(cArgs); NOREF(pResult); 996 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString); 997 } 998 999 1000 /** 1001 * The 'logflags' command. 1002 * 1003 * @returns VBox status. 1004 * @param pCmd Pointer to the command descriptor (as registered). 1005 * @param pCmdHlp Pointer to command helper functions. 1006 * @param pVM Pointer to the current VM (if any). 1007 * @param paArgs Pointer to (readonly) array of arguments. 1008 * @param cArgs Number of arguments in the array. 1009 */ 1010 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1011 { 1012 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString); 1013 if (VBOX_SUCCESS(rc)) 1014 return VINF_SUCCESS; 1015 NOREF(pCmd); NOREF(cArgs); NOREF(pResult); 1016 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString); 1017 } 1018 1019 1020 /** 1021 * The 'format' command. 1022 * 1023 * @returns VBox status. 1024 * @param pCmd Pointer to the command descriptor (as registered). 1025 * @param pCmdHlp Pointer to command helper functions. 1026 * @param pVM Pointer to the current VM (if any). 1027 * @param paArgs Pointer to (readonly) array of arguments. 1028 * @param cArgs Number of arguments in the array. 1029 */ 1030 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1031 { 1032 LogFlow(("dbgcCmdFormat\n")); 1033 static const char *apszRangeDesc[] = 1034 { 1035 "none", "bytes", "elements" 1036 }; 1037 int rc; 1038 1039 for (unsigned iArg = 0; iArg < cArgs; iArg++) 1040 { 1041 switch (paArgs[iArg].enmType) 1042 { 1043 case DBGCVAR_TYPE_UNKNOWN: 1044 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1045 "Unknown variable type!\n"); 1046 break; 1047 case DBGCVAR_TYPE_GC_FLAT: 1048 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1049 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1050 "Guest flat address: %%%08x range %lld %s\n", 1051 paArgs[iArg].u.GCFlat, 1052 paArgs[iArg].u64Range, 1053 apszRangeDesc[paArgs[iArg].enmRangeType]); 1054 else 1055 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1056 "Guest flat address: %%%08x\n", 1057 paArgs[iArg].u.GCFlat); 1058 break; 1059 case DBGCVAR_TYPE_GC_FAR: 1060 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1061 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1062 "Guest far address: %04x:%08x range %lld %s\n", 1063 paArgs[iArg].u.GCFar.sel, 1064 paArgs[iArg].u.GCFar.off, 1065 paArgs[iArg].u64Range, 1066 apszRangeDesc[paArgs[iArg].enmRangeType]); 1067 else 1068 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1069 "Guest far address: %04x:%08x\n", 1070 paArgs[iArg].u.GCFar.sel, 1071 paArgs[iArg].u.GCFar.off); 1072 break; 1073 case DBGCVAR_TYPE_GC_PHYS: 1074 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1075 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1076 "Guest physical address: %%%%%08x range %lld %s\n", 1077 paArgs[iArg].u.GCPhys, 1078 paArgs[iArg].u64Range, 1079 apszRangeDesc[paArgs[iArg].enmRangeType]); 1080 else 1081 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1082 "Guest physical address: %%%%%08x\n", 1083 paArgs[iArg].u.GCPhys); 1084 break; 1085 case DBGCVAR_TYPE_HC_FLAT: 1086 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1087 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1088 "Host flat address: %%%08x range %lld %s\n", 1089 paArgs[iArg].u.pvHCFlat, 1090 paArgs[iArg].u64Range, 1091 apszRangeDesc[paArgs[iArg].enmRangeType]); 1092 else 1093 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1094 "Host flat address: %%%08x\n", 1095 paArgs[iArg].u.pvHCFlat); 1096 break; 1097 case DBGCVAR_TYPE_HC_FAR: 1098 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1099 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1100 "Host far address: %04x:%08x range %lld %s\n", 1101 paArgs[iArg].u.HCFar.sel, 1102 paArgs[iArg].u.HCFar.off, 1103 paArgs[iArg].u64Range, 1104 apszRangeDesc[paArgs[iArg].enmRangeType]); 1105 else 1106 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1107 "Host far address: %04x:%08x\n", 1108 paArgs[iArg].u.HCFar.sel, 1109 paArgs[iArg].u.HCFar.off); 1110 break; 1111 case DBGCVAR_TYPE_HC_PHYS: 1112 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1113 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1114 "Host physical address: %VHp range %lld %s\n", 1115 paArgs[iArg].u.HCPhys, 1116 paArgs[iArg].u64Range, 1117 apszRangeDesc[paArgs[iArg].enmRangeType]); 1118 else 1119 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1120 "Host physical address: %VHp\n", 1121 paArgs[iArg].u.HCPhys); 1122 break; 1123 1124 case DBGCVAR_TYPE_STRING: 1125 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1126 "String, %lld bytes long: %s\n", 1127 paArgs[iArg].u64Range, 1128 paArgs[iArg].u.pszString); 1129 break; 1130 1131 case DBGCVAR_TYPE_NUMBER: 1132 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE) 1133 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1134 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n", 1135 paArgs[iArg].u.u64Number, 1136 paArgs[iArg].u.u64Number, 1137 paArgs[iArg].u.u64Number, 1138 paArgs[iArg].u64Range, 1139 apszRangeDesc[paArgs[iArg].enmRangeType]); 1140 else 1141 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1142 "Number: hex %llx dec 0i%lld oct 0t%llo\n", 1143 paArgs[iArg].u.u64Number, 1144 paArgs[iArg].u.u64Number, 1145 paArgs[iArg].u.u64Number); 1146 break; 1147 1148 default: 1149 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1150 "Invalid argument type %d\n", 1151 paArgs[iArg].enmType); 1152 break; 1153 } 1154 } /* arg loop */ 1155 1156 NOREF(pCmd); NOREF(pVM); NOREF(pResult); 1157 return 0; 1158 } 1159 1160 1161 /** 1162 * The 'loadsyms' command. 1163 * 1164 * @returns VBox status. 1165 * @param pCmd Pointer to the command descriptor (as registered). 1166 * @param pCmdHlp Pointer to command helper functions. 1167 * @param pVM Pointer to the current VM (if any). 1168 * @param paArgs Pointer to (readonly) array of arguments. 1169 * @param cArgs Number of arguments in the array. 1170 */ 1171 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1172 { 1173 /* 1174 * Validate the parsing and make sense of the input. 1175 * This is a mess as usual because we don't trust the parser yet. 1176 */ 1177 if ( cArgs < 1 1178 || paArgs[0].enmType != DBGCVAR_TYPE_STRING) 1179 { 1180 AssertMsgFailed(("Parse error, first argument required to be string!\n")); 1181 return VERR_PARSE_INCORRECT_ARG_TYPE; 1182 } 1183 DBGCVAR AddrVar; 1184 RTGCUINTPTR Delta = 0; 1185 const char *pszModule = NULL; 1186 RTGCUINTPTR ModuleAddress = 0; 1187 unsigned cbModule = 0; 1188 if (cArgs > 1) 1189 { 1190 unsigned iArg = 1; 1191 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER) 1192 { 1193 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number; 1194 iArg++; 1195 } 1196 if (iArg < cArgs) 1197 { 1198 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING) 1199 { 1200 AssertMsgFailed(("Parse error, module argument required to be string!\n")); 1201 return VERR_PARSE_INCORRECT_ARG_TYPE; 1202 } 1203 pszModule = paArgs[iArg].u.pszString; 1204 iArg++; 1205 if (iArg < cArgs) 1206 { 1207 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType)) 1208 { 1209 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n")); 1210 return VERR_PARSE_INCORRECT_ARG_TYPE; 1211 } 1212 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]); 1213 if (VBOX_FAILURE(rc)) 1214 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]); 1215 ModuleAddress = paArgs[iArg].u.GCFlat; 1216 iArg++; 1217 if (iArg < cArgs) 1218 { 1219 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER) 1220 { 1221 AssertMsgFailed(("Parse error, module argument required to be an interger!\n")); 1222 return VERR_PARSE_INCORRECT_ARG_TYPE; 1223 } 1224 cbModule = (unsigned)paArgs[iArg].u.u64Number; 1225 iArg++; 1226 if (iArg < cArgs) 1227 { 1228 AssertMsgFailed(("Parse error, too many arguments!\n")); 1229 return VERR_PARSE_TOO_MANY_ARGUMENTS; 1230 } 1231 } 1232 } 1233 } 1234 } 1235 1236 /* 1237 * Call the debug info manager about this loading... 1238 */ 1239 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule); 1240 if (VBOX_FAILURE(rc)) 1241 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n", 1242 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress); 1243 1244 NOREF(pCmd); NOREF(pResult); 1245 return VINF_SUCCESS; 1246 } 1247 1248 1249 /** 1250 * The 'set' command. 1251 * 1252 * @returns VBox status. 1253 * @param pCmd Pointer to the command descriptor (as registered). 1254 * @param pCmdHlp Pointer to command helper functions. 1255 * @param pVM Pointer to the current VM (if any). 1256 * @param paArgs Pointer to (readonly) array of arguments. 1257 * @param cArgs Number of arguments in the array. 1258 */ 1259 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1260 { 1261 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1262 1263 /* parse sanity check. */ 1264 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType)); 1265 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING) 1266 return VERR_PARSE_INCORRECT_ARG_TYPE; 1267 1268 1269 /* 1270 * A variable must start with an alpha chars and only contain alpha numerical chars. 1271 */ 1272 const char *pszVar = paArgs[0].u.pszString; 1273 if (!isalpha(*pszVar) || *pszVar == '_') 1274 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1275 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString); 1276 1277 while (isalnum(*pszVar) || *pszVar == '_') 1278 *pszVar++; 1279 if (*pszVar) 1280 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, 1281 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString); 1282 1283 1284 /* 1285 * Calc variable size. 1286 */ 1287 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR); 1288 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING) 1289 cbVar += 1 + (size_t)paArgs[1].u64Range; 1290 1291 /* 1292 * Look for existing one. 1293 */ 1294 pszVar = paArgs[0].u.pszString; 1295 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++) 1296 { 1297 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName)) 1298 { 1299 /* 1300 * Update existing variable. 1301 */ 1302 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar); 1303 if (!pv) 1304 return VERR_PARSE_NO_MEMORY; 1305 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv; 1306 1307 pVar->Var = paArgs[1]; 1308 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1); 1309 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING) 1310 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1); 1311 return 0; 1312 } 1313 } 1314 1315 /* 1316 * Allocate another. 1317 */ 1318 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar); 1319 1320 pVar->Var = paArgs[1]; 1321 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1); 1322 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING) 1323 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1); 1324 1325 /* need to reallocate the pointer array too? */ 1326 if (!(pDbgc->cVars % 0x20)) 1327 { 1328 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0])); 1329 if (!pv) 1330 { 1331 RTMemFree(pVar); 1332 return VERR_PARSE_NO_MEMORY; 1333 } 1334 pDbgc->papVars = (PDBGCNAMEDVAR *)pv; 1335 } 1336 pDbgc->papVars[pDbgc->cVars++] = pVar; 1337 1338 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult); 1339 return 0; 1340 } 1341 1342 1343 /** 1344 * The 'unset' command. 1345 * 1346 * @returns VBox status. 1347 * @param pCmd Pointer to the command descriptor (as registered). 1348 * @param pCmdHlp Pointer to command helper functions. 1349 * @param pVM Pointer to the current VM (if any). 1350 * @param paArgs Pointer to (readonly) array of arguments. 1351 * @param cArgs Number of arguments in the array. 1352 */ 1353 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1354 { 1355 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1356 1357 /* 1358 * Don't trust the parser. 1359 */ 1360 for (unsigned i = 0; i < cArgs; i++) 1361 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING) 1362 { 1363 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i)); 1364 return VERR_PARSE_INCORRECT_ARG_TYPE; 1365 } 1366 1367 /* 1368 * Iterate the variables and unset them. 1369 */ 1370 for (unsigned iArg = 0; iArg < cArgs; iArg++) 1371 { 1372 const char *pszVar = paArgs[iArg].u.pszString; 1373 1374 /* 1375 * Look up the variable. 1376 */ 1377 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++) 1378 { 1379 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName)) 1380 { 1381 /* 1382 * Shuffle the array removing this entry. 1383 */ 1384 void *pvFree = pDbgc->papVars[iVar]; 1385 if (iVar + 1 < pDbgc->cVars) 1386 memmove(&pDbgc->papVars[iVar], 1387 &pDbgc->papVars[iVar + 1], 1388 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0])); 1389 pDbgc->papVars[--pDbgc->cVars] = NULL; 1390 1391 RTMemFree(pvFree); 1392 } 1393 } /* lookup */ 1394 } /* arg loop */ 1395 1396 NOREF(pCmd); NOREF(pVM); NOREF(pResult); 1397 return 0; 1398 } 1399 1400 1401 /** 1402 * The 'loadvars' command. 1403 * 1404 * @returns VBox status. 1405 * @param pCmd Pointer to the command descriptor (as registered). 1406 * @param pCmdHlp Pointer to command helper functions. 1407 * @param pVM Pointer to the current VM (if any). 1408 * @param paArgs Pointer to (readonly) array of arguments. 1409 * @param cArgs Number of arguments in the array. 1410 */ 1411 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1412 { 1413 /* 1414 * Don't trust the parser. 1415 */ 1416 if ( cArgs != 1 1417 || paArgs[0].enmType != DBGCVAR_TYPE_STRING) 1418 { 1419 AssertMsgFailed(("Expected one string exactly!\n")); 1420 return VERR_PARSE_INCORRECT_ARG_TYPE; 1421 } 1422 1423 /* 1424 * Iterate the variables and unset them. 1425 */ 1426 FILE *pFile = fopen(paArgs[0].u.pszString, "r"); 1427 if (pFile) 1428 { 1429 char szLine[4096]; 1430 while (fgets(szLine, sizeof(szLine), pFile)) 1431 { 1432 /* Strip it. */ 1433 char *psz = szLine; 1434 while (isblank(*psz)) 1435 psz++; 1436 int i = (int)strlen(psz) - 1; 1437 while (i >= 0 && isspace(psz[i])) 1438 psz[i--] ='\0'; 1439 /* Execute it if not comment or empty line. */ 1440 if ( *psz != '\0' 1441 && *psz != '#' 1442 && *psz != ';') 1443 { 1444 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz); 1445 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz); 1446 } 1447 } 1448 fclose(pFile); 1449 } 1450 else 1451 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString); 1452 1453 NOREF(pCmd); NOREF(pVM); NOREF(pResult); 1454 return 0; 1455 } 1456 1457 1458 /** 1459 * The 'showvars' command. 1460 * 1461 * @returns VBox status. 1462 * @param pCmd Pointer to the command descriptor (as registered). 1463 * @param pCmdHlp Pointer to command helper functions. 1464 * @param pVM Pointer to the current VM (if any). 1465 * @param paArgs Pointer to (readonly) array of arguments. 1466 * @param cArgs Number of arguments in the array. 1467 */ 1468 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1469 { 1470 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1471 1472 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++) 1473 { 1474 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName); 1475 if (!rc) 1476 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL); 1477 if (rc) 1478 return rc; 1479 } 1480 1481 NOREF(paArgs); NOREF(cArgs); NOREF(pResult); 1482 return 0; 1483 } 1484 1485 1486 /** 1487 * The 'harakiri' command. 1488 * 1489 * @returns VBox status. 1490 * @param pCmd Pointer to the command descriptor (as registered). 1491 * @param pCmdHlp Pointer to command helper functions. 1492 * @param pVM Pointer to the current VM (if any). 1493 * @param paArgs Pointer to (readonly) array of arguments. 1494 * @param cArgs Number of arguments in the array. 1495 */ 1496 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1497 { 1498 Log(("dbgcCmdHarakiri\n")); 1499 for (;;) 1500 exit(126); 1501 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult); 1502 } 1503 1504 1505 1506 1507 1508 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 1509 // 1510 // 1511 // B u l t i n S y m b o l s 1512 // 1513 // 1514 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 1515 1516 1517 1518 /** 1519 * Get builtin register symbol. 1520 * 1521 * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines. 1522 * 1523 * @returns 0 on success. 1524 * @returns VBox evaluation / parsing error code on failure. 1525 * The caller does the bitching. 1526 * @param pSymDesc Pointer to the symbol descriptor. 1527 * @param pCmdHlp Pointer to the command callback structure. 1528 * @param enmType The result type. 1529 * @param pResult Where to store the result. 1530 */ 1531 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult) 1532 { 1533 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName)); 1534 1535 /* 1536 * pVM is required. 1537 */ 1538 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1539 Assert(pDbgc->pVM); 1540 1541 /* 1542 * Get the right CPU context. 1543 */ 1544 PCPUMCTX pCtx; 1545 int rc; 1546 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER)) 1547 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx); 1548 else 1549 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx); 1550 if (VBOX_FAILURE(rc)) 1551 return rc; 1552 1553 /* 1554 * Get the value. 1555 */ 1556 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser); 1557 uint64_t u64; 1558 switch (SYMREG_SIZE(pSymDesc->uUser)) 1559 { 1560 case 1: u64 = *(uint8_t *)pvValue; break; 1561 case 2: u64 = *(uint16_t *)pvValue; break; 1562 case 4: u64 = *(uint32_t *)pvValue; break; 1563 case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break; 1564 case 8: u64 = *(uint64_t *)pvValue; break; 1565 default: 1566 return VERR_PARSE_NOT_IMPLEMENTED; 1567 } 1568 1569 /* 1570 * Construct the desired result. 1571 */ 1572 if (enmType == DBGCVAR_TYPE_ANY) 1573 enmType = DBGCVAR_TYPE_NUMBER; 1574 pResult->pDesc = NULL; 1575 pResult->pNext = NULL; 1576 pResult->enmType = enmType; 1577 pResult->enmRangeType = DBGCVAR_RANGE_NONE; 1578 pResult->u64Range = 0; 1579 1580 switch (enmType) 1581 { 1582 case DBGCVAR_TYPE_GC_FLAT: 1583 pResult->u.GCFlat = (RTGCPTR)u64; 1584 break; 1585 1586 case DBGCVAR_TYPE_GC_FAR: 1587 switch (SYMREG_SIZE(pSymDesc->uUser)) 1588 { 1589 case 4: 1590 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL)) 1591 { 1592 pResult->u.GCFar.off = (uint16_t)u64; 1593 pResult->u.GCFar.sel = (uint16_t)(u64 >> 16); 1594 } 1595 else 1596 { 1597 pResult->u.GCFar.sel = (uint16_t)u64; 1598 pResult->u.GCFar.off = (uint16_t)(u64 >> 16); 1599 } 1600 break; 1601 case 6: 1602 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL)) 1603 { 1604 pResult->u.GCFar.off = (uint32_t)u64; 1605 pResult->u.GCFar.sel = (uint16_t)(u64 >> 32); 1606 } 1607 else 1608 { 1609 pResult->u.GCFar.sel = (uint32_t)u64; 1610 pResult->u.GCFar.off = (uint16_t)(u64 >> 32); 1611 } 1612 break; 1613 1614 default: 1615 return VERR_PARSE_BAD_RESULT_TYPE; 1616 } 1617 break; 1618 1619 case DBGCVAR_TYPE_GC_PHYS: 1620 pResult->u.GCPhys = (RTGCPHYS)u64; 1621 break; 1622 1623 case DBGCVAR_TYPE_HC_FLAT: 1624 pResult->u.pvHCFlat = (void *)(uintptr_t)u64; 1625 break; 1626 1627 case DBGCVAR_TYPE_HC_FAR: 1628 switch (SYMREG_SIZE(pSymDesc->uUser)) 1629 { 1630 case 4: 1631 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL)) 1632 { 1633 pResult->u.HCFar.off = (uint16_t)u64; 1634 pResult->u.HCFar.sel = (uint16_t)(u64 >> 16); 1635 } 1636 else 1637 { 1638 pResult->u.HCFar.sel = (uint16_t)u64; 1639 pResult->u.HCFar.off = (uint16_t)(u64 >> 16); 1640 } 1641 break; 1642 case 6: 1643 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL)) 1644 { 1645 pResult->u.HCFar.off = (uint32_t)u64; 1646 pResult->u.HCFar.sel = (uint16_t)(u64 >> 32); 1647 } 1648 else 1649 { 1650 pResult->u.HCFar.sel = (uint32_t)u64; 1651 pResult->u.HCFar.off = (uint16_t)(u64 >> 32); 1652 } 1653 break; 1654 1655 default: 1656 return VERR_PARSE_BAD_RESULT_TYPE; 1657 } 1658 break; 1659 1660 case DBGCVAR_TYPE_HC_PHYS: 1661 pResult->u.GCPhys = (RTGCPHYS)u64; 1662 break; 1663 1664 case DBGCVAR_TYPE_NUMBER: 1665 pResult->u.u64Number = u64; 1666 break; 1667 1668 case DBGCVAR_TYPE_STRING: 1669 case DBGCVAR_TYPE_UNKNOWN: 1670 default: 1671 return VERR_PARSE_BAD_RESULT_TYPE; 1672 1673 } 1674 1675 return 0; 1676 } 1677 1678 1679 /** 1680 * Set builtin register symbol. 1681 * 1682 * The uUser is special for these symbol descriptors. See the SYMREG_* #defines. 1683 * 1684 * @returns 0 on success. 1685 * @returns VBox evaluation / parsing error code on failure. 1686 * The caller does the bitching. 1687 * @param pSymDesc Pointer to the symbol descriptor. 1688 * @param pCmdHlp Pointer to the command callback structure. 1689 * @param pValue The value to assign the symbol. 1690 */ 1691 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue) 1692 { 1693 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName)); 1694 1695 /* 1696 * pVM is required. 1697 */ 1698 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp); 1699 Assert(pDbgc->pVM); 1700 1701 /* 1702 * Get the right CPU context. 1703 */ 1704 PCPUMCTX pCtx; 1705 int rc; 1706 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER)) 1707 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx); 1708 else 1709 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx); 1710 if (VBOX_FAILURE(rc)) 1711 return rc; 1712 1713 /* 1714 * Check the new value. 1715 */ 1716 if (pValue->enmType != DBGCVAR_TYPE_NUMBER) 1717 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH; 1718 1719 /* 1720 * Set the value. 1721 */ 1722 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser); 1723 switch (SYMREG_SIZE(pSymDesc->uUser)) 1724 { 1725 case 1: 1726 *(uint8_t *)pvValue = (uint8_t)pValue->u.u64Number; 1727 break; 1728 case 2: 1729 *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number; 1730 break; 1731 case 4: 1732 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number; 1733 break; 1734 case 6: 1735 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number; 1736 ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32); 1737 break; 1738 case 8: 1739 *(uint64_t *)pvValue = pValue->u.u64Number; 1740 break; 1741 default: 1742 return VERR_PARSE_NOT_IMPLEMENTED; 1743 } 1744 1745 return VINF_SUCCESS; 1746 } 1747 1748 1749 1750 1751 1752 1753 1754 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 1755 // 1756 // 1757 // O p e r a t o r s 1758 // 1759 // 1760 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\// 108 /** Number of operators in the operator array. */ 109 const unsigned g_cOps = RT_ELEMENTS(g_aOps); 1761 110 1762 111 … … 1989 338 * @param pResult Where to store the result. 1990 339 */ 1991 staticDECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)340 DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult) 1992 341 { 1993 342 // LogFlow(("dbgcOpAddrFlat\n")); … … 2057 406 * @param pResult Where to store the result. 2058 407 */ 2059 staticDECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)408 DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult) 2060 409 { 2061 410 // LogFlow(("dbgcOpAddrPhys\n")); … … 2134 483 * @param pResult Where to store the result. 2135 484 */ 2136 staticDECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)485 DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult) 2137 486 { 2138 487 // LogFlow(("dbgcOpAddrPhys\n")); … … 2216 565 * @param pResult Where to store the result. 2217 566 */ 2218 staticDECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)567 DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult) 2219 568 { 2220 569 // LogFlow(("dbgcOpAddrHost\n")); … … 3201 1550 3202 1551 3203 3204 3205 3206 /**3207 * Output callback.3208 *3209 * @returns number of bytes written.3210 * @param pvArg User argument.3211 * @param pachChars Pointer to an array of utf-8 characters.3212 * @param cbChars Number of bytes in the character array pointed to by pachChars.3213 */3214 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)3215 {3216 PDBGC pDbgc = (PDBGC)pvArg;3217 if (cbChars)3218 {3219 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);3220 if (VBOX_FAILURE(rc))3221 {3222 pDbgc->rcOutput = rc;3223 cbChars = 0;3224 }3225 }3226 3227 return cbChars;3228 }3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3239 //3240 //3241 // C a l l b a c k H e l p e r s3242 //3243 //3244 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3245 3246 3247 3248 /**3249 * Command helper for writing text to the debug console.3250 *3251 * @returns VBox status.3252 * @param pCmdHlp Pointer to the command callback structure.3253 * @param pvBuf What to write.3254 * @param cbBuf Number of bytes to write.3255 * @param pcbWritten Where to store the number of bytes actually written.3256 * If NULL the entire buffer must be successfully written.3257 */3258 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)3259 {3260 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3261 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);3262 }3263 3264 3265 /**3266 * Command helper for writing formatted text to the debug console.3267 *3268 * @returns VBox status.3269 * @param pCmdHlp Pointer to the command callback structure.3270 * @param pcb Where to store the number of bytes written.3271 * @param pszFormat The format string.3272 * This is using the log formatter, so it's format extensions can be used.3273 * @param ... Arguments specified in the format string.3274 */3275 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)3276 {3277 /*3278 * Do the formatting and output.3279 */3280 va_list args;3281 va_start(args, pszFormat);3282 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);3283 va_end(args);3284 3285 return rc;3286 }3287 3288 /**3289 * Callback to format non-standard format specifiers.3290 *3291 * @returns The number of bytes formatted.3292 * @param pvArg Formatter argument.3293 * @param pfnOutput Pointer to output function.3294 * @param pvArgOutput Argument for the output function.3295 * @param ppszFormat Pointer to the format string pointer. Advance this till the char3296 * after the format specifier.3297 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.3298 * @param cchWidth Format Width. -1 if not specified.3299 * @param cchPrecision Format Precision. -1 if not specified.3300 * @param fFlags Flags (RTSTR_NTFS_*).3301 * @param chArgSize The argument size specifier, 'l' or 'L'.3302 */3303 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,3304 const char **ppszFormat, va_list *pArgs, int cchWidth,3305 int cchPrecision, unsigned fFlags, char chArgSize)3306 {3307 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);3308 if (**ppszFormat != 'D')3309 {3310 (*ppszFormat)++;3311 return 0;3312 }3313 3314 (*ppszFormat)++;3315 switch (**ppszFormat)3316 {3317 /*3318 * Print variable without range.3319 * The argument is a const pointer to the variable.3320 */3321 case 'V':3322 {3323 (*ppszFormat)++;3324 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);3325 switch (pVar->enmType)3326 {3327 case DBGCVAR_TYPE_GC_FLAT:3328 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);3329 case DBGCVAR_TYPE_GC_FAR:3330 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);3331 case DBGCVAR_TYPE_GC_PHYS:3332 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);3333 case DBGCVAR_TYPE_HC_FLAT:3334 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);3335 case DBGCVAR_TYPE_HC_FAR:3336 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);3337 case DBGCVAR_TYPE_HC_PHYS:3338 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);3339 case DBGCVAR_TYPE_STRING:3340 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);3341 case DBGCVAR_TYPE_NUMBER:3342 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);3343 3344 case DBGCVAR_TYPE_UNKNOWN:3345 default:3346 return pfnOutput(pvArgOutput, "??", 2);3347 }3348 }3349 3350 /*3351 * Print variable with range.3352 * The argument is a const pointer to the variable.3353 */3354 case 'v':3355 {3356 (*ppszFormat)++;3357 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);3358 3359 char szRange[32];3360 switch (pVar->enmRangeType)3361 {3362 case DBGCVAR_RANGE_NONE:3363 szRange[0] = '\0';3364 break;3365 case DBGCVAR_RANGE_ELEMENTS:3366 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);3367 break;3368 case DBGCVAR_RANGE_BYTES:3369 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);3370 break;3371 }3372 3373 switch (pVar->enmType)3374 {3375 case DBGCVAR_TYPE_GC_FLAT:3376 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);3377 case DBGCVAR_TYPE_GC_FAR:3378 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);3379 case DBGCVAR_TYPE_GC_PHYS:3380 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);3381 case DBGCVAR_TYPE_HC_FLAT:3382 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);3383 case DBGCVAR_TYPE_HC_FAR:3384 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);3385 case DBGCVAR_TYPE_HC_PHYS:3386 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);3387 case DBGCVAR_TYPE_STRING:3388 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);3389 case DBGCVAR_TYPE_NUMBER:3390 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);3391 3392 case DBGCVAR_TYPE_UNKNOWN:3393 default:3394 return pfnOutput(pvArgOutput, "??", 2);3395 }3396 }3397 3398 default:3399 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));3400 return 0;3401 }3402 }3403 3404 3405 /**3406 * Command helper for writing formatted text to the debug console.3407 *3408 * @returns VBox status.3409 * @param pCmdHlp Pointer to the command callback structure.3410 * @param pcb Where to store the number of bytes written.3411 * @param pszFormat The format string.3412 * This is using the log formatter, so it's format extensions can be used.3413 * @param args Arguments specified in the format string.3414 */3415 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)3416 {3417 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3418 3419 /*3420 * Do the formatting and output.3421 */3422 pDbgc->rcOutput = 0;3423 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);3424 3425 if (pcbWritten)3426 *pcbWritten = cb;3427 3428 return pDbgc->rcOutput;3429 }3430 3431 3432 /**3433 * Reports an error from a DBGF call.3434 *3435 * @returns VBox status code appropriate to return from a command.3436 * @param pCmdHlp Pointer to command helpers.3437 * @param rc The VBox status code returned by a DBGF call.3438 * @param pszFormat Format string for additional messages. Can be NULL.3439 * @param ... Format arguments, optional.3440 */3441 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)3442 {3443 switch (rc)3444 {3445 case VINF_SUCCESS:3446 break;3447 3448 default:3449 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");3450 if (VBOX_SUCCESS(rc) && pszFormat)3451 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);3452 break;3453 }3454 return rc;3455 }3456 3457 3458 /**3459 * Reports an error from a DBGF call.3460 *3461 * @returns VBox status code appropriate to return from a command.3462 * @param pCmdHlp Pointer to command helpers.3463 * @param rc The VBox status code returned by a DBGF call.3464 * @param pszFormat Format string for additional messages. Can be NULL.3465 * @param ... Format arguments, optional.3466 */3467 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)3468 {3469 va_list args;3470 va_start(args, pszFormat);3471 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);3472 va_end(args);3473 return rcRet;3474 }3475 3476 3477 /**3478 * Command helper for reading memory specified by a DBGC variable.3479 *3480 * @returns VBox status code appropriate to return from a command.3481 * @param pCmdHlp Pointer to the command callback structure.3482 * @param pVM VM handle if GC or physical HC address.3483 * @param pvBuffer Where to store the read data.3484 * @param cbRead Number of bytes to read.3485 * @param pVarPointer DBGC variable specifying where to start reading.3486 * @param pcbRead Where to store the number of bytes actually read.3487 * This optional, but it's useful when read GC virtual memory where a3488 * page in the requested range might not be present.3489 * If not specified not-present failure or end of a HC physical page3490 * will cause failure.3491 */3492 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)3493 {3494 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3495 3496 /*3497 * Dummy check.3498 */3499 if (cbRead == 0)3500 {3501 if (*pcbRead)3502 *pcbRead = 0;3503 return VINF_SUCCESS;3504 }3505 3506 /*3507 * Convert Far addresses getting size and the correct base address.3508 * Getting and checking the size is what makes this messy and slow.3509 */3510 DBGCVAR Var = *pVarPointer;3511 switch (pVarPointer->enmType)3512 {3513 case DBGCVAR_TYPE_GC_FAR:3514 {3515 /* Use DBGFR3AddrFromSelOff for the conversion. */3516 Assert(pDbgc->pVM);3517 DBGFADDRESS Address;3518 int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);3519 if (VBOX_FAILURE(rc))3520 return rc;3521 3522 /* don't bother with flat selectors (for now). */3523 if (!DBGFADDRESS_IS_FLAT(&Address))3524 {3525 SELMSELINFO SelInfo;3526 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);3527 if (VBOX_SUCCESS(rc))3528 {3529 RTGCUINTPTR cb; /* -1 byte */3530 if (SELMSelInfoIsExpandDown(&SelInfo))3531 {3532 if ( !SelInfo.Raw.Gen.u1Granularity3533 && Address.off > UINT16_C(0xffff))3534 return VERR_OUT_OF_SELECTOR_BOUNDS;3535 if (Address.off <= SelInfo.cbLimit)3536 return VERR_OUT_OF_SELECTOR_BOUNDS;3537 cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;3538 }3539 else3540 {3541 if (Address.off > SelInfo.cbLimit)3542 return VERR_OUT_OF_SELECTOR_BOUNDS;3543 cb = SelInfo.cbLimit - Address.off;3544 }3545 if (cbRead - 1 > cb)3546 {3547 if (!pcbRead)3548 return VERR_OUT_OF_SELECTOR_BOUNDS;3549 cbRead = cb + 1;3550 }3551 }3552 3553 Var.enmType = DBGCVAR_TYPE_GC_FLAT;3554 Var.u.GCFlat = Address.FlatPtr;3555 }3556 break;3557 }3558 3559 case DBGCVAR_TYPE_GC_FLAT:3560 case DBGCVAR_TYPE_GC_PHYS:3561 case DBGCVAR_TYPE_HC_FLAT:3562 case DBGCVAR_TYPE_HC_PHYS:3563 break;3564 3565 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */3566 default:3567 return VERR_NOT_IMPLEMENTED;3568 }3569 3570 3571 3572 /*3573 * Copy page by page.3574 */3575 size_t cbLeft = cbRead;3576 for (;;)3577 {3578 /*3579 * Calc read size.3580 */3581 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);3582 switch (pVarPointer->enmType)3583 {3584 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;3585 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;3586 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;3587 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! */3588 default: break;3589 }3590 3591 /*3592 * Perform read.3593 */3594 int rc;3595 switch (Var.enmType)3596 {3597 case DBGCVAR_TYPE_GC_FLAT:3598 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);3599 break;3600 case DBGCVAR_TYPE_GC_PHYS:3601 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);3602 break;3603 3604 case DBGCVAR_TYPE_HC_PHYS:3605 case DBGCVAR_TYPE_HC_FLAT:3606 case DBGCVAR_TYPE_HC_FAR:3607 {3608 DBGCVAR Var2;3609 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);3610 if (VBOX_SUCCESS(rc))3611 {3612 /** @todo protect this!!! */3613 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);3614 rc = 0;3615 }3616 else3617 rc = VERR_INVALID_POINTER;3618 break;3619 }3620 3621 default:3622 rc = VERR_PARSE_INCORRECT_ARG_TYPE;3623 }3624 3625 /*3626 * Check for failure.3627 */3628 if (VBOX_FAILURE(rc))3629 {3630 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)3631 return VINF_SUCCESS;3632 return rc;3633 }3634 3635 /*3636 * Next.3637 */3638 cbLeft -= cb;3639 if (!cbLeft)3640 break;3641 pvBuffer = (char *)pvBuffer + cb;3642 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);3643 if (VBOX_FAILURE(rc))3644 {3645 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)3646 return VINF_SUCCESS;3647 return rc;3648 }3649 }3650 3651 /*3652 * Done3653 */3654 if (pcbRead)3655 *pcbRead = cbRead;3656 return 0;3657 }3658 3659 /**3660 * Command helper for writing memory specified by a DBGC variable.3661 *3662 * @returns VBox status code appropriate to return from a command.3663 * @param pCmdHlp Pointer to the command callback structure.3664 * @param pVM VM handle if GC or physical HC address.3665 * @param pvBuffer What to write.3666 * @param cbWrite Number of bytes to write.3667 * @param pVarPointer DBGC variable specifying where to start reading.3668 * @param pcbWritten Where to store the number of bytes written.3669 * This is optional. If NULL be aware that some of the buffer3670 * might have been written to the specified address.3671 */3672 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)3673 {3674 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);3675 return VERR_NOT_IMPLEMENTED;3676 }3677 3678 3679 /**3680 * Evaluates an expression.3681 * (Hopefully the parser and functions are fully reentrant.)3682 *3683 * @returns VBox status code appropriate to return from a command.3684 * @param pCmdHlp Pointer to the command callback structure.3685 * @param pResult Where to store the result.3686 * @param pszExpr The expression. Format string with the format DBGC extensions.3687 * @param ... Format arguments.3688 */3689 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)3690 {3691 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3692 3693 /*3694 * Format the expression.3695 */3696 char szExprFormatted[2048];3697 va_list args;3698 va_start(args, pszExpr);3699 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);3700 va_end(args);3701 /* ignore overflows. */3702 3703 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);3704 }3705 3706 3707 /**3708 * Executes one command expression.3709 * (Hopefully the parser and functions are fully reentrant.)3710 *3711 * @returns VBox status code appropriate to return from a command.3712 * @param pCmdHlp Pointer to the command callback structure.3713 * @param pszExpr The expression. Format string with the format DBGC extensions.3714 * @param ... Format arguments.3715 */3716 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)3717 {3718 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3719 /* Save the scratch state. */3720 char *pszScratch = pDbgc->pszScratch;3721 unsigned iArg = pDbgc->iArg;3722 3723 /*3724 * Format the expression.3725 */3726 va_list args;3727 va_start(args, pszExpr);3728 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);3729 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);3730 va_end(args);3731 if (cb >= cbScratch)3732 return VERR_BUFFER_OVERFLOW;3733 3734 /*3735 * Execute the command.3736 * We save and restore the arg index and scratch buffer pointer.3737 */3738 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;3739 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);3740 3741 /* Restore the scratch state. */3742 pDbgc->iArg = iArg;3743 pDbgc->pszScratch = pszScratch;3744 3745 return rc;3746 }3747 3748 3749 /**3750 * Converts a DBGC variable to a DBGF address structure.3751 *3752 * @returns VBox status code.3753 * @param pCmdHlp Pointer to the command callback structure.3754 * @param pVar The variable to convert.3755 * @param pAddress The target address.3756 */3757 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)3758 {3759 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3760 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);3761 }3762 3763 3764 /**3765 * Converts a DBGC variable to a boolean.3766 *3767 * @returns VBox status code.3768 * @param pCmdHlp Pointer to the command callback structure.3769 * @param pVar The variable to convert.3770 * @param pf Where to store the boolean.3771 */3772 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)3773 {3774 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3775 NOREF(pDbgc);3776 3777 switch (pVar->enmType)3778 {3779 case DBGCVAR_TYPE_STRING:3780 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */3781 if ( !strcmp(pVar->u.pszString, "true")3782 || !strcmp(pVar->u.pszString, "True")3783 || !strcmp(pVar->u.pszString, "TRUE")3784 || !strcmp(pVar->u.pszString, "on")3785 || !strcmp(pVar->u.pszString, "On")3786 || !strcmp(pVar->u.pszString, "oN")3787 || !strcmp(pVar->u.pszString, "ON")3788 || !strcmp(pVar->u.pszString, "enabled")3789 || !strcmp(pVar->u.pszString, "Enabled")3790 || !strcmp(pVar->u.pszString, "DISABLED"))3791 {3792 *pf = true;3793 return VINF_SUCCESS;3794 }3795 if ( !strcmp(pVar->u.pszString, "false")3796 || !strcmp(pVar->u.pszString, "False")3797 || !strcmp(pVar->u.pszString, "FALSE")3798 || !strcmp(pVar->u.pszString, "off")3799 || !strcmp(pVar->u.pszString, "Off")3800 || !strcmp(pVar->u.pszString, "OFF")3801 || !strcmp(pVar->u.pszString, "disabled")3802 || !strcmp(pVar->u.pszString, "Disabled")3803 || !strcmp(pVar->u.pszString, "DISABLED"))3804 {3805 *pf = false;3806 return VINF_SUCCESS;3807 }3808 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */3809 3810 case DBGCVAR_TYPE_GC_FLAT:3811 case DBGCVAR_TYPE_GC_PHYS:3812 case DBGCVAR_TYPE_HC_FLAT:3813 case DBGCVAR_TYPE_HC_PHYS:3814 case DBGCVAR_TYPE_NUMBER:3815 *pf = pVar->u.u64Number != 0;3816 return VINF_SUCCESS;3817 3818 case DBGCVAR_TYPE_HC_FAR:3819 case DBGCVAR_TYPE_GC_FAR:3820 case DBGCVAR_TYPE_SYMBOL:3821 default:3822 return VERR_PARSE_INCORRECT_ARG_TYPE;3823 }3824 }3825 3826 3827 3828 3829 3830 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3831 //3832 //3833 // V a r i a b l e M a n i p u l a t i o n3834 //3835 //3836 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3837 3838 3839 3840 /** @todo move me!*/3841 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)3842 {3843 if (pVar)3844 {3845 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;3846 pVar->u.GCFlat = GCFlat;3847 pVar->enmRangeType = DBGCVAR_RANGE_NONE;3848 pVar->u64Range = 0;3849 }3850 }3851 3852 3853 /** @todo move me!*/3854 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)3855 {3856 if (pVar)3857 {3858 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;3859 pVar->u.GCFlat = GCFlat;3860 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;3861 pVar->u64Range = cb;3862 }3863 }3864 3865 3866 /** @todo move me!*/3867 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)3868 {3869 if (pVar)3870 {3871 if (pVar2)3872 *pVar = *pVar2;3873 else3874 {3875 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;3876 memset(&pVar->u, 0, sizeof(pVar->u));3877 pVar->enmRangeType = DBGCVAR_RANGE_NONE;3878 pVar->u64Range = 0;3879 }3880 }3881 }3882 3883 3884 /** @todo move me!*/3885 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)3886 {3887 if (pVar)3888 {3889 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;3890 pVar->u64Range = cb;3891 }3892 }3893 3894 3895 /** @todo move me!*/3896 void dbgcVarSetNoRange(PDBGCVAR pVar)3897 {3898 if (pVar)3899 {3900 pVar->enmRangeType = DBGCVAR_RANGE_NONE;3901 pVar->u64Range = 0;3902 }3903 }3904 3905 3906 /**3907 * Converts a DBGC variable to a DBGF address.3908 *3909 * @returns VBox status code.3910 * @param pDbgc The DBGC instance.3911 * @param pVar The variable.3912 * @param pAddress Where to store the address.3913 */3914 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)3915 {3916 AssertReturn(pVar, VERR_INVALID_PARAMETER);3917 switch (pVar->enmType)3918 {3919 case DBGCVAR_TYPE_GC_FLAT:3920 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);3921 return VINF_SUCCESS;3922 3923 case DBGCVAR_TYPE_NUMBER:3924 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);3925 return VINF_SUCCESS;3926 3927 case DBGCVAR_TYPE_GC_FAR:3928 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);3929 3930 case DBGCVAR_TYPE_STRING:3931 case DBGCVAR_TYPE_SYMBOL:3932 {3933 DBGCVAR Var;3934 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);3935 if (VBOX_FAILURE(rc))3936 return rc;3937 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);3938 }3939 3940 case DBGCVAR_TYPE_GC_PHYS:3941 case DBGCVAR_TYPE_HC_FLAT:3942 case DBGCVAR_TYPE_HC_FAR:3943 case DBGCVAR_TYPE_HC_PHYS:3944 default:3945 return VERR_PARSE_CONVERSION_FAILED;3946 }3947 }3948 3949 3950 3951 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3952 //3953 //3954 // B r e a k p o i n t M a n a g e m e n t3955 //3956 //3957 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3958 3959 3960 /**3961 * Adds a breakpoint to the DBGC breakpoint list.3962 */3963 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)3964 {3965 /*3966 * Check if it already exists.3967 */3968 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);3969 if (pBp)3970 return VERR_DBGC_BP_EXISTS;3971 3972 /*3973 * Add the breakpoint.3974 */3975 if (pszCmd)3976 pszCmd = RTStrStripL(pszCmd);3977 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;3978 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));3979 if (!pBp)3980 return VERR_NO_MEMORY;3981 if (cchCmd)3982 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);3983 else3984 pBp->szCmd[0] = '\0';3985 pBp->cchCmd = cchCmd;3986 pBp->iBp = iBp;3987 pBp->pNext = pDbgc->pFirstBp;3988 pDbgc->pFirstBp = pBp;3989 3990 return VINF_SUCCESS;3991 }3992 3993 /**3994 * Updates the a breakpoint.3995 *3996 * @returns VBox status code.3997 * @param pDbgc The DBGC instance.3998 * @param iBp The breakpoint to update.3999 * @param pszCmd The new command.4000 */4001 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)4002 {4003 /*4004 * Find the breakpoint.4005 */4006 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);4007 if (!pBp)4008 return VERR_DBGC_BP_NOT_FOUND;4009 4010 /*4011 * Do we need to reallocate?4012 */4013 if (pszCmd)4014 pszCmd = RTStrStripL(pszCmd);4015 if (!pszCmd || !*pszCmd)4016 pBp->szCmd[0] = '\0';4017 else4018 {4019 size_t cchCmd = strlen(pszCmd);4020 if (strlen(pBp->szCmd) >= cchCmd)4021 {4022 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);4023 pBp->cchCmd = cchCmd;4024 }4025 else4026 {4027 /*4028 * Yes, let's do it the simple way...4029 */4030 int rc = dbgcBpDelete(pDbgc, iBp);4031 AssertRC(rc);4032 return dbgcBpAdd(pDbgc, iBp, pszCmd);4033 }4034 }4035 return VINF_SUCCESS;4036 }4037 4038 4039 /**4040 * Deletes a breakpoint.4041 *4042 * @returns VBox status code.4043 * @param pDbgc The DBGC instance.4044 * @param iBp The breakpoint to delete.4045 */4046 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)4047 {4048 /*4049 * Search thru the list, when found unlink and free it.4050 */4051 PDBGCBP pBpPrev = NULL;4052 PDBGCBP pBp = pDbgc->pFirstBp;4053 for (; pBp; pBp = pBp->pNext)4054 {4055 if (pBp->iBp == iBp)4056 {4057 if (pBpPrev)4058 pBpPrev->pNext = pBp->pNext;4059 else4060 pDbgc->pFirstBp = pBp->pNext;4061 RTMemFree(pBp);4062 return VINF_SUCCESS;4063 }4064 pBpPrev = pBp;4065 }4066 4067 return VERR_DBGC_BP_NOT_FOUND;4068 }4069 4070 4071 /**4072 * Get a breakpoint.4073 *4074 * @returns Pointer to the breakpoint.4075 * @returns NULL if the breakpoint wasn't found.4076 * @param pDbgc The DBGC instance.4077 * @param iBp The breakpoint to get.4078 */4079 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)4080 {4081 /*4082 * Enumerate the list.4083 */4084 PDBGCBP pBp = pDbgc->pFirstBp;4085 for (; pBp; pBp = pBp->pNext)4086 if (pBp->iBp == iBp)4087 return pBp;4088 return NULL;4089 }4090 4091 4092 /**4093 * Executes the command of a breakpoint.4094 *4095 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.4096 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.4097 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.4098 * @returns VBox status code from dbgcProcessCommand() other wise.4099 * @param pDbgc The DBGC instance.4100 * @param iBp The breakpoint to execute.4101 */4102 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)4103 {4104 /*4105 * Find the breakpoint.4106 */4107 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);4108 if (!pBp)4109 return VERR_DBGC_BP_NOT_FOUND;4110 4111 /*4112 * Anything to do?4113 */4114 if (!pBp->cchCmd)4115 return VINF_DBGC_BP_NO_COMMAND;4116 4117 /*4118 * Execute the command.4119 * This means copying it to the scratch buffer and process it as if it4120 * were user input. We must save and restore the state of the scratch buffer.4121 */4122 /* Save the scratch state. */4123 char *pszScratch = pDbgc->pszScratch;4124 unsigned iArg = pDbgc->iArg;4125 4126 /* Copy the command to the scratch buffer. */4127 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);4128 if (pBp->cchCmd >= cbScratch)4129 return VERR_BUFFER_OVERFLOW;4130 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);4131 4132 /* Execute the command. */4133 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;4134 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);4135 4136 /* Restore the scratch state. */4137 pDbgc->iArg = iArg;4138 pDbgc->pszScratch = pszScratch;4139 4140 return rc;4141 }4142 4143 4144 4145 4146 4147 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4148 //4149 //4150 // I n p u t , p a r s i n g a n d l o g g i n g4151 //4152 //4153 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4154 4155 4156 4157 /**4158 * Prints any log lines from the log buffer.4159 *4160 * The caller must not call function this unless pDbgc->fLog is set.4161 *4162 * @returns VBox status. (output related)4163 * @param pDbgc Debugger console instance data.4164 */4165 static int dbgcProcessLog(PDBGC pDbgc)4166 {4167 /** @todo */4168 NOREF(pDbgc);4169 return 0;4170 }4171 4172 4173 4174 /**4175 * Handle input buffer overflow.4176 *4177 * Will read any available input looking for a '\n' to reset the buffer on.4178 *4179 * @returns VBox status.4180 * @param pDbgc Debugger console instance data.4181 */4182 static int dbgcInputOverflow(PDBGC pDbgc)4183 {4184 /*4185 * Assert overflow status and reset the input buffer.4186 */4187 if (!pDbgc->fInputOverflow)4188 {4189 pDbgc->fInputOverflow = true;4190 pDbgc->iRead = pDbgc->iWrite = 0;4191 pDbgc->cInputLines = 0;4192 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");4193 }4194 4195 /*4196 * Eat input till no more or there is a '\n'.4197 * When finding a '\n' we'll continue normal processing.4198 */4199 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))4200 {4201 size_t cbRead;4202 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);4203 if (VBOX_FAILURE(rc))4204 return rc;4205 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);4206 if (psz)4207 {4208 pDbgc->fInputOverflow = false;4209 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;4210 pDbgc->iWrite = (unsigned)cbRead;4211 pDbgc->cInputLines = 0;4212 break;4213 }4214 }4215 4216 return 0;4217 }4218 4219 4220 4221 /**4222 * Read input and do some preprocessing.4223 *4224 * @returns VBox status.4225 * In addition to the iWrite and achInput, cInputLines is maintained.4226 * In case of an input overflow the fInputOverflow flag will be set.4227 * @param pDbgc Debugger console instance data.4228 */4229 static int dbgcInputRead(PDBGC pDbgc)4230 {4231 /*4232 * We have ready input.4233 * Read it till we don't have any or we have a full input buffer.4234 */4235 int rc = 0;4236 do4237 {4238 /*4239 * More available buffer space?4240 */4241 size_t cbLeft;4242 if (pDbgc->iWrite > pDbgc->iRead)4243 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);4244 else4245 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;4246 if (!cbLeft)4247 {4248 /* overflow? */4249 if (!pDbgc->cInputLines)4250 rc = dbgcInputOverflow(pDbgc);4251 break;4252 }4253 4254 /*4255 * Read one char and interpret it.4256 */4257 char achRead[128];4258 size_t cbRead;4259 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);4260 if (VBOX_FAILURE(rc))4261 return rc;4262 char *psz = &achRead[0];4263 while (cbRead-- > 0)4264 {4265 char ch = *psz++;4266 switch (ch)4267 {4268 /*4269 * Ignore.4270 */4271 case '\0':4272 case '\r':4273 case '\a':4274 break;4275 4276 /*4277 * Backspace.4278 */4279 case '\b':4280 Log2(("DBGC: backspace\n"));4281 if (pDbgc->iRead != pDbgc->iWrite)4282 {4283 unsigned iWriteUndo = pDbgc->iWrite;4284 if (pDbgc->iWrite)4285 pDbgc->iWrite--;4286 else4287 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;4288 4289 if (pDbgc->achInput[pDbgc->iWrite] == '\n')4290 pDbgc->iWrite = iWriteUndo;4291 }4292 break;4293 4294 /*4295 * Add char to buffer.4296 */4297 case '\t':4298 case '\n':4299 case ';':4300 switch (ch)4301 {4302 case '\t': ch = ' '; break;4303 case '\n': pDbgc->cInputLines++; break;4304 }4305 default:4306 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));4307 pDbgc->achInput[pDbgc->iWrite] = ch;4308 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))4309 pDbgc->iWrite = 0;4310 break;4311 }4312 }4313 4314 /* Terminate it to make it easier to read in the debugger. */4315 pDbgc->achInput[pDbgc->iWrite] = '\0';4316 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));4317 4318 return rc;4319 }4320 4321 4322 /**4323 * Finds a builtin symbol.4324 * @returns Pointer to symbol descriptor on success.4325 * @returns NULL on failure.4326 * @param pDbgc The debug console instance.4327 * @param pszSymbol The symbol name.4328 */4329 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)4330 {4331 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)4332 if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))4333 return &g_aSyms[iSym];4334 4335 /** @todo externally registered symbols. */4336 NOREF(pDbgc);4337 return NULL;4338 }4339 4340 4341 /**4342 * Resolves a symbol (or tries to do so at least).4343 *4344 * @returns 0 on success.4345 * @returns VBox status on failure.4346 * @param pDbgc The debug console instance.4347 * @param pszSymbol The symbol name.4348 * @param enmType The result type.4349 * @param pResult Where to store the result.4350 */4351 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)4352 {4353 /*4354 * Builtin?4355 */4356 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);4357 if (pSymDesc)4358 {4359 if (!pSymDesc->pfnGet)4360 return VERR_PARSE_WRITEONLY_SYMBOL;4361 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);4362 }4363 4364 4365 /*4366 * Ask PDM.4367 */4368 /** @todo resolve symbols using PDM. */4369 4370 4371 /*4372 * Ask the debug info manager.4373 */4374 DBGFSYMBOL Symbol;4375 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);4376 if (VBOX_SUCCESS(rc))4377 {4378 /*4379 * Default return is a flat gc address.4380 */4381 memset(pResult, 0, sizeof(*pResult));4382 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;4383 pResult->u64Range = Symbol.cb;4384 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;4385 pResult->u.GCFlat = Symbol.Value;4386 DBGCVAR VarTmp;4387 switch (enmType)4388 {4389 /* nothing to do. */4390 case DBGCVAR_TYPE_GC_FLAT:4391 case DBGCVAR_TYPE_GC_FAR:4392 case DBGCVAR_TYPE_ANY:4393 return VINF_SUCCESS;4394 4395 /* simply make it numeric. */4396 case DBGCVAR_TYPE_NUMBER:4397 pResult->enmType = DBGCVAR_TYPE_NUMBER;4398 pResult->u.u64Number = Symbol.Value;4399 return VINF_SUCCESS;4400 4401 /* cast it. */4402 4403 case DBGCVAR_TYPE_GC_PHYS:4404 VarTmp = *pResult;4405 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);4406 4407 case DBGCVAR_TYPE_HC_FAR:4408 case DBGCVAR_TYPE_HC_FLAT:4409 VarTmp = *pResult;4410 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);4411 4412 case DBGCVAR_TYPE_HC_PHYS:4413 VarTmp = *pResult;4414 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);4415 4416 default:4417 AssertMsgFailed(("Internal error enmType=%d\n", enmType));4418 return VERR_INVALID_PARAMETER;4419 }4420 }4421 4422 return VERR_PARSE_NOT_IMPLEMENTED;4423 }4424 4425 4426 4427 /**4428 * Finds a routine.4429 *4430 * @returns Pointer to the command descriptor.4431 * If the request was for an external command, the caller is responsible for4432 * unlocking the external command list.4433 * @returns NULL if not found.4434 * @param pDbgc The debug console instance.4435 * @param pachName Pointer to the routine string (not terminated).4436 * @param cchName Length of the routine name.4437 * @param fExternal Whether or not the routine is external.4438 */4439 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)4440 {4441 if (!fExternal)4442 {4443 /* emulation first, so commands can be overloaded (info ++). */4444 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;4445 unsigned cLeft = pDbgc->cEmulationCmds;4446 while (cLeft-- > 0)4447 {4448 if ( !strncmp(pachName, pCmd->pszCmd, cchName)4449 && !pCmd->pszCmd[cchName])4450 return pCmd;4451 pCmd++;4452 }4453 4454 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)4455 {4456 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)4457 && !g_aCmds[iCmd].pszCmd[cchName])4458 return &g_aCmds[iCmd];4459 }4460 }4461 else4462 {4463 DBGCEXTCMDS_LOCK_RD();4464 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)4465 {4466 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)4467 {4468 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)4469 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])4470 return &pExtCmds->paCmds[iCmd];4471 }4472 }4473 DBGCEXTCMDS_UNLOCK_RD();4474 }4475 4476 NOREF(pDbgc);4477 return NULL;4478 }4479 4480 4481 1552 /** 4482 1553 * Searches for an operator descriptor which matches the start of … … 4491 1562 * @param chPrev The previous char. Some operators requires a blank in front of it. 4492 1563 */ 4493 staticPCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)1564 PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev) 4494 1565 { 4495 1566 PCDBGCOP pOp = NULL; … … 4528 1599 } 4529 1600 4530 4531 /**4532 * Initalizes g_bmOperatorChars.4533 */4534 static void dbgcInitOpCharBitMap(void)4535 {4536 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));4537 for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)4538 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);4539 }4540 4541 4542 /**4543 * Checks whether the character may be the start of an operator.4544 *4545 * @returns true/false.4546 * @param ch The character.4547 */4548 DECLINLINE(bool) dbgcIsOpChar(char ch)4549 {4550 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);4551 }4552 4553 4554 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)4555 {4556 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));4557 4558 /*4559 * Removing any quoting and escapings.4560 */4561 char ch = *pszExpr;4562 if (ch == '"' || ch == '\'' || ch == '`')4563 {4564 if (pszExpr[--cchExpr] != ch)4565 return VERR_PARSE_UNBALANCED_QUOTE;4566 cchExpr--;4567 pszExpr++;4568 4569 /** @todo string unescaping. */4570 }4571 pszExpr[cchExpr] = '\0';4572 4573 /*4574 * Make the argument.4575 */4576 pArg->pDesc = NULL;4577 pArg->pNext = NULL;4578 pArg->enmType = DBGCVAR_TYPE_STRING;4579 pArg->u.pszString = pszExpr;4580 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;4581 pArg->u64Range = cchExpr;4582 4583 NOREF(pDbgc);4584 return 0;4585 }4586 4587 4588 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)4589 {4590 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));4591 /*4592 * Convert to number.4593 */4594 uint64_t u64 = 0;4595 char ch;4596 while ((ch = *pszExpr) != '\0')4597 {4598 uint64_t u64Prev = u64;4599 unsigned u = ch - '0';4600 if (u < 10 && u < uBase)4601 u64 = u64 * uBase + u;4602 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)4603 u64 = u64 * uBase + u;4604 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)4605 u64 = u64 * uBase + u;4606 else4607 return VERR_PARSE_INVALID_NUMBER;4608 4609 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */4610 if (u64Prev != u64 / uBase)4611 return VERR_PARSE_NUMBER_TOO_BIG;4612 4613 /* next */4614 pszExpr++;4615 }4616 4617 /*4618 * Initialize the argument.4619 */4620 pArg->pDesc = NULL;4621 pArg->pNext = NULL;4622 pArg->enmType = DBGCVAR_TYPE_NUMBER;4623 pArg->u.u64Number = u64;4624 pArg->enmRangeType = DBGCVAR_RANGE_NONE;4625 pArg->u64Range = 0;4626 4627 return 0;4628 }4629 4630 4631 /**4632 * Match variable and variable descriptor, promoting the variable if necessary.4633 *4634 * @returns VBox status code.4635 * @param pDbgc Debug console instanace.4636 * @param pVar Variable.4637 * @param pVarDesc Variable descriptor.4638 */4639 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)4640 {4641 /*4642 * (If match or promoted to match, return, else break.)4643 */4644 switch (pVarDesc->enmCategory)4645 {4646 /*4647 * Anything goes4648 */4649 case DBGCVAR_CAT_ANY:4650 return VINF_SUCCESS;4651 4652 /*4653 * Pointer with and without range.4654 * We can try resolve strings and symbols as symbols and4655 * promote numbers to flat GC pointers.4656 */4657 case DBGCVAR_CAT_POINTER_NO_RANGE:4658 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)4659 return VERR_PARSE_NO_RANGE_ALLOWED;4660 /* fallthru */4661 case DBGCVAR_CAT_POINTER:4662 switch (pVar->enmType)4663 {4664 case DBGCVAR_TYPE_GC_FLAT:4665 case DBGCVAR_TYPE_GC_FAR:4666 case DBGCVAR_TYPE_GC_PHYS:4667 case DBGCVAR_TYPE_HC_FLAT:4668 case DBGCVAR_TYPE_HC_FAR:4669 case DBGCVAR_TYPE_HC_PHYS:4670 return VINF_SUCCESS;4671 4672 case DBGCVAR_TYPE_SYMBOL:4673 case DBGCVAR_TYPE_STRING:4674 {4675 DBGCVAR Var;4676 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);4677 if (VBOX_SUCCESS(rc))4678 {4679 /* deal with range */4680 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)4681 {4682 Var.enmRangeType = pVar->enmRangeType;4683 Var.u64Range = pVar->u64Range;4684 }4685 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)4686 Var.enmRangeType = DBGCVAR_RANGE_NONE;4687 *pVar = Var;4688 return rc;4689 }4690 break;4691 }4692 4693 case DBGCVAR_TYPE_NUMBER:4694 {4695 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;4696 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;4697 pVar->u.GCFlat = GCPtr;4698 return VINF_SUCCESS;4699 }4700 4701 default:4702 break;4703 }4704 break;4705 4706 /*4707 * GC pointer with and without range.4708 * We can try resolve strings and symbols as symbols and4709 * promote numbers to flat GC pointers.4710 */4711 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:4712 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)4713 return VERR_PARSE_NO_RANGE_ALLOWED;4714 /* fallthru */4715 case DBGCVAR_CAT_GC_POINTER:4716 switch (pVar->enmType)4717 {4718 case DBGCVAR_TYPE_GC_FLAT:4719 case DBGCVAR_TYPE_GC_FAR:4720 case DBGCVAR_TYPE_GC_PHYS:4721 return VINF_SUCCESS;4722 4723 case DBGCVAR_TYPE_HC_FLAT:4724 case DBGCVAR_TYPE_HC_FAR:4725 case DBGCVAR_TYPE_HC_PHYS:4726 return VERR_PARSE_CONVERSION_FAILED;4727 4728 case DBGCVAR_TYPE_SYMBOL:4729 case DBGCVAR_TYPE_STRING:4730 {4731 DBGCVAR Var;4732 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);4733 if (VBOX_SUCCESS(rc))4734 {4735 /* deal with range */4736 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)4737 {4738 Var.enmRangeType = pVar->enmRangeType;4739 Var.u64Range = pVar->u64Range;4740 }4741 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)4742 Var.enmRangeType = DBGCVAR_RANGE_NONE;4743 *pVar = Var;4744 return rc;4745 }4746 break;4747 }4748 4749 case DBGCVAR_TYPE_NUMBER:4750 {4751 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;4752 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;4753 pVar->u.GCFlat = GCPtr;4754 return VINF_SUCCESS;4755 }4756 4757 default:4758 break;4759 }4760 break;4761 4762 /*4763 * Number with or without a range.4764 * Numbers can be resolved from symbols, but we cannot demote a pointer4765 * to a number.4766 */4767 case DBGCVAR_CAT_NUMBER_NO_RANGE:4768 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)4769 return VERR_PARSE_NO_RANGE_ALLOWED;4770 /* fallthru */4771 case DBGCVAR_CAT_NUMBER:4772 switch (pVar->enmType)4773 {4774 case DBGCVAR_TYPE_NUMBER:4775 return VINF_SUCCESS;4776 4777 case DBGCVAR_TYPE_SYMBOL:4778 case DBGCVAR_TYPE_STRING:4779 {4780 DBGCVAR Var;4781 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);4782 if (VBOX_SUCCESS(rc))4783 {4784 *pVar = Var;4785 return rc;4786 }4787 break;4788 }4789 default:4790 break;4791 }4792 break;4793 4794 /*4795 * Strings can easily be made from symbols (and of course strings).4796 * We could consider reformatting the addresses and numbers into strings later...4797 */4798 case DBGCVAR_CAT_STRING:4799 switch (pVar->enmType)4800 {4801 case DBGCVAR_TYPE_SYMBOL:4802 pVar->enmType = DBGCVAR_TYPE_STRING;4803 /* fallthru */4804 case DBGCVAR_TYPE_STRING:4805 return VINF_SUCCESS;4806 default:4807 break;4808 }4809 break;4810 4811 /*4812 * Symol is pretty much the same thing as a string (at least until we actually implement it).4813 */4814 case DBGCVAR_CAT_SYMBOL:4815 switch (pVar->enmType)4816 {4817 case DBGCVAR_TYPE_STRING:4818 pVar->enmType = DBGCVAR_TYPE_SYMBOL;4819 /* fallthru */4820 case DBGCVAR_TYPE_SYMBOL:4821 return VINF_SUCCESS;4822 default:4823 break;4824 }4825 break;4826 4827 /*4828 * Anything else is illegal.4829 */4830 default:4831 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));4832 break;4833 }4834 4835 return VERR_PARSE_NO_ARGUMENT_MATCH;4836 }4837 4838 4839 /**4840 * Matches a set of variables with a description set.4841 *4842 * This is typically used for routine arguments before a call. The effects in4843 * addition to the validation, is that some variables might be propagated to4844 * other types in order to match the description. The following transformations4845 * are supported:4846 * - String reinterpreted as a symbol and resolved to a number or pointer.4847 * - Number to a pointer.4848 * - Pointer to a number.4849 * @returns 0 on success with paVars.4850 * @returns VBox error code for match errors.4851 */4852 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,4853 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,4854 PDBGCVAR paVars, unsigned cVars)4855 {4856 /*4857 * Just do basic min / max checks first.4858 */4859 if (cVars < cVarsMin)4860 return VERR_PARSE_TOO_FEW_ARGUMENTS;4861 if (cVars > cVarsMax)4862 return VERR_PARSE_TOO_MANY_ARGUMENTS;4863 4864 /*4865 * Match the descriptors and actual variables.4866 */4867 PCDBGCVARDESC pPrevDesc = NULL;4868 unsigned cCurDesc = 0;4869 unsigned iVar = 0;4870 unsigned iVarDesc = 0;4871 while (iVar < cVars)4872 {4873 /* walk the descriptors */4874 if (iVarDesc >= cVarDescs)4875 return VERR_PARSE_TOO_MANY_ARGUMENTS;4876 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV4877 && &paVarDescs[iVarDesc - 1] != pPrevDesc)4878 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)4879 {4880 iVarDesc++;4881 if (iVarDesc >= cVarDescs)4882 return VERR_PARSE_TOO_MANY_ARGUMENTS;4883 cCurDesc = 0;4884 }4885 4886 /*4887 * Skip thru optional arguments until we find something which matches4888 * or can easily be promoted to what the descriptor want.4889 */4890 for (;;)4891 {4892 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);4893 if (VBOX_SUCCESS(rc))4894 {4895 paVars[iVar].pDesc = &paVarDescs[iVarDesc];4896 cCurDesc++;4897 break;4898 }4899 4900 /* can we advance? */4901 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)4902 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;4903 if (++iVarDesc >= cVarDescs)4904 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;4905 cCurDesc = 0;4906 }4907 4908 /* next var */4909 iVar++;4910 }4911 4912 /*4913 * Check that the rest of the descriptors are optional.4914 */4915 while (iVarDesc < cVarDescs)4916 {4917 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)4918 return VERR_PARSE_TOO_FEW_ARGUMENTS;4919 cCurDesc = 0;4920 4921 /* next */4922 iVarDesc++;4923 }4924 4925 return 0;4926 }4927 4928 4929 /**4930 * Evaluates one argument with respect to unary operators.4931 *4932 * @returns 0 on success. pResult contains the result.4933 * @returns VBox error code on parse or other evaluation error.4934 *4935 * @param pDbgc Debugger console instance data.4936 * @param pszExpr The expression string.4937 * @param pResult Where to store the result of the expression evaluation.4938 */4939 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)4940 {4941 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));4942 4943 /*4944 * The state of the expression is now such that it will start by zero or more4945 * unary operators and being followed by an expression of some kind.4946 * The expression is either plain or in parenthesis.4947 *4948 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)4949 * ASSUME: unary operators are all of equal precedence.4950 */4951 int rc = 0;4952 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');4953 if (pOp)4954 {4955 /* binary operators means syntax error. */4956 if (pOp->fBinary)4957 return VERR_PARSE_UNEXPECTED_OPERATOR;4958 4959 /*4960 * If the next expression (the one following the unary operator) is in a4961 * parenthesis a full eval is needed. If not the unary eval will suffice.4962 */4963 /* calc and strip next expr. */4964 char *pszExpr2 = pszExpr + pOp->cchName;4965 while (isblank(*pszExpr2))4966 pszExpr2++;4967 4968 if (!*pszExpr2)4969 rc = VERR_PARSE_EMPTY_ARGUMENT;4970 else4971 {4972 DBGCVAR Arg;4973 if (*pszExpr2 == '(')4974 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);4975 else4976 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);4977 if (VBOX_SUCCESS(rc))4978 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);4979 }4980 }4981 else4982 {4983 /*4984 * Didn't find any operators, so it we have to check if this can be an4985 * function call before assuming numeric or string expression.4986 *4987 * (ASSUMPTIONS:)4988 * A function name only contains alphanumerical chars and it can not start4989 * with a numerical character.4990 * Immediately following the name is a parenthesis which must over4991 * the remaining part of the expression.4992 */4993 bool fExternal = *pszExpr == '.';4994 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;4995 char *pszFunEnd = NULL;4996 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))4997 {4998 pszFunEnd = pszExpr + 1;4999 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))5000 pszFunEnd++;5001 if (*pszFunEnd != '(')5002 pszFunEnd = NULL;5003 }5004 5005 if (pszFunEnd)5006 {5007 /*5008 * Ok, it's a function call.5009 */5010 if (fExternal)5011 pszExpr++, cchExpr--;5012 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);5013 if (!pFun)5014 return VERR_PARSE_FUNCTION_NOT_FOUND;5015 if (!pFun->pResultDesc)5016 return VERR_PARSE_NOT_A_FUNCTION;5017 5018 /*5019 * Parse the expression in parenthesis.5020 */5021 cchExpr -= pszFunEnd - pszExpr;5022 pszExpr = pszFunEnd;5023 /** @todo implement multiple arguments. */5024 DBGCVAR Arg;5025 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);5026 if (!rc)5027 {5028 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);5029 if (!rc)5030 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);5031 }5032 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)5033 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);5034 }5035 else5036 {5037 /*5038 * Didn't find any operators, so it must be a plain expression.5039 * This might be numeric or a string expression.5040 */5041 char ch = pszExpr[0];5042 char ch2 = pszExpr[1];5043 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))5044 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);5045 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))5046 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);5047 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))5048 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);5049 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.5050 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))5051 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);5052 else5053 {5054 /*5055 * Hexadecimal number or a string?5056 */5057 char *psz = pszExpr;5058 while (isxdigit(*psz))5059 psz++;5060 if (!*psz)5061 rc = dbgcEvalSubNum(pszExpr, 16, pResult);5062 else if ((*psz == 'h' || *psz == 'H') && !psz[1])5063 {5064 *psz = '\0';5065 rc = dbgcEvalSubNum(pszExpr, 16, pResult);5066 }5067 else5068 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);5069 }5070 }5071 }5072 5073 return rc;5074 }5075 5076 5077 /**5078 * Evaluates one argument.5079 *5080 * @returns 0 on success. pResult contains the result.5081 * @returns VBox error code on parse or other evaluation error.5082 *5083 * @param pDbgc Debugger console instance data.5084 * @param pszExpr The expression string.5085 * @param pResult Where to store the result of the expression evaluation.5086 */5087 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)5088 {5089 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));5090 /*5091 * First we need to remove blanks in both ends.5092 * ASSUMES: There is no quoting unless the entire expression is a string.5093 */5094 5095 /* stripping. */5096 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))5097 pszExpr[--cchExpr] = '\0';5098 while (isblank(*pszExpr))5099 pszExpr++, cchExpr--;5100 if (!*pszExpr)5101 return VERR_PARSE_EMPTY_ARGUMENT;5102 5103 /* it there is any kind of quoting in the expression, it's string meat. */5104 if (strpbrk(pszExpr, "\"'`"))5105 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);5106 5107 /*5108 * Check if there are any parenthesis which needs removing.5109 */5110 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')5111 {5112 do5113 {5114 unsigned cPar = 1;5115 char *psz = pszExpr + 1;5116 char ch;5117 while ((ch = *psz) != '\0')5118 {5119 if (ch == '(')5120 cPar++;5121 else if (ch == ')')5122 {5123 if (cPar <= 0)5124 return VERR_PARSE_UNBALANCED_PARENTHESIS;5125 cPar--;5126 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */5127 break;5128 }5129 /* next */5130 psz++;5131 }5132 if (ch)5133 break;5134 5135 /* remove the parenthesis. */5136 pszExpr++;5137 cchExpr -= 2;5138 pszExpr[cchExpr] = '\0';5139 5140 /* strip blanks. */5141 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))5142 pszExpr[--cchExpr] = '\0';5143 while (isblank(*pszExpr))5144 pszExpr++, cchExpr--;5145 if (!*pszExpr)5146 return VERR_PARSE_EMPTY_ARGUMENT;5147 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');5148 }5149 5150 /* tabs to spaces. */5151 char *psz = pszExpr;5152 while ((psz = strchr(psz, '\t')) != NULL)5153 *psz = ' ';5154 5155 /*5156 * Now, we need to look for the binary operator with the lowest precedence.5157 *5158 * If there are no operators we're left with a simple expression which we5159 * evaluate with respect to unary operators5160 */5161 char *pszOpSplit = NULL;5162 PCDBGCOP pOpSplit = NULL;5163 unsigned cBinaryOps = 0;5164 unsigned cPar = 0;5165 char ch;5166 char chPrev = ' ';5167 bool fBinary = false;5168 psz = pszExpr;5169 5170 while ((ch = *psz) != '\0')5171 {5172 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));5173 /*5174 * Parenthesis.5175 */5176 if (ch == '(')5177 {5178 cPar++;5179 fBinary = false;5180 }5181 else if (ch == ')')5182 {5183 if (cPar <= 0)5184 return VERR_PARSE_UNBALANCED_PARENTHESIS;5185 cPar--;5186 fBinary = true;5187 }5188 /*5189 * Potential operator.5190 */5191 else if (cPar == 0 && !isblank(ch))5192 {5193 PCDBGCOP pOp = dbgcIsOpChar(ch)5194 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)5195 : NULL;5196 if (pOp)5197 {5198 /* If not the right kind of operator we've got a syntax error. */5199 if (pOp->fBinary != fBinary)5200 return VERR_PARSE_UNEXPECTED_OPERATOR;5201 5202 /*5203 * Update the parse state and skip the operator.5204 */5205 if (!pOpSplit)5206 {5207 pOpSplit = pOp;5208 pszOpSplit = psz;5209 cBinaryOps = fBinary;5210 }5211 else if (fBinary)5212 {5213 cBinaryOps++;5214 if (pOp->iPrecedence >= pOpSplit->iPrecedence)5215 {5216 pOpSplit = pOp;5217 pszOpSplit = psz;5218 }5219 }5220 5221 psz += pOp->cchName - 1;5222 fBinary = false;5223 }5224 else5225 fBinary = true;5226 }5227 5228 /* next */5229 psz++;5230 chPrev = ch;5231 } /* parse loop. */5232 5233 5234 /*5235 * Either we found an operator to divide the expression by5236 * or we didn't find any. In the first case it's divide and5237 * conquer. In the latter it's a single expression which5238 * needs dealing with its unary operators if any.5239 */5240 int rc;5241 if ( cBinaryOps5242 && pOpSplit->fBinary)5243 {5244 /* process 1st sub expression. */5245 *pszOpSplit = '\0';5246 DBGCVAR Arg1;5247 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);5248 if (VBOX_SUCCESS(rc))5249 {5250 /* process 2nd sub expression. */5251 char *psz2 = pszOpSplit + pOpSplit->cchName;5252 DBGCVAR Arg2;5253 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);5254 if (VBOX_SUCCESS(rc))5255 /* apply the operator. */5256 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);5257 }5258 }5259 else if (cBinaryOps)5260 {5261 /* process sub expression. */5262 pszOpSplit += pOpSplit->cchName;5263 DBGCVAR Arg;5264 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);5265 if (VBOX_SUCCESS(rc))5266 /* apply the operator. */5267 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);5268 }5269 else5270 /* plain expression or using unary operators perhaps with paratheses. */5271 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);5272 5273 return rc;5274 }5275 5276 5277 /**5278 * Parses the arguments of one command.5279 *5280 * @returns 0 on success.5281 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.5282 * @param pDbgc Debugger console instance data.5283 * @param pCmd Pointer to the command descriptor.5284 * @param pszArg Pointer to the arguments to parse.5285 * @param paArgs Where to store the parsed arguments.5286 * @param cArgs Size of the paArgs array.5287 * @param pcArgs Where to store the number of arguments.5288 * In the event of an error this is used to store the index of the offending argument.5289 */5290 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)5291 {5292 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));5293 /*5294 * Check if we have any argument and if the command takes any.5295 */5296 *pcArgs = 0;5297 /* strip leading blanks. */5298 while (*pszArgs && isblank(*pszArgs))5299 pszArgs++;5300 if (!*pszArgs)5301 {5302 if (!pCmd->cArgsMin)5303 return 0;5304 return VERR_PARSE_TOO_FEW_ARGUMENTS;5305 }5306 /** @todo fixme - foo() doesn't work. */5307 if (!pCmd->cArgsMax)5308 return VERR_PARSE_TOO_MANY_ARGUMENTS;5309 5310 /*5311 * This is a hack, it's "temporary" and should go away "when" the parser is5312 * modified to match arguments while parsing.5313 */5314 if ( pCmd->cArgsMax == 15315 && pCmd->cArgsMin == 15316 && pCmd->cArgDescs == 15317 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING5318 && cArgs >= 1)5319 {5320 *pcArgs = 1;5321 RTStrStripR(pszArgs);5322 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);5323 }5324 5325 5326 /*5327 * The parse loop.5328 */5329 PDBGCVAR pArg0 = &paArgs[0];5330 PDBGCVAR pArg = pArg0;5331 *pcArgs = 0;5332 do5333 {5334 /*5335 * Can we have another argument?5336 */5337 if (*pcArgs >= pCmd->cArgsMax)5338 return VERR_PARSE_TOO_MANY_ARGUMENTS;5339 if (pArg >= &paArgs[cArgs])5340 return VERR_PARSE_ARGUMENT_OVERFLOW;5341 5342 /*5343 * Find the end of the argument.5344 */5345 int cPar = 0;5346 char chQuote = '\0';5347 char *pszEnd = NULL;5348 char *psz = pszArgs;5349 char ch;5350 bool fBinary = false;5351 for (;;)5352 {5353 /*5354 * Check for the end.5355 */5356 if ((ch = *psz) == '\0')5357 {5358 if (chQuote)5359 return VERR_PARSE_UNBALANCED_QUOTE;5360 if (cPar)5361 return VERR_PARSE_UNBALANCED_PARENTHESIS;5362 pszEnd = psz;5363 break;5364 }5365 /*5366 * When quoted we ignore everything but the quotation char.5367 * We use the REXX way of escaping the quotation char, i.e. double occurence.5368 */5369 else if (ch == '\'' || ch == '"' || ch == '`')5370 {5371 if (chQuote)5372 {5373 /* end quote? */5374 if (ch == chQuote)5375 {5376 if (psz[1] == ch)5377 psz++; /* skip the escaped quote char */5378 else5379 chQuote = '\0'; /* end of quoted string. */5380 }5381 }5382 else5383 chQuote = ch; /* open new quote */5384 }5385 /*5386 * Parenthesis can of course be nested.5387 */5388 else if (ch == '(')5389 {5390 cPar++;5391 fBinary = false;5392 }5393 else if (ch == ')')5394 {5395 if (!cPar)5396 return VERR_PARSE_UNBALANCED_PARENTHESIS;5397 cPar--;5398 fBinary = true;5399 }5400 else if (!chQuote && !cPar)5401 {5402 /*5403 * Encountering blanks may mean the end of it all. A binary operator5404 * will force continued parsing.5405 */5406 if (isblank(*psz))5407 {5408 pszEnd = psz++; /* just in case. */5409 while (isblank(*psz))5410 psz++;5411 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');5412 if (!pOp || pOp->fBinary != fBinary)5413 break; /* the end. */5414 psz += pOp->cchName;5415 while (isblank(*psz)) /* skip blanks so we don't get here again */5416 psz++;5417 fBinary = false;5418 continue;5419 }5420 5421 /*5422 * Look for operators without a space up front.5423 */5424 if (dbgcIsOpChar(*psz))5425 {5426 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');5427 if (pOp)5428 {5429 if (pOp->fBinary != fBinary)5430 {5431 pszEnd = psz;5432 /** @todo this is a parsing error really. */5433 break; /* the end. */5434 }5435 psz += pOp->cchName;5436 while (isblank(*psz)) /* skip blanks so we don't get here again */5437 psz++;5438 fBinary = false;5439 continue;5440 }5441 }5442 fBinary = true;5443 }5444 5445 /* next char */5446 psz++;5447 }5448 *pszEnd = '\0';5449 /* (psz = next char to process) */5450 5451 /*5452 * Parse and evaluate the argument.5453 */5454 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);5455 if (VBOX_FAILURE(rc))5456 return rc;5457 5458 /*5459 * Next.5460 */5461 pArg++;5462 (*pcArgs)++;5463 pszArgs = psz;5464 while (*pszArgs && isblank(*pszArgs))5465 pszArgs++;5466 } while (*pszArgs);5467 5468 /*5469 * Match the arguments.5470 */5471 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);5472 }5473 5474 5475 /**5476 * Process one command.5477 *5478 * @returns VBox status code. Any error indicates the termination of the console session.5479 * @param pDbgc Debugger console instance data.5480 * @param pszCmd Pointer to the command.5481 * @param cchCmd Length of the command.5482 */5483 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)5484 {5485 char *pszCmdInput = pszCmd;5486 5487 /*5488 * Skip blanks.5489 */5490 while (isblank(*pszCmd))5491 pszCmd++, cchCmd--;5492 5493 /* external command? */5494 bool fExternal = *pszCmd == '.';5495 if (fExternal)5496 pszCmd++, cchCmd--;5497 5498 /*5499 * Find arguments.5500 */5501 char *pszArgs = pszCmd;5502 while (isalnum(*pszArgs))5503 pszArgs++;5504 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))5505 {5506 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);5507 return 0;5508 }5509 5510 /*5511 * Find the command.5512 */5513 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);5514 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))5515 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);5516 5517 /*5518 * Parse arguments (if any).5519 */5520 unsigned cArgs;5521 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);5522 5523 /*5524 * Execute the command.5525 */5526 if (!rc)5527 {5528 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);5529 }5530 else5531 {5532 /* report parse / eval error. */5533 switch (rc)5534 {5535 case VERR_PARSE_TOO_FEW_ARGUMENTS:5536 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5537 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);5538 break;5539 case VERR_PARSE_TOO_MANY_ARGUMENTS:5540 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5541 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);5542 break;5543 case VERR_PARSE_ARGUMENT_OVERFLOW:5544 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5545 "Syntax error: Too many arguments.\n");5546 break;5547 case VERR_PARSE_UNBALANCED_QUOTE:5548 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5549 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);5550 break;5551 case VERR_PARSE_UNBALANCED_PARENTHESIS:5552 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5553 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);5554 break;5555 case VERR_PARSE_EMPTY_ARGUMENT:5556 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5557 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);5558 break;5559 case VERR_PARSE_UNEXPECTED_OPERATOR:5560 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5561 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);5562 break;5563 case VERR_PARSE_INVALID_NUMBER:5564 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5565 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);5566 break;5567 case VERR_PARSE_NUMBER_TOO_BIG:5568 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5569 "Error: Numeric overflow (argument %d).\n", cArgs);5570 break;5571 case VERR_PARSE_INVALID_OPERATION:5572 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5573 "Error: Invalid operation attempted (argument %d).\n", cArgs);5574 break;5575 case VERR_PARSE_FUNCTION_NOT_FOUND:5576 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5577 "Error: Function not found (argument %d).\n", cArgs);5578 break;5579 case VERR_PARSE_NOT_A_FUNCTION:5580 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5581 "Error: The function specified is not a function (argument %d).\n", cArgs);5582 break;5583 case VERR_PARSE_NO_MEMORY:5584 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5585 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);5586 break;5587 case VERR_PARSE_INCORRECT_ARG_TYPE:5588 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5589 "Error: Incorrect argument type (argument %d?).\n", cArgs);5590 break;5591 case VERR_PARSE_VARIABLE_NOT_FOUND:5592 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5593 "Error: An undefined variable was referenced (argument %d).\n", cArgs);5594 break;5595 case VERR_PARSE_CONVERSION_FAILED:5596 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5597 "Error: A conversion between two types failed (argument %d).\n", cArgs);5598 break;5599 case VERR_PARSE_NOT_IMPLEMENTED:5600 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5601 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);5602 break;5603 case VERR_PARSE_BAD_RESULT_TYPE:5604 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5605 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);5606 break;5607 case VERR_PARSE_WRITEONLY_SYMBOL:5608 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5609 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);5610 break;5611 5612 default:5613 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5614 "Error: Unknown error %d!\n", rc);5615 return rc;5616 }5617 5618 /*5619 * Parse errors are non fatal.5620 */5621 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)5622 rc = 0;5623 }5624 5625 return rc;5626 }5627 5628 5629 /**5630 * Process all commands current in the buffer.5631 *5632 * @returns VBox status code. Any error indicates the termination of the console session.5633 * @param pDbgc Debugger console instance data.5634 */5635 static int dbgcProcessCommands(PDBGC pDbgc)5636 {5637 int rc = 0;5638 while (pDbgc->cInputLines)5639 {5640 /*5641 * Empty the log buffer if we're hooking the log.5642 */5643 if (pDbgc->fLog)5644 {5645 rc = dbgcProcessLog(pDbgc);5646 if (VBOX_FAILURE(rc))5647 break;5648 }5649 5650 if (pDbgc->iRead == pDbgc->iWrite)5651 {5652 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));5653 pDbgc->cInputLines = 0;5654 return 0;5655 }5656 5657 /*5658 * Copy the command to the parse buffer.5659 */5660 char ch;5661 char *psz = &pDbgc->achInput[pDbgc->iRead];5662 char *pszTrg = &pDbgc->achScratch[0];5663 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )5664 {5665 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])5666 psz = &pDbgc->achInput[0];5667 5668 if (psz == &pDbgc->achInput[pDbgc->iWrite])5669 {5670 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));5671 pDbgc->cInputLines = 0;5672 return 0;5673 }5674 5675 pszTrg++;5676 }5677 *pszTrg = '\0';5678 5679 /*5680 * Advance the buffer.5681 */5682 pDbgc->iRead = psz - &pDbgc->achInput[0];5683 if (ch == '\n')5684 pDbgc->cInputLines--;5685 5686 /*5687 * Parse and execute this command.5688 */5689 pDbgc->pszScratch = psz;5690 pDbgc->iArg = 0;5691 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);5692 if (rc)5693 break;5694 }5695 5696 return rc;5697 }5698 5699 5700 /**5701 * Reads input, parses it and executes commands on '\n'.5702 *5703 * @returns VBox status.5704 * @param pDbgc Debugger console instance data.5705 */5706 static int dbgcProcessInput(PDBGC pDbgc)5707 {5708 /*5709 * We know there's input ready, so let's read it first.5710 */5711 int rc = dbgcInputRead(pDbgc);5712 if (VBOX_FAILURE(rc))5713 return rc;5714 5715 /*5716 * Now execute any ready commands.5717 */5718 if (pDbgc->cInputLines)5719 {5720 /** @todo this fReady stuff is broken. */5721 pDbgc->fReady = false;5722 rc = dbgcProcessCommands(pDbgc);5723 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)5724 pDbgc->fReady = true;5725 if ( VBOX_SUCCESS(rc)5726 && pDbgc->iRead == pDbgc->iWrite5727 && pDbgc->fReady)5728 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");5729 }5730 5731 return rc;5732 }5733 5734 5735 /**5736 * Gets the event context identifier string.5737 * @returns Read only string.5738 * @param enmCtx The context.5739 */5740 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)5741 {5742 switch (enmCtx)5743 {5744 case DBGFEVENTCTX_RAW: return "raw";5745 case DBGFEVENTCTX_REM: return "rem";5746 case DBGFEVENTCTX_HWACCL: return "hwaccl";5747 case DBGFEVENTCTX_HYPER: return "hyper";5748 case DBGFEVENTCTX_OTHER: return "other";5749 5750 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";5751 default:5752 AssertMsgFailed(("enmCtx=%d\n", enmCtx));5753 return "!Unknown Event Ctx!";5754 }5755 }5756 5757 5758 /**5759 * Processes debugger events.5760 *5761 * @returns VBox status.5762 * @param pDbgc DBGC Instance data.5763 * @param pEvent Pointer to event data.5764 */5765 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)5766 {5767 /*5768 * Flush log first.5769 */5770 if (pDbgc->fLog)5771 {5772 int rc = dbgcProcessLog(pDbgc);5773 if (VBOX_FAILURE(rc))5774 return rc;5775 }5776 5777 /*5778 * Process the event.5779 */5780 pDbgc->pszScratch = &pDbgc->achInput[0];5781 pDbgc->iArg = 0;5782 bool fPrintPrompt = true;5783 int rc = VINF_SUCCESS;5784 switch (pEvent->enmType)5785 {5786 /*5787 * The first part is events we have initiated with commands.5788 */5789 case DBGFEVENT_HALT_DONE:5790 {5791 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",5792 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));5793 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */5794 if (VBOX_SUCCESS(rc))5795 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5796 break;5797 }5798 5799 5800 /*5801 * The second part is events which can occur at any time.5802 */5803 case DBGFEVENT_FATAL_ERROR:5804 {5805 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",5806 dbgcGetEventCtx(pEvent->enmCtx));5807 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */5808 if (VBOX_SUCCESS(rc))5809 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5810 break;5811 }5812 5813 case DBGFEVENT_BREAKPOINT:5814 case DBGFEVENT_BREAKPOINT_HYPER:5815 {5816 bool fRegCtxGuest = pDbgc->fRegCtxGuest;5817 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;5818 5819 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);5820 switch (rc)5821 {5822 case VERR_DBGC_BP_NOT_FOUND:5823 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",5824 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));5825 break;5826 5827 case VINF_DBGC_BP_NO_COMMAND:5828 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",5829 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));5830 break;5831 5832 case VINF_BUFFER_OVERFLOW:5833 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",5834 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));5835 break;5836 5837 default:5838 break;5839 }5840 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))5841 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5842 else5843 pDbgc->fRegCtxGuest = fRegCtxGuest;5844 break;5845 }5846 5847 case DBGFEVENT_STEPPED:5848 case DBGFEVENT_STEPPED_HYPER:5849 {5850 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;5851 5852 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));5853 if (VBOX_SUCCESS(rc))5854 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5855 break;5856 }5857 5858 case DBGFEVENT_ASSERTION_HYPER:5859 {5860 pDbgc->fRegCtxGuest = false;5861 5862 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5863 "\ndbgf event: Hypervisor Assertion! (%s)\n"5864 "%s"5865 "%s"5866 "\n",5867 dbgcGetEventCtx(pEvent->enmCtx),5868 pEvent->u.Assert.pszMsg1,5869 pEvent->u.Assert.pszMsg2);5870 if (VBOX_SUCCESS(rc))5871 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5872 break;5873 }5874 5875 case DBGFEVENT_DEV_STOP:5876 {5877 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5878 "\n"5879 "dbgf event: DBGFSTOP (%s)\n"5880 "File: %s\n"5881 "Line: %d\n"5882 "Function: %s\n",5883 dbgcGetEventCtx(pEvent->enmCtx),5884 pEvent->u.Src.pszFile,5885 pEvent->u.Src.uLine,5886 pEvent->u.Src.pszFunction);5887 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)5888 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,5889 "Message: %s\n",5890 pEvent->u.Src.pszMessage);5891 if (VBOX_SUCCESS(rc))5892 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");5893 break;5894 }5895 5896 5897 case DBGFEVENT_INVALID_COMMAND:5898 {5899 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");5900 fPrintPrompt = !pDbgc->fReady;5901 break;5902 }5903 5904 case DBGFEVENT_TERMINATING:5905 {5906 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");5907 rc = VERR_GENERAL_FAILURE;5908 break;5909 }5910 5911 5912 default:5913 {5914 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);5915 fPrintPrompt = !pDbgc->fReady;5916 break;5917 }5918 }5919 5920 /*5921 * Prompt, anyone?5922 */5923 if (fPrintPrompt && VBOX_SUCCESS(rc))5924 {5925 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");5926 }5927 5928 return rc;5929 }5930 5931 5932 5933 5934 5935 /**5936 * Make a console instance.5937 *5938 * This will not return until either an 'exit' command is issued or a error code5939 * indicating connection loss is encountered.5940 *5941 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.5942 * @returns The VBox status code causing the console termination.5943 *5944 * @param pVM VM Handle.5945 * @param pBack Pointer to the backend structure. This must contain5946 * a full set of function pointers to service the console.5947 * @param fFlags Reserved, must be zero.5948 * @remark A forced termination of the console is easiest done by forcing the5949 * callbacks to return fatal failures.5950 */5951 DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)5952 {5953 /*5954 * Validate input.5955 */5956 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);5957 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);5958 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);5959 5960 /*5961 * Allocate and initialize instance data5962 */5963 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));5964 if (!pDbgc)5965 return VERR_NO_MEMORY;5966 5967 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;5968 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;5969 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;5970 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;5971 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;5972 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;5973 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;5974 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;5975 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;5976 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;5977 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;5978 pDbgc->pBack = pBack;5979 pDbgc->pVM = NULL;5980 pDbgc->pszEmulation = "CodeView/WinDbg";5981 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];5982 pDbgc->cEmulationCmds = g_cCmdsCodeView;5983 //pDbgc->fLog = false;5984 pDbgc->fRegCtxGuest = true;5985 pDbgc->fRegTerse = true;5986 //pDbgc->DisasmPos = {0};5987 //pDbgc->SourcePos = {0};5988 //pDbgc->DumpPos = {0};5989 //pDbgc->cbDumpElement = 0;5990 //pDbgc->cVars = 0;5991 //pDbgc->paVars = NULL;5992 //pDbgc->pFirstBp = NULL;5993 //pDbgc->uInputZero = 0;5994 //pDbgc->iRead = 0;5995 //pDbgc->iWrite = 0;5996 //pDbgc->cInputLines = 0;5997 //pDbgc->fInputOverflow = false;5998 pDbgc->fReady = true;5999 pDbgc->pszScratch = &pDbgc->achScratch[0];6000 //pDbgc->iArg = 0;6001 //pDbgc->rcOutput = 0;6002 6003 dbgcInitOpCharBitMap();6004 6005 /*6006 * Print welcome message.6007 */6008 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,6009 "Welcome to the VirtualBox Debugger!\n");6010 if (VBOX_FAILURE(rc))6011 goto l_failure;6012 6013 /*6014 * Attach to the VM.6015 */6016 rc = DBGFR3Attach(pVM);6017 if (VBOX_FAILURE(rc))6018 {6019 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);6020 goto l_failure;6021 }6022 pDbgc->pVM = pVM;6023 6024 /*6025 * Print commandline and auto select result.6026 */6027 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,6028 "Current VM is %08x\n" /** @todo get and print the VM name! */6029 "VBoxDbg> ",6030 pDbgc->pVM);6031 if (VBOX_FAILURE(rc))6032 goto l_failure;6033 6034 /*6035 * Main Debugger Loop.6036 *6037 * This loop will either block on waiting for input or on waiting on6038 * debug events. If we're forwarding the log we cannot wait for long6039 * before we must flush the log.6040 */6041 for (rc = 0;;)6042 {6043 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))6044 {6045 /*6046 * Wait for a debug event.6047 */6048 PCDBGFEVENT pEvent;6049 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);6050 if (VBOX_SUCCESS(rc))6051 {6052 rc = dbgcProcessEvent(pDbgc, pEvent);6053 if (VBOX_FAILURE(rc))6054 break;6055 }6056 else if (rc != VERR_TIMEOUT)6057 break;6058 6059 /*6060 * Check for input.6061 */6062 if (pBack->pfnInput(pDbgc->pBack, 0))6063 {6064 rc = dbgcProcessInput(pDbgc);6065 if (VBOX_FAILURE(rc))6066 break;6067 }6068 }6069 else6070 {6071 /*6072 * Wait for input. If Logging is enabled we'll only wait very briefly.6073 */6074 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))6075 {6076 rc = dbgcProcessInput(pDbgc);6077 if (VBOX_FAILURE(rc))6078 break;6079 }6080 }6081 6082 /*6083 * Forward log output.6084 */6085 if (pDbgc->fLog)6086 {6087 rc = dbgcProcessLog(pDbgc);6088 if (VBOX_FAILURE(rc))6089 break;6090 }6091 }6092 6093 6094 l_failure:6095 /*6096 * Cleanup console debugger session.6097 */6098 /* Disable log hook. */6099 if (pDbgc->fLog)6100 {6101 6102 }6103 6104 /* Detach from the VM. */6105 if (pDbgc->pVM)6106 DBGFR3Detach(pDbgc->pVM);6107 6108 /* finally, free the instance memory. */6109 RTMemFree(pDbgc);6110 6111 return rc;6112 }6113 6114 6115 6116 /**6117 * Register one or more external commands.6118 *6119 * @returns VBox status.6120 * @param paCommands Pointer to an array of command descriptors.6121 * The commands must be unique. It's not possible6122 * to register the same commands more than once.6123 * @param cCommands Number of commands.6124 */6125 DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)6126 {6127 /*6128 * Lock the list.6129 */6130 DBGCEXTCMDS_LOCK_WR();6131 PDBGCEXTCMDS pCur = g_pExtCmdsHead;6132 while (pCur)6133 {6134 if (paCommands == pCur->paCmds)6135 {6136 DBGCEXTCMDS_UNLOCK_WR();6137 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));6138 return VWRN_DBGC_ALREADY_REGISTERED;6139 }6140 pCur = pCur->pNext;6141 }6142 6143 /*6144 * Allocate new chunk.6145 */6146 int rc = 0;6147 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));6148 if (pCur)6149 {6150 pCur->cCmds = cCommands;6151 pCur->paCmds = paCommands;6152 pCur->pNext = g_pExtCmdsHead;6153 g_pExtCmdsHead = pCur;6154 }6155 else6156 rc = VERR_NO_MEMORY;6157 DBGCEXTCMDS_UNLOCK_WR();6158 6159 return rc;6160 }6161 6162 6163 /**6164 * Deregister one or more external commands previously registered by6165 * DBGCRegisterCommands().6166 *6167 * @returns VBox status.6168 * @param paCommands Pointer to an array of command descriptors6169 * as given to DBGCRegisterCommands().6170 * @param cCommands Number of commands.6171 */6172 DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)6173 {6174 /*6175 * Lock the list.6176 */6177 DBGCEXTCMDS_LOCK_WR();6178 PDBGCEXTCMDS pPrev = NULL;6179 PDBGCEXTCMDS pCur = g_pExtCmdsHead;6180 while (pCur)6181 {6182 if (paCommands == pCur->paCmds)6183 {6184 if (pPrev)6185 pPrev->pNext = pCur->pNext;6186 else6187 g_pExtCmdsHead = pCur->pNext;6188 DBGCEXTCMDS_UNLOCK_WR();6189 6190 RTMemFree(pCur);6191 return VINF_SUCCESS;6192 }6193 pPrev = pCur;6194 pCur = pCur->pNext;6195 }6196 DBGCEXTCMDS_UNLOCK_WR();6197 6198 NOREF(cCommands);6199 return VERR_DBGC_COMMANDS_NOT_REGISTERED;6200 }6201 -
trunk/src/VBox/Debugger/DBGConsole.cpp
r5672 r5673 148 148 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 149 149 150 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);151 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);152 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);153 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);154 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);155 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);156 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);157 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);158 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);159 160 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);161 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);162 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);163 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);164 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);165 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);166 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);167 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);168 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);169 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);170 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);171 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);172 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);173 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);174 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);175 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);176 177 150 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult); 178 151 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue); 179 152 180 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);181 153 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult); 182 154 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd); … … 311 283 }; 312 284 313 314 /** Operators. */315 static const DBGCOP g_aOps[] =316 {317 /* szName is initialized as a 4 char array because of M$C elsewise optimizing it away in /Ox mode (the 'const char' vs 'char' problem). */318 /* szName, cchName, fBinary, iPrecedence, pfnHandlerUnary, pfnHandlerBitwise */319 { {'-'}, 1, false, 1, dbgcOpMinus, NULL, "Unary minus." },320 { {'+'}, 1, false, 1, dbgcOpPluss, NULL, "Unary pluss." },321 { {'!'}, 1, false, 1, dbgcOpBooleanNot, NULL, "Boolean not." },322 { {'~'}, 1, false, 1, dbgcOpBitwiseNot, NULL, "Bitwise complement." },323 { {':'}, 1, true, 2, NULL, dbgcOpAddrFar, "Far pointer." },324 { {'%'}, 1, false, 3, dbgcOpAddrFlat, NULL, "Flat address." },325 { {'%','%'}, 2, false, 3, dbgcOpAddrPhys, NULL, "Physical address." },326 { {'#'}, 1, false, 3, dbgcOpAddrHost, NULL, "Flat host address." },327 { {'#','%','%'}, 3, false, 3, dbgcOpAddrHostPhys, NULL, "Physical host address." },328 { {'$'}, 1, false, 3, dbgcOpVar, NULL, "Reference a variable." },329 { {'*'}, 1, true, 10, NULL, dbgcOpMult, "Multiplication." },330 { {'/'}, 1, true, 11, NULL, dbgcOpDiv, "Division." },331 { {'%'}, 1, true, 12, NULL, dbgcOpMod, "Modulus." },332 { {'+'}, 1, true, 13, NULL, dbgcOpAdd, "Addition." },333 { {'-'}, 1, true, 14, NULL, dbgcOpSub, "Subtraction." },334 { {'<','<'}, 2, true, 15, NULL, dbgcOpBitwiseShiftLeft, "Bitwise left shift." },335 { {'>','>'}, 2, true, 16, NULL, dbgcOpBitwiseShiftRight, "Bitwise right shift." },336 { {'&'}, 1, true, 17, NULL, dbgcOpBitwiseAnd, "Bitwise and." },337 { {'^'}, 1, true, 18, NULL, dbgcOpBitwiseXor, "Bitwise exclusiv or." },338 { {'|'}, 1, true, 19, NULL, dbgcOpBitwiseOr, "Bitwise inclusive or." },339 { {'&','&'}, 2, true, 20, NULL, dbgcOpBooleanAnd, "Boolean and." },340 { {'|','|'}, 2, true, 21, NULL, dbgcOpBooleanOr, "Boolean or." },341 { {'L'}, 1, true, 22, NULL, dbgcOpRangeLength, "Range elements." },342 { {'L','B'}, 2, true, 23, NULL, dbgcOpRangeLengthBytes, "Range bytes." },343 { {'T'}, 1, true, 24, NULL, dbgcOpRangeTo, "Range to." }344 };345 346 /** Bitmap where set bits indicates the characters the may start an operator name. */347 static uint32_t g_bmOperatorChars[256 / (4*8)];348 285 349 286 /** Register symbol uUser value. … … 513 450 514 451 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 515 462 /** 516 463 * Prints full command help. … … 626 573 "Operators:\n"); 627 574 unsigned iPrecedence = 0; 628 unsigned cLeft = ELEMENTS(g_aOps);575 unsigned cLeft = g_cOps; 629 576 while (cLeft > 0) 630 577 { 631 for (i = 0; i < ELEMENTS(g_aOps); i++)578 for (i = 0; i < g_cOps; i++) 632 579 if (g_aOps[i].iPrecedence == iPrecedence) 633 580 { … … 690 637 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName)) 691 638 { 692 for (i = 0; i < ELEMENTS(g_aOps); i++)639 for (i = 0; i < g_cOps; i++) 693 640 if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString)) 694 641 { … … 1755 1702 // 1756 1703 // 1757 // O p e r a t o r s1758 //1759 //1760 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//1761 1762 1763 /**1764 * Minus (unary).1765 *1766 * @returns 0 on success.1767 * @returns VBox evaluation / parsing error code on failure.1768 * The caller does the bitching.1769 * @param pDbgc Debugger console instance data.1770 * @param pArg The argument.1771 * @param pResult Where to store the result.1772 */1773 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1774 {1775 // LogFlow(("dbgcOpMinus\n"));1776 *pResult = *pArg;1777 switch (pArg->enmType)1778 {1779 case DBGCVAR_TYPE_GC_FLAT:1780 pResult->u.GCFlat = -(RTGCINTPTR)pResult->u.GCFlat;1781 break;1782 case DBGCVAR_TYPE_GC_FAR:1783 pResult->u.GCFar.off = -(int32_t)pResult->u.GCFar.off;1784 break;1785 case DBGCVAR_TYPE_GC_PHYS:1786 pResult->u.GCPhys = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;1787 break;1788 case DBGCVAR_TYPE_HC_FLAT:1789 pResult->u.pvHCFlat = (void *) -(intptr_t)pResult->u.pvHCFlat;1790 break;1791 case DBGCVAR_TYPE_HC_FAR:1792 pResult->u.HCFar.off = -(int32_t)pResult->u.HCFar.off;1793 break;1794 case DBGCVAR_TYPE_HC_PHYS:1795 pResult->u.HCPhys = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;1796 break;1797 case DBGCVAR_TYPE_NUMBER:1798 pResult->u.u64Number = -(int64_t)pResult->u.u64Number;1799 break;1800 1801 case DBGCVAR_TYPE_UNKNOWN:1802 case DBGCVAR_TYPE_STRING:1803 default:1804 return VERR_PARSE_INCORRECT_ARG_TYPE;1805 }1806 NOREF(pDbgc);1807 return 0;1808 }1809 1810 1811 /**1812 * Pluss (unary).1813 *1814 * @returns 0 on success.1815 * @returns VBox evaluation / parsing error code on failure.1816 * The caller does the bitching.1817 * @param pDbgc Debugger console instance data.1818 * @param pArg The argument.1819 * @param pResult Where to store the result.1820 */1821 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1822 {1823 // LogFlow(("dbgcOpPluss\n"));1824 *pResult = *pArg;1825 switch (pArg->enmType)1826 {1827 case DBGCVAR_TYPE_GC_FLAT:1828 case DBGCVAR_TYPE_GC_FAR:1829 case DBGCVAR_TYPE_GC_PHYS:1830 case DBGCVAR_TYPE_HC_FLAT:1831 case DBGCVAR_TYPE_HC_FAR:1832 case DBGCVAR_TYPE_HC_PHYS:1833 case DBGCVAR_TYPE_NUMBER:1834 break;1835 1836 case DBGCVAR_TYPE_UNKNOWN:1837 case DBGCVAR_TYPE_STRING:1838 default:1839 return VERR_PARSE_INCORRECT_ARG_TYPE;1840 }1841 NOREF(pDbgc);1842 return 0;1843 }1844 1845 1846 /**1847 * Boolean not (unary).1848 *1849 * @returns 0 on success.1850 * @returns VBox evaluation / parsing error code on failure.1851 * The caller does the bitching.1852 * @param pDbgc Debugger console instance data.1853 * @param pArg The argument.1854 * @param pResult Where to store the result.1855 */1856 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1857 {1858 // LogFlow(("dbgcOpBooleanNot\n"));1859 *pResult = *pArg;1860 switch (pArg->enmType)1861 {1862 case DBGCVAR_TYPE_GC_FLAT:1863 pResult->u.u64Number = !pResult->u.GCFlat;1864 break;1865 case DBGCVAR_TYPE_GC_FAR:1866 pResult->u.u64Number = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;1867 break;1868 case DBGCVAR_TYPE_GC_PHYS:1869 pResult->u.u64Number = !pResult->u.GCPhys;1870 break;1871 case DBGCVAR_TYPE_HC_FLAT:1872 pResult->u.u64Number = !pResult->u.pvHCFlat;1873 break;1874 case DBGCVAR_TYPE_HC_FAR:1875 pResult->u.u64Number = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;1876 break;1877 case DBGCVAR_TYPE_HC_PHYS:1878 pResult->u.u64Number = !pResult->u.HCPhys;1879 break;1880 case DBGCVAR_TYPE_NUMBER:1881 pResult->u.u64Number = !pResult->u.u64Number;1882 break;1883 case DBGCVAR_TYPE_STRING:1884 pResult->u.u64Number = !pResult->u64Range;1885 break;1886 1887 case DBGCVAR_TYPE_UNKNOWN:1888 default:1889 return VERR_PARSE_INCORRECT_ARG_TYPE;1890 }1891 pResult->enmType = DBGCVAR_TYPE_NUMBER;1892 NOREF(pDbgc);1893 return 0;1894 }1895 1896 1897 /**1898 * Bitwise not (unary).1899 *1900 * @returns 0 on success.1901 * @returns VBox evaluation / parsing error code on failure.1902 * The caller does the bitching.1903 * @param pDbgc Debugger console instance data.1904 * @param pArg The argument.1905 * @param pResult Where to store the result.1906 */1907 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1908 {1909 // LogFlow(("dbgcOpBitwiseNot\n"));1910 *pResult = *pArg;1911 switch (pArg->enmType)1912 {1913 case DBGCVAR_TYPE_GC_FLAT:1914 pResult->u.GCFlat = ~pResult->u.GCFlat;1915 break;1916 case DBGCVAR_TYPE_GC_FAR:1917 pResult->u.GCFar.off = ~pResult->u.GCFar.off;1918 break;1919 case DBGCVAR_TYPE_GC_PHYS:1920 pResult->u.GCPhys = ~pResult->u.GCPhys;1921 break;1922 case DBGCVAR_TYPE_HC_FLAT:1923 pResult->u.pvHCFlat = (void *)~(uintptr_t)pResult->u.pvHCFlat;1924 break;1925 case DBGCVAR_TYPE_HC_FAR:1926 pResult->u.HCFar.off= ~pResult->u.HCFar.off;1927 break;1928 case DBGCVAR_TYPE_HC_PHYS:1929 pResult->u.HCPhys = ~pResult->u.HCPhys;1930 break;1931 case DBGCVAR_TYPE_NUMBER:1932 pResult->u.u64Number = ~pResult->u.u64Number;1933 break;1934 1935 case DBGCVAR_TYPE_UNKNOWN:1936 case DBGCVAR_TYPE_STRING:1937 default:1938 return VERR_PARSE_INCORRECT_ARG_TYPE;1939 }1940 NOREF(pDbgc);1941 return 0;1942 }1943 1944 1945 /**1946 * Reference variable (unary).1947 *1948 * @returns 0 on success.1949 * @returns VBox evaluation / parsing error code on failure.1950 * The caller does the bitching.1951 * @param pDbgc Debugger console instance data.1952 * @param pArg The argument.1953 * @param pResult Where to store the result.1954 */1955 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1956 {1957 // LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));1958 /*1959 * Parse sanity.1960 */1961 if (pArg->enmType != DBGCVAR_TYPE_STRING)1962 return VERR_PARSE_INCORRECT_ARG_TYPE;1963 1964 /*1965 * Lookup the variable.1966 */1967 const char *pszVar = pArg->u.pszString;1968 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)1969 {1970 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))1971 {1972 *pResult = pDbgc->papVars[iVar]->Var;1973 return 0;1974 }1975 }1976 1977 return VERR_PARSE_VARIABLE_NOT_FOUND;1978 }1979 1980 1981 /**1982 * Flat address (unary).1983 *1984 * @returns VINF_SUCCESS on success.1985 * @returns VBox evaluation / parsing error code on failure.1986 * The caller does the bitching.1987 * @param pDbgc Debugger console instance data.1988 * @param pArg The argument.1989 * @param pResult Where to store the result.1990 */1991 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)1992 {1993 // LogFlow(("dbgcOpAddrFlat\n"));1994 int rc;1995 *pResult = *pArg;1996 1997 switch (pArg->enmType)1998 {1999 case DBGCVAR_TYPE_GC_FLAT:2000 return VINF_SUCCESS;2001 2002 case DBGCVAR_TYPE_GC_FAR:2003 {2004 Assert(pDbgc->pVM);2005 DBGFADDRESS Address;2006 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);2007 if (VBOX_SUCCESS(rc))2008 {2009 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;2010 pResult->u.GCFlat = Address.FlatPtr;2011 return VINF_SUCCESS;2012 }2013 return VERR_PARSE_CONVERSION_FAILED;2014 }2015 2016 case DBGCVAR_TYPE_GC_PHYS:2017 //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.2018 return VERR_PARSE_INCORRECT_ARG_TYPE;2019 2020 case DBGCVAR_TYPE_HC_FLAT:2021 return VINF_SUCCESS;2022 2023 case DBGCVAR_TYPE_HC_FAR:2024 return VERR_PARSE_INCORRECT_ARG_TYPE;2025 2026 case DBGCVAR_TYPE_HC_PHYS:2027 Assert(pDbgc->pVM);2028 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;2029 rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);2030 if (VBOX_SUCCESS(rc))2031 return VINF_SUCCESS;2032 return VERR_PARSE_CONVERSION_FAILED;2033 2034 case DBGCVAR_TYPE_NUMBER:2035 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;2036 pResult->u.GCFlat = (RTGCPTR)pResult->u.u64Number;2037 return VINF_SUCCESS;2038 2039 case DBGCVAR_TYPE_STRING:2040 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);2041 2042 case DBGCVAR_TYPE_UNKNOWN:2043 default:2044 return VERR_PARSE_INCORRECT_ARG_TYPE;2045 }2046 }2047 2048 2049 /**2050 * Physical address (unary).2051 *2052 * @returns 0 on success.2053 * @returns VBox evaluation / parsing error code on failure.2054 * The caller does the bitching.2055 * @param pDbgc Debugger console instance data.2056 * @param pArg The argument.2057 * @param pResult Where to store the result.2058 */2059 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)2060 {2061 // LogFlow(("dbgcOpAddrPhys\n"));2062 int rc;2063 2064 *pResult = *pArg;2065 switch (pArg->enmType)2066 {2067 case DBGCVAR_TYPE_GC_FLAT:2068 Assert(pDbgc->pVM);2069 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;2070 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);2071 if (VBOX_SUCCESS(rc))2072 return 0;2073 /** @todo more memory types! */2074 return VERR_PARSE_CONVERSION_FAILED;2075 2076 case DBGCVAR_TYPE_GC_FAR:2077 {2078 Assert(pDbgc->pVM);2079 DBGFADDRESS Address;2080 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);2081 if (VBOX_SUCCESS(rc))2082 {2083 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;2084 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);2085 if (VBOX_SUCCESS(rc))2086 return 0;2087 /** @todo more memory types! */2088 }2089 return VERR_PARSE_CONVERSION_FAILED;2090 }2091 2092 case DBGCVAR_TYPE_GC_PHYS:2093 return 0;2094 2095 case DBGCVAR_TYPE_HC_FLAT:2096 Assert(pDbgc->pVM);2097 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;2098 rc = PGMR3DbgHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);2099 if (VBOX_SUCCESS(rc))2100 return 0;2101 /** @todo more memory types! */2102 return VERR_PARSE_CONVERSION_FAILED;2103 2104 case DBGCVAR_TYPE_HC_FAR:2105 return VERR_PARSE_INCORRECT_ARG_TYPE;2106 2107 case DBGCVAR_TYPE_HC_PHYS:2108 return 0;2109 2110 case DBGCVAR_TYPE_NUMBER:2111 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;2112 pResult->u.GCPhys = (RTGCPHYS)pResult->u.u64Number;2113 return 0;2114 2115 case DBGCVAR_TYPE_STRING:2116 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);2117 2118 case DBGCVAR_TYPE_UNKNOWN:2119 default:2120 return VERR_PARSE_INCORRECT_ARG_TYPE;2121 }2122 return 0;2123 }2124 2125 2126 /**2127 * Physical host address (unary).2128 *2129 * @returns 0 on success.2130 * @returns VBox evaluation / parsing error code on failure.2131 * The caller does the bitching.2132 * @param pDbgc Debugger console instance data.2133 * @param pArg The argument.2134 * @param pResult Where to store the result.2135 */2136 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)2137 {2138 // LogFlow(("dbgcOpAddrPhys\n"));2139 int rc;2140 2141 *pResult = *pArg;2142 switch (pArg->enmType)2143 {2144 case DBGCVAR_TYPE_GC_FLAT:2145 Assert(pDbgc->pVM);2146 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;2147 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);2148 if (VBOX_SUCCESS(rc))2149 return 0;2150 /** @todo more memory types. */2151 return VERR_PARSE_CONVERSION_FAILED;2152 2153 case DBGCVAR_TYPE_GC_FAR:2154 {2155 Assert(pDbgc->pVM);2156 DBGFADDRESS Address;2157 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);2158 if (VBOX_SUCCESS(rc))2159 {2160 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;2161 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);2162 if (VBOX_SUCCESS(rc))2163 return 0;2164 /** @todo more memory types. */2165 }2166 return VERR_PARSE_CONVERSION_FAILED;2167 }2168 2169 case DBGCVAR_TYPE_GC_PHYS:2170 Assert(pDbgc->pVM);2171 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;2172 rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);2173 if (VBOX_SUCCESS(rc))2174 return 0;2175 return VERR_PARSE_CONVERSION_FAILED;2176 2177 case DBGCVAR_TYPE_HC_FLAT:2178 Assert(pDbgc->pVM);2179 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;2180 rc = PGMR3DbgHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);2181 if (VBOX_SUCCESS(rc))2182 return 0;2183 /** @todo more memory types! */2184 return VERR_PARSE_CONVERSION_FAILED;2185 2186 case DBGCVAR_TYPE_HC_FAR:2187 return VERR_PARSE_INCORRECT_ARG_TYPE;2188 2189 case DBGCVAR_TYPE_HC_PHYS:2190 return 0;2191 2192 case DBGCVAR_TYPE_NUMBER:2193 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;2194 pResult->u.HCPhys = (RTGCPHYS)pResult->u.u64Number;2195 return 0;2196 2197 case DBGCVAR_TYPE_STRING:2198 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);2199 2200 case DBGCVAR_TYPE_UNKNOWN:2201 default:2202 return VERR_PARSE_INCORRECT_ARG_TYPE;2203 }2204 return 0;2205 }2206 2207 2208 /**2209 * Host address (unary).2210 *2211 * @returns 0 on success.2212 * @returns VBox evaluation / parsing error code on failure.2213 * The caller does the bitching.2214 * @param pDbgc Debugger console instance data.2215 * @param pArg The argument.2216 * @param pResult Where to store the result.2217 */2218 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)2219 {2220 // LogFlow(("dbgcOpAddrHost\n"));2221 int rc;2222 2223 *pResult = *pArg;2224 switch (pArg->enmType)2225 {2226 case DBGCVAR_TYPE_GC_FLAT:2227 Assert(pDbgc->pVM);2228 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;2229 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);2230 if (VBOX_SUCCESS(rc))2231 return 0;2232 /** @todo more memory types. */2233 return VERR_PARSE_CONVERSION_FAILED;2234 2235 case DBGCVAR_TYPE_GC_FAR:2236 {2237 Assert(pDbgc->pVM);2238 DBGFADDRESS Address;2239 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);2240 if (VBOX_SUCCESS(rc))2241 {2242 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;2243 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);2244 if (VBOX_SUCCESS(rc))2245 return 0;2246 /** @todo more memory types. */2247 }2248 return VERR_PARSE_CONVERSION_FAILED;2249 }2250 2251 case DBGCVAR_TYPE_GC_PHYS:2252 Assert(pDbgc->pVM);2253 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;2254 rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);2255 if (VBOX_SUCCESS(rc))2256 return 0;2257 return VERR_PARSE_CONVERSION_FAILED;2258 2259 case DBGCVAR_TYPE_HC_FLAT:2260 return 0;2261 2262 case DBGCVAR_TYPE_HC_FAR:2263 case DBGCVAR_TYPE_HC_PHYS:2264 /** @todo !*/2265 return VERR_PARSE_CONVERSION_FAILED;2266 2267 case DBGCVAR_TYPE_NUMBER:2268 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;2269 pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;2270 return 0;2271 2272 case DBGCVAR_TYPE_STRING:2273 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);2274 2275 case DBGCVAR_TYPE_UNKNOWN:2276 default:2277 return VERR_PARSE_INCORRECT_ARG_TYPE;2278 }2279 }2280 2281 /**2282 * Bitwise not (unary).2283 *2284 * @returns 0 on success.2285 * @returns VBox evaluation / parsing error code on failure.2286 * The caller does the bitching.2287 * @param pDbgc Debugger console instance data.2288 * @param pArg The argument.2289 * @param pResult Where to store the result.2290 */2291 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2292 {2293 // LogFlow(("dbgcOpAddrFar\n"));2294 int rc;2295 2296 switch (pArg1->enmType)2297 {2298 case DBGCVAR_TYPE_STRING:2299 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);2300 if (VBOX_FAILURE(rc))2301 return rc;2302 break;2303 case DBGCVAR_TYPE_NUMBER:2304 *pResult = *pArg1;2305 break;2306 2307 case DBGCVAR_TYPE_GC_FLAT:2308 case DBGCVAR_TYPE_GC_FAR:2309 case DBGCVAR_TYPE_GC_PHYS:2310 case DBGCVAR_TYPE_HC_FLAT:2311 case DBGCVAR_TYPE_HC_FAR:2312 case DBGCVAR_TYPE_HC_PHYS:2313 case DBGCVAR_TYPE_UNKNOWN:2314 default:2315 return VERR_PARSE_INCORRECT_ARG_TYPE;2316 }2317 pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;2318 2319 /* common code for the two types we support. */2320 switch (pArg2->enmType)2321 {2322 case DBGCVAR_TYPE_GC_FLAT:2323 pResult->u.GCFar.off = pArg2->u.GCFlat;2324 pResult->enmType = DBGCVAR_TYPE_GC_FAR;2325 break;2326 2327 case DBGCVAR_TYPE_HC_FLAT:2328 pResult->u.HCFar.off = pArg2->u.GCFlat;2329 pResult->enmType = DBGCVAR_TYPE_GC_FAR;2330 break;2331 2332 case DBGCVAR_TYPE_NUMBER:2333 pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;2334 pResult->enmType = DBGCVAR_TYPE_GC_FAR;2335 break;2336 2337 case DBGCVAR_TYPE_STRING:2338 {2339 DBGCVAR Var;2340 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);2341 if (VBOX_FAILURE(rc))2342 return rc;2343 pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;2344 pResult->enmType = DBGCVAR_TYPE_GC_FAR;2345 break;2346 }2347 2348 case DBGCVAR_TYPE_GC_FAR:2349 case DBGCVAR_TYPE_GC_PHYS:2350 case DBGCVAR_TYPE_HC_FAR:2351 case DBGCVAR_TYPE_HC_PHYS:2352 case DBGCVAR_TYPE_UNKNOWN:2353 default:2354 return VERR_PARSE_INCORRECT_ARG_TYPE;2355 }2356 return 0;2357 2358 }2359 2360 2361 /**2362 * Multiplication operator (binary).2363 *2364 * @returns 0 on success.2365 * @returns VBox evaluation / parsing error code on failure.2366 * The caller does the bitching.2367 * @param pDbgc Debugger console instance data.2368 * @param pArg1 The first argument.2369 * @param pArg2 The 2nd argument.2370 * @param pResult Where to store the result.2371 */2372 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2373 {2374 // LogFlow(("dbgcOpMult\n"));2375 int rc;2376 2377 /*2378 * Switch the factors so we preserve pointers, far pointers are considered more2379 * important that physical and flat pointers.2380 */2381 if ( DBGCVAR_ISPOINTER(pArg2->enmType)2382 && ( !DBGCVAR_ISPOINTER(pArg1->enmType)2383 || ( DBGCVAR_IS_FAR_PTR(pArg2->enmType)2384 && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))2385 {2386 PCDBGCVAR pTmp = pArg1;2387 pArg2 = pArg1;2388 pArg1 = pTmp;2389 }2390 2391 /*2392 * Convert the 2nd number into a number we use multiply the first with.2393 */2394 DBGCVAR Factor2 = *pArg2;2395 if ( Factor2.enmType == DBGCVAR_TYPE_STRING2396 || Factor2.enmType == DBGCVAR_TYPE_SYMBOL)2397 {2398 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);2399 if (VBOX_FAILURE(rc))2400 return rc;2401 }2402 uint64_t u64Factor;2403 switch (Factor2.enmType)2404 {2405 case DBGCVAR_TYPE_GC_FLAT: u64Factor = Factor2.u.GCFlat; break;2406 case DBGCVAR_TYPE_GC_FAR: u64Factor = Factor2.u.GCFar.off; break;2407 case DBGCVAR_TYPE_GC_PHYS: u64Factor = Factor2.u.GCPhys; break;2408 case DBGCVAR_TYPE_HC_FLAT: u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;2409 case DBGCVAR_TYPE_HC_FAR: u64Factor = Factor2.u.HCFar.off; break;2410 case DBGCVAR_TYPE_HC_PHYS: u64Factor = Factor2.u.HCPhys; break;2411 case DBGCVAR_TYPE_NUMBER: u64Factor = Factor2.u.u64Number; break;2412 default:2413 return VERR_PARSE_INCORRECT_ARG_TYPE;2414 }2415 2416 /*2417 * Fix symbols in the 1st factor.2418 */2419 *pResult = *pArg1;2420 if ( pResult->enmType == DBGCVAR_TYPE_STRING2421 || pResult->enmType == DBGCVAR_TYPE_SYMBOL)2422 {2423 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);2424 if (VBOX_FAILURE(rc))2425 return rc;2426 }2427 2428 /*2429 * Do the multiplication.2430 */2431 switch (pArg1->enmType)2432 {2433 case DBGCVAR_TYPE_GC_FLAT: pResult->u.GCFlat *= u64Factor; break;2434 case DBGCVAR_TYPE_GC_FAR: pResult->u.GCFar.off *= u64Factor; break;2435 case DBGCVAR_TYPE_GC_PHYS: pResult->u.GCPhys *= u64Factor; break;2436 case DBGCVAR_TYPE_HC_FLAT:2437 pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);2438 break;2439 case DBGCVAR_TYPE_HC_FAR: pResult->u.HCFar.off *= u64Factor; break;2440 case DBGCVAR_TYPE_HC_PHYS: pResult->u.HCPhys *= u64Factor; break;2441 case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number *= u64Factor; break;2442 default:2443 return VERR_PARSE_INCORRECT_ARG_TYPE;2444 }2445 return 0;2446 }2447 2448 2449 /**2450 * Division operator (binary).2451 *2452 * @returns 0 on success.2453 * @returns VBox evaluation / parsing error code on failure.2454 * The caller does the bitching.2455 * @param pDbgc Debugger console instance data.2456 * @param pArg1 The first argument.2457 * @param pArg2 The 2nd argument.2458 * @param pResult Where to store the result.2459 */2460 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2461 {2462 LogFlow(("dbgcOpDiv\n"));2463 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);2464 return -1;2465 }2466 2467 2468 /**2469 * Modulus operator (binary).2470 *2471 * @returns 0 on success.2472 * @returns VBox evaluation / parsing error code on failure.2473 * The caller does the bitching.2474 * @param pDbgc Debugger console instance data.2475 * @param pArg1 The first argument.2476 * @param pArg2 The 2nd argument.2477 * @param pResult Where to store the result.2478 */2479 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2480 {2481 LogFlow(("dbgcOpMod\n"));2482 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);2483 return -1;2484 }2485 2486 2487 /**2488 * Addition operator (binary).2489 *2490 * @returns 0 on success.2491 * @returns VBox evaluation / parsing error code on failure.2492 * The caller does the bitching.2493 * @param pDbgc Debugger console instance data.2494 * @param pArg1 The first argument.2495 * @param pArg2 The 2nd argument.2496 * @param pResult Where to store the result.2497 */2498 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2499 {2500 // LogFlow(("dbgcOpAdd\n"));2501 2502 /*2503 * An addition operation will return (when possible) the left side type in the2504 * expression. We make an omission for numbers, where we'll take the right side2505 * type instead. An expression where only the left hand side is a string we'll2506 * use the right hand type assuming that the string is a symbol.2507 */2508 if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)2509 || (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))2510 {2511 PCDBGCVAR pTmp = pArg2;2512 pArg2 = pArg1;2513 pArg1 = pTmp;2514 }2515 DBGCVAR Sym1, Sym2;2516 if (pArg1->enmType == DBGCVAR_TYPE_STRING)2517 {2518 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);2519 if (VBOX_FAILURE(rc))2520 return rc;2521 pArg1 = &Sym1;2522 2523 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);2524 if (VBOX_FAILURE(rc))2525 return rc;2526 pArg2 = &Sym2;2527 }2528 2529 int rc;2530 DBGCVAR Var;2531 DBGCVAR Var2;2532 switch (pArg1->enmType)2533 {2534 /*2535 * GC Flat2536 */2537 case DBGCVAR_TYPE_GC_FLAT:2538 switch (pArg2->enmType)2539 {2540 case DBGCVAR_TYPE_HC_FLAT:2541 case DBGCVAR_TYPE_HC_FAR:2542 case DBGCVAR_TYPE_HC_PHYS:2543 return VERR_PARSE_INVALID_OPERATION;2544 default:2545 *pResult = *pArg1;2546 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);2547 if (VBOX_FAILURE(rc))2548 return rc;2549 pResult->u.GCFlat += pArg2->u.GCFlat;2550 break;2551 }2552 break;2553 2554 /*2555 * GC Far2556 */2557 case DBGCVAR_TYPE_GC_FAR:2558 switch (pArg2->enmType)2559 {2560 case DBGCVAR_TYPE_HC_FLAT:2561 case DBGCVAR_TYPE_HC_FAR:2562 case DBGCVAR_TYPE_HC_PHYS:2563 return VERR_PARSE_INVALID_OPERATION;2564 case DBGCVAR_TYPE_NUMBER:2565 *pResult = *pArg1;2566 pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;2567 break;2568 default:2569 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);2570 if (VBOX_FAILURE(rc))2571 return rc;2572 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);2573 if (VBOX_FAILURE(rc))2574 return rc;2575 pResult->u.GCFlat += pArg2->u.GCFlat;2576 break;2577 }2578 break;2579 2580 /*2581 * GC Phys2582 */2583 case DBGCVAR_TYPE_GC_PHYS:2584 switch (pArg2->enmType)2585 {2586 case DBGCVAR_TYPE_HC_FLAT:2587 case DBGCVAR_TYPE_HC_FAR:2588 case DBGCVAR_TYPE_HC_PHYS:2589 return VERR_PARSE_INVALID_OPERATION;2590 default:2591 *pResult = *pArg1;2592 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);2593 if (VBOX_FAILURE(rc))2594 return rc;2595 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)2596 return VERR_PARSE_INVALID_OPERATION;2597 pResult->u.GCPhys += Var.u.GCPhys;2598 break;2599 }2600 break;2601 2602 /*2603 * HC Flat2604 */2605 case DBGCVAR_TYPE_HC_FLAT:2606 *pResult = *pArg1;2607 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);2608 if (VBOX_FAILURE(rc))2609 return rc;2610 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);2611 if (VBOX_FAILURE(rc))2612 return rc;2613 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;2614 break;2615 2616 /*2617 * HC Far2618 */2619 case DBGCVAR_TYPE_HC_FAR:2620 switch (pArg2->enmType)2621 {2622 case DBGCVAR_TYPE_NUMBER:2623 *pResult = *pArg1;2624 pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;2625 break;2626 2627 default:2628 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);2629 if (VBOX_FAILURE(rc))2630 return rc;2631 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);2632 if (VBOX_FAILURE(rc))2633 return rc;2634 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);2635 if (VBOX_FAILURE(rc))2636 return rc;2637 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;2638 break;2639 }2640 break;2641 2642 /*2643 * HC Phys2644 */2645 case DBGCVAR_TYPE_HC_PHYS:2646 *pResult = *pArg1;2647 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);2648 if (VBOX_FAILURE(rc))2649 return rc;2650 pResult->u.HCPhys += Var.u.HCPhys;2651 break;2652 2653 /*2654 * Numbers (see start of function)2655 */2656 case DBGCVAR_TYPE_NUMBER:2657 *pResult = *pArg1;2658 switch (pArg2->enmType)2659 {2660 case DBGCVAR_TYPE_SYMBOL:2661 case DBGCVAR_TYPE_STRING:2662 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);2663 if (VBOX_FAILURE(rc))2664 return rc;2665 case DBGCVAR_TYPE_NUMBER:2666 pResult->u.u64Number += pArg2->u.u64Number;2667 break;2668 default:2669 return VERR_PARSE_INVALID_OPERATION;2670 }2671 break;2672 2673 default:2674 return VERR_PARSE_INVALID_OPERATION;2675 2676 }2677 return 0;2678 }2679 2680 2681 /**2682 * Subtration operator (binary).2683 *2684 * @returns 0 on success.2685 * @returns VBox evaluation / parsing error code on failure.2686 * The caller does the bitching.2687 * @param pDbgc Debugger console instance data.2688 * @param pArg1 The first argument.2689 * @param pArg2 The 2nd argument.2690 * @param pResult Where to store the result.2691 */2692 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2693 {2694 // LogFlow(("dbgcOpSub\n"));2695 2696 /*2697 * An subtraction operation will return the left side type in the expression.2698 * However, if the left hand side is a number and the right hand a pointer of2699 * some kind we'll convert the left hand side to the same type as the right hand.2700 * Any strings will be attempted resolved as symbols.2701 */2702 DBGCVAR Sym1, Sym2;2703 if ( pArg2->enmType == DBGCVAR_TYPE_STRING2704 && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER2705 || pArg1->enmType == DBGCVAR_TYPE_STRING))2706 {2707 int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);2708 if (VBOX_FAILURE(rc))2709 return rc;2710 pArg2 = &Sym2;2711 }2712 2713 if (pArg1->enmType == DBGCVAR_TYPE_STRING)2714 {2715 DBGCVARTYPE enmType;2716 switch (pArg2->enmType)2717 {2718 case DBGCVAR_TYPE_NUMBER:2719 enmType = DBGCVAR_TYPE_ANY;2720 break;2721 case DBGCVAR_TYPE_GC_FLAT:2722 case DBGCVAR_TYPE_GC_PHYS:2723 case DBGCVAR_TYPE_HC_FLAT:2724 case DBGCVAR_TYPE_HC_PHYS:2725 enmType = pArg2->enmType;2726 break;2727 case DBGCVAR_TYPE_GC_FAR:2728 enmType = DBGCVAR_TYPE_GC_FLAT;2729 break;2730 case DBGCVAR_TYPE_HC_FAR:2731 enmType = DBGCVAR_TYPE_HC_FLAT;2732 break;2733 2734 default:2735 case DBGCVAR_TYPE_STRING:2736 AssertMsgFailed(("Can't happen\n"));2737 enmType = DBGCVAR_TYPE_STRING;2738 break;2739 }2740 if (enmType != DBGCVAR_TYPE_STRING)2741 {2742 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);2743 if (VBOX_FAILURE(rc))2744 return rc;2745 pArg1 = &Sym1;2746 }2747 }2748 else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)2749 {2750 PFNDBGCOPUNARY pOp = NULL;2751 switch (pArg2->enmType)2752 {2753 case DBGCVAR_TYPE_GC_FAR:2754 case DBGCVAR_TYPE_GC_FLAT:2755 pOp = dbgcOpAddrFlat;2756 break;2757 case DBGCVAR_TYPE_GC_PHYS:2758 pOp = dbgcOpAddrPhys;2759 break;2760 case DBGCVAR_TYPE_HC_FAR:2761 case DBGCVAR_TYPE_HC_FLAT:2762 pOp = dbgcOpAddrHost;2763 break;2764 case DBGCVAR_TYPE_HC_PHYS:2765 pOp = dbgcOpAddrHostPhys;2766 break;2767 case DBGCVAR_TYPE_NUMBER:2768 break;2769 default:2770 case DBGCVAR_TYPE_STRING:2771 AssertMsgFailed(("Can't happen\n"));2772 break;2773 }2774 if (pOp)2775 {2776 int rc = pOp(pDbgc, pArg1, &Sym1);2777 if (VBOX_FAILURE(rc))2778 return rc;2779 pArg1 = &Sym1;2780 }2781 }2782 2783 2784 /*2785 * Normal processing.2786 */2787 int rc;2788 DBGCVAR Var;2789 DBGCVAR Var2;2790 switch (pArg1->enmType)2791 {2792 /*2793 * GC Flat2794 */2795 case DBGCVAR_TYPE_GC_FLAT:2796 switch (pArg2->enmType)2797 {2798 case DBGCVAR_TYPE_HC_FLAT:2799 case DBGCVAR_TYPE_HC_FAR:2800 case DBGCVAR_TYPE_HC_PHYS:2801 return VERR_PARSE_INVALID_OPERATION;2802 default:2803 *pResult = *pArg1;2804 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);2805 if (VBOX_FAILURE(rc))2806 return rc;2807 pResult->u.GCFlat -= pArg2->u.GCFlat;2808 break;2809 }2810 break;2811 2812 /*2813 * GC Far2814 */2815 case DBGCVAR_TYPE_GC_FAR:2816 switch (pArg2->enmType)2817 {2818 case DBGCVAR_TYPE_HC_FLAT:2819 case DBGCVAR_TYPE_HC_FAR:2820 case DBGCVAR_TYPE_HC_PHYS:2821 return VERR_PARSE_INVALID_OPERATION;2822 case DBGCVAR_TYPE_NUMBER:2823 *pResult = *pArg1;2824 pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;2825 break;2826 default:2827 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);2828 if (VBOX_FAILURE(rc))2829 return rc;2830 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);2831 if (VBOX_FAILURE(rc))2832 return rc;2833 pResult->u.GCFlat -= pArg2->u.GCFlat;2834 break;2835 }2836 break;2837 2838 /*2839 * GC Phys2840 */2841 case DBGCVAR_TYPE_GC_PHYS:2842 switch (pArg2->enmType)2843 {2844 case DBGCVAR_TYPE_HC_FLAT:2845 case DBGCVAR_TYPE_HC_FAR:2846 case DBGCVAR_TYPE_HC_PHYS:2847 return VERR_PARSE_INVALID_OPERATION;2848 default:2849 *pResult = *pArg1;2850 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);2851 if (VBOX_FAILURE(rc))2852 return rc;2853 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)2854 return VERR_PARSE_INVALID_OPERATION;2855 pResult->u.GCPhys -= Var.u.GCPhys;2856 break;2857 }2858 break;2859 2860 /*2861 * HC Flat2862 */2863 case DBGCVAR_TYPE_HC_FLAT:2864 *pResult = *pArg1;2865 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);2866 if (VBOX_FAILURE(rc))2867 return rc;2868 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);2869 if (VBOX_FAILURE(rc))2870 return rc;2871 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;2872 break;2873 2874 /*2875 * HC Far2876 */2877 case DBGCVAR_TYPE_HC_FAR:2878 switch (pArg2->enmType)2879 {2880 case DBGCVAR_TYPE_NUMBER:2881 *pResult = *pArg1;2882 pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;2883 break;2884 2885 default:2886 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);2887 if (VBOX_FAILURE(rc))2888 return rc;2889 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);2890 if (VBOX_FAILURE(rc))2891 return rc;2892 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);2893 if (VBOX_FAILURE(rc))2894 return rc;2895 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;2896 break;2897 }2898 break;2899 2900 /*2901 * HC Phys2902 */2903 case DBGCVAR_TYPE_HC_PHYS:2904 *pResult = *pArg1;2905 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);2906 if (VBOX_FAILURE(rc))2907 return rc;2908 pResult->u.HCPhys -= Var.u.HCPhys;2909 break;2910 2911 /*2912 * Numbers (see start of function)2913 */2914 case DBGCVAR_TYPE_NUMBER:2915 *pResult = *pArg1;2916 switch (pArg2->enmType)2917 {2918 case DBGCVAR_TYPE_SYMBOL:2919 case DBGCVAR_TYPE_STRING:2920 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);2921 if (VBOX_FAILURE(rc))2922 return rc;2923 case DBGCVAR_TYPE_NUMBER:2924 pResult->u.u64Number -= pArg2->u.u64Number;2925 break;2926 default:2927 return VERR_PARSE_INVALID_OPERATION;2928 }2929 break;2930 2931 default:2932 return VERR_PARSE_INVALID_OPERATION;2933 2934 }2935 return 0;2936 }2937 2938 2939 /**2940 * Bitwise shift left operator (binary).2941 *2942 * @returns 0 on success.2943 * @returns VBox evaluation / parsing error code on failure.2944 * The caller does the bitching.2945 * @param pDbgc Debugger console instance data.2946 * @param pArg1 The first argument.2947 * @param pArg2 The 2nd argument.2948 * @param pResult Where to store the result.2949 */2950 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2951 {2952 LogFlow(("dbgcOpBitwiseShiftLeft\n"));2953 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);2954 return -1;2955 }2956 2957 2958 /**2959 * Bitwise shift right operator (binary).2960 *2961 * @returns 0 on success.2962 * @returns VBox evaluation / parsing error code on failure.2963 * The caller does the bitching.2964 * @param pDbgc Debugger console instance data.2965 * @param pArg1 The first argument.2966 * @param pArg2 The 2nd argument.2967 * @param pResult Where to store the result.2968 */2969 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2970 {2971 LogFlow(("dbgcOpBitwiseShiftRight\n"));2972 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);2973 return -1;2974 }2975 2976 2977 /**2978 * Bitwise and operator (binary).2979 *2980 * @returns 0 on success.2981 * @returns VBox evaluation / parsing error code on failure.2982 * The caller does the bitching.2983 * @param pDbgc Debugger console instance data.2984 * @param pArg1 The first argument.2985 * @param pArg2 The 2nd argument.2986 * @param pResult Where to store the result.2987 */2988 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)2989 {2990 LogFlow(("dbgcOpBitwiseAnd\n"));2991 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);2992 return -1;2993 }2994 2995 2996 /**2997 * Bitwise exclusive or operator (binary).2998 *2999 * @returns 0 on success.3000 * @returns VBox evaluation / parsing error code on failure.3001 * The caller does the bitching.3002 * @param pDbgc Debugger console instance data.3003 * @param pArg1 The first argument.3004 * @param pArg2 The 2nd argument.3005 * @param pResult Where to store the result.3006 */3007 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3008 {3009 LogFlow(("dbgcOpBitwiseXor\n"));3010 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);3011 return -1;3012 }3013 3014 3015 /**3016 * Bitwise inclusive or operator (binary).3017 *3018 * @returns 0 on success.3019 * @returns VBox evaluation / parsing error code on failure.3020 * The caller does the bitching.3021 * @param pDbgc Debugger console instance data.3022 * @param pArg1 The first argument.3023 * @param pArg2 The 2nd argument.3024 * @param pResult Where to store the result.3025 */3026 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3027 {3028 LogFlow(("dbgcOpBitwiseOr\n"));3029 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);3030 return -1;3031 }3032 3033 3034 /**3035 * Boolean and operator (binary).3036 *3037 * @returns 0 on success.3038 * @returns VBox evaluation / parsing error code on failure.3039 * The caller does the bitching.3040 * @param pDbgc Debugger console instance data.3041 * @param pArg1 The first argument.3042 * @param pArg2 The 2nd argument.3043 * @param pResult Where to store the result.3044 */3045 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3046 {3047 LogFlow(("dbgcOpBooleanAnd\n"));3048 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);3049 return -1;3050 }3051 3052 3053 /**3054 * Boolean or operator (binary).3055 *3056 * @returns 0 on success.3057 * @returns VBox evaluation / parsing error code on failure.3058 * The caller does the bitching.3059 * @param pDbgc Debugger console instance data.3060 * @param pArg1 The first argument.3061 * @param pArg2 The 2nd argument.3062 * @param pResult Where to store the result.3063 */3064 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3065 {3066 LogFlow(("dbgcOpBooleanOr\n"));3067 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);3068 return -1;3069 }3070 3071 3072 /**3073 * Range to operator (binary).3074 *3075 * @returns 0 on success.3076 * @returns VBox evaluation / parsing error code on failure.3077 * The caller does the bitching.3078 * @param pDbgc Debugger console instance data.3079 * @param pArg1 The first argument.3080 * @param pArg2 The 2nd argument.3081 * @param pResult Where to store the result.3082 */3083 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3084 {3085 // LogFlow(("dbgcOpRangeLength\n"));3086 /*3087 * Make result. Strings needs to be resolved into symbols.3088 */3089 if (pArg1->enmType == DBGCVAR_TYPE_STRING)3090 {3091 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);3092 if (VBOX_FAILURE(rc))3093 return rc;3094 }3095 else3096 *pResult = *pArg1;3097 3098 /*3099 * Convert 2nd argument to element count.3100 */3101 pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;3102 switch (pArg2->enmType)3103 {3104 case DBGCVAR_TYPE_NUMBER:3105 pResult->u64Range = pArg2->u.u64Number;3106 break;3107 3108 case DBGCVAR_TYPE_STRING:3109 {3110 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);3111 if (VBOX_FAILURE(rc))3112 return rc;3113 pResult->u64Range = pArg2->u.u64Number;3114 break;3115 }3116 3117 default:3118 return VERR_PARSE_INVALID_OPERATION;3119 }3120 3121 return VINF_SUCCESS;3122 }3123 3124 3125 /**3126 * Range to operator (binary).3127 *3128 * @returns 0 on success.3129 * @returns VBox evaluation / parsing error code on failure.3130 * The caller does the bitching.3131 * @param pDbgc Debugger console instance data.3132 * @param pArg1 The first argument.3133 * @param pArg2 The 2nd argument.3134 * @param pResult Where to store the result.3135 */3136 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3137 {3138 // LogFlow(("dbgcOpRangeLengthBytes\n"));3139 int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);3140 if (VBOX_SUCCESS(rc))3141 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;3142 return rc;3143 }3144 3145 3146 /**3147 * Range to operator (binary).3148 *3149 * @returns 0 on success.3150 * @returns VBox evaluation / parsing error code on failure.3151 * The caller does the bitching.3152 * @param pDbgc Debugger console instance data.3153 * @param pArg1 The first argument.3154 * @param pArg2 The 2nd argument.3155 * @param pResult Where to store the result.3156 */3157 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)3158 {3159 // LogFlow(("dbgcOpRangeTo\n"));3160 /*3161 * Calc number of bytes between the two args.3162 */3163 DBGCVAR Diff;3164 int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);3165 if (VBOX_FAILURE(rc))3166 return rc;3167 3168 /*3169 * Use the diff as the range of Arg1.3170 */3171 *pResult = *pArg1;3172 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;3173 switch (Diff.enmType)3174 {3175 case DBGCVAR_TYPE_GC_FLAT:3176 pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;3177 break;3178 case DBGCVAR_TYPE_GC_PHYS:3179 pResult->u64Range = Diff.u.GCPhys;3180 break;3181 case DBGCVAR_TYPE_HC_FLAT:3182 pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;3183 break;3184 case DBGCVAR_TYPE_HC_PHYS:3185 pResult->u64Range = Diff.u.HCPhys;3186 break;3187 case DBGCVAR_TYPE_NUMBER:3188 pResult->u64Range = Diff.u.u64Number;3189 break;3190 3191 case DBGCVAR_TYPE_GC_FAR:3192 case DBGCVAR_TYPE_STRING:3193 case DBGCVAR_TYPE_HC_FAR:3194 default:3195 AssertMsgFailed(("Impossible!\n"));3196 return VERR_PARSE_INVALID_OPERATION;3197 }3198 3199 return 0;3200 }3201 3202 3203 3204 3205 3206 /**3207 * Output callback.3208 *3209 * @returns number of bytes written.3210 * @param pvArg User argument.3211 * @param pachChars Pointer to an array of utf-8 characters.3212 * @param cbChars Number of bytes in the character array pointed to by pachChars.3213 */3214 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)3215 {3216 PDBGC pDbgc = (PDBGC)pvArg;3217 if (cbChars)3218 {3219 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);3220 if (VBOX_FAILURE(rc))3221 {3222 pDbgc->rcOutput = rc;3223 cbChars = 0;3224 }3225 }3226 3227 return cbChars;3228 }3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//3239 //3240 //3241 1704 // C a l l b a c k H e l p e r s 3242 1705 // … … 3401 1864 } 3402 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 3403 1892 3404 1893 … … 4349 2838 * @param pResult Where to store the result. 4350 2839 */ 4351 staticint dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)2840 int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult) 4352 2841 { 4353 2842 /* … … 4480 2969 4481 2970 /** 4482 * Searches for an operator descriptor which matches the start of4483 * the expression given us.4484 *4485 * @returns Pointer to the operator on success.4486 * @param pDbgc The debug console instance.4487 * @param pszExpr Pointer to the expression string which might start with an operator.4488 * @param fPreferBinary Whether to favour binary or unary operators.4489 * Caller must assert that it's the disired type! Both types will still4490 * be returned, this is only for resolving duplicates.4491 * @param chPrev The previous char. Some operators requires a blank in front of it.4492 */4493 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)4494 {4495 PCDBGCOP pOp = NULL;4496 for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)4497 {4498 if ( g_aOps[iOp].szName[0] == pszExpr[0]4499 && (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])4500 && (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))4501 {4502 /*4503 * Check that we don't mistake it for some other operator which have more chars.4504 */4505 unsigned j;4506 for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)4507 if ( g_aOps[j].cchName > g_aOps[iOp].cchName4508 && g_aOps[j].szName[0] == pszExpr[0]4509 && (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])4510 && (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )4511 break;4512 if (j < ELEMENTS(g_aOps))4513 continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */4514 pOp = &g_aOps[iOp];4515 4516 /*4517 * Prefered type?4518 */4519 if (g_aOps[iOp].fBinary == fPreferBinary)4520 break;4521 }4522 }4523 4524 if (pOp)4525 Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));4526 NOREF(pDbgc); NOREF(chPrev);4527 return pOp;4528 }4529 4530 4531 /**4532 2971 * Initalizes g_bmOperatorChars. 4533 2972 */ … … 4535 2974 { 4536 2975 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars)); 4537 for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)2976 for (unsigned iOp = 0; iOp < g_cOps; iOp++) 4538 2977 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]); 4539 2978 } -
trunk/src/VBox/Debugger/Makefile.kmk
r5669 r5673 36 36 Debugger_SOURCES = \ 37 37 DBGConsole.cpp \ 38 DBGCOps.cpp \ 38 39 DBGCEmulateCodeView.cpp \ 39 40 DBGCTcp.cpp … … 98 99 VBoxDbgStats.cpp \ 99 100 DBGConsole.cpp \ 101 DBGCOps.cpp \ 100 102 DBGCEmulateCodeView.cpp 101 103
Note:
See TracChangeset
for help on using the changeset viewer.