Changeset 5669 in vbox
- Timestamp:
- Nov 11, 2007 5:05:02 AM (17 years ago)
- Location:
- trunk/src/VBox/Debugger
- Files:
-
- 3 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Debugger/DBGCEmulateCodeView.cpp
r5668 r5669 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 *******************************************************************************/ 49 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 50 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 51 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 52 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 53 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 54 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 133 55 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 134 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 135 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 136 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 137 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 56 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 138 57 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 139 58 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); … … 143 62 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 144 63 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 145 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);146 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);147 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);148 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);149 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);150 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);151 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);152 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);153 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);154 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);155 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);156 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);157 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);158 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);159 160 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);161 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);162 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);163 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);164 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);165 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);166 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);167 64 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 168 65 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 169 66 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 67 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 170 68 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 171 69 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); … … 173 71 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 174 72 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 73 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 175 74 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 176 75 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 177 178 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);179 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);180 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);181 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);182 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);183 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);184 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);185 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);186 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);187 188 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);189 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);190 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);191 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);192 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);193 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);194 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);195 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);196 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);197 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);198 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);199 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);200 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);201 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);202 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);203 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);204 205 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);206 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);207 208 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat);209 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb);210 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2);211 static void dbgcVarSetNoRange(PDBGCVAR pVar);212 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb);213 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress);214 215 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd);216 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd);217 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp);218 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp);219 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp);220 221 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol);222 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);223 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult);224 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd);225 76 226 77 … … 228 79 * Global Variables * 229 80 *******************************************************************************/ 230 /**231 * Pointer to head of the list of external commands.232 */233 static PDBGCEXTCMDS g_pExtCmdsHead; /** @todo rw protect g_pExtCmdsHead! */234 /** Locks the g_pExtCmdsHead list for reading. */235 #define DBGCEXTCMDS_LOCK_RD() do { } while (0)236 /** Locks the g_pExtCmdsHead list for writing. */237 #define DBGCEXTCMDS_LOCK_WR() do { } while (0)238 /** UnLocks the g_pExtCmdsHead list after reading. */239 #define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)240 /** UnLocks the g_pExtCmdsHead list after writing. */241 #define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)242 243 244 /** One argument of any kind. */245 static const DBGCVARDESC g_aArgAny[] =246 {247 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */248 { 0, 1, DBGCVAR_CAT_ANY, 0, "var", "Any type of argument." },249 };250 251 /** Multiple string arguments (min 1). */252 static const DBGCVARDESC g_aArgMultiStr[] =253 {254 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */255 { 1, ~0, DBGCVAR_CAT_STRING, 0, "strings", "One or more strings." },256 };257 258 /** Filename string. */259 static const DBGCVARDESC g_aArgFilename[] =260 {261 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */262 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },263 };264 265 266 /** 'br' arguments. */267 static const DBGCVARDESC g_aArgBrkREM[] =268 {269 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */270 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },271 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },272 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },273 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },274 };275 276 277 /** 'dg', 'dga', 'dl', 'dla' arguments. */278 static const DBGCVARDESC g_aArgDumpDT[] =279 {280 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */281 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." },282 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." },283 };284 285 286 /** 'di', 'dia' arguments. */287 static const DBGCVARDESC g_aArgDumpIDT[] =288 {289 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */290 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." },291 };292 293 294 /** 'dpd*' arguments. */295 static const DBGCVARDESC g_aArgDumpPD[] =296 {297 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */298 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." },299 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },300 };301 302 303 /** 'dpda' arguments. */304 static const DBGCVARDESC g_aArgDumpPDAddr[] =305 {306 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */307 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },308 };309 310 311 /** 'dpt?' arguments. */312 static const DBGCVARDESC g_aArgDumpPT[] =313 {314 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */315 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },316 };317 318 319 /** 'dpta' arguments. */320 static const DBGCVARDESC g_aArgDumpPTAddr[] =321 {322 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */323 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },324 };325 326 327 /** 'dt' arguments. */328 static const DBGCVARDESC g_aArgDumpTSS[] =329 {330 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */331 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." },332 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }333 };334 335 336 /** 'help' arguments. */337 static const DBGCVARDESC g_aArgHelp[] =338 {339 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */340 { 0, ~0, DBGCVAR_CAT_STRING, 0, "cmd/op", "Zero or more command or operator names." },341 };342 343 344 /** 'info' arguments. */345 static const DBGCVARDESC g_aArgInfo[] =346 {347 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */348 { 1, 1, DBGCVAR_CAT_STRING, 0, "info", "The name of the info to display." },349 { 0, 1, DBGCVAR_CAT_STRING, 0, "args", "String arguments to the handler." },350 };351 352 353 /** loadsyms arguments. */354 static const DBGCVARDESC g_aArgLoadSyms[] =355 {356 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */357 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },358 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "delta", "Delta to add to the loaded symbols. (optional)" },359 { 0, 1, DBGCVAR_CAT_STRING, 0, "module name", "Module name." },360 { 0, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "module address", "Module address." },361 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "module size", "The module size. (optional)" },362 };363 364 365 /** log arguments. */366 static const DBGCVARDESC g_aArgLog[] =367 {368 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */369 { 1, 1, DBGCVAR_CAT_STRING, 0, "groups", "Group modifier string (quote it!)." }370 };371 372 373 /** logdest arguments. */374 static const DBGCVARDESC g_aArgLogDest[] =375 {376 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */377 { 1, 1, DBGCVAR_CAT_STRING, 0, "dests", "Destination modifier string (quote it!)." }378 };379 380 381 /** logflags arguments. */382 static const DBGCVARDESC g_aArgLogFlags[] =383 {384 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */385 { 1, 1, DBGCVAR_CAT_STRING, 0, "flags", "Flag modifier string (quote it!)." }386 };387 388 389 /** 'set' arguments */390 static const DBGCVARDESC g_aArgSet[] =391 {392 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */393 { 1, 1, DBGCVAR_CAT_STRING, 0, "var", "Variable name." },394 { 1, 1, DBGCVAR_CAT_ANY, 0, "value", "Value to assign to the variable." },395 };396 397 398 399 400 401 /** Command descriptors for the basic commands. */402 static const DBGCCMD g_aCmds[] =403 {404 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */405 { "br", 1, 4, &g_aArgBrkREM[0], ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]",406 "Sets a recompiler specific breakpoint." },407 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },408 { "dg", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." },409 { "dga", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." },410 { "di", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." },411 { "dia", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." },412 { "dl", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." },413 { "dla", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." },414 { "dpd", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." },415 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." },416 { "dpdb", 1, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " },417 { "dpdg", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." },418 { "dpdh", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " },419 { "dpt", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." },420 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." },421 { "dptb", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." },422 { "dptg", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." },423 { "dpth", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." },424 { "dt", 0, 1, &g_aArgDumpTSS[0], ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." },425 { "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." },426 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },427 { "format", 1, 1, &g_aArgAny[0], ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },428 { "harakiri", 0, 0, NULL, 0, NULL, 0, dbgcCmdHarakiri, "", "Kills debugger process." },429 { "help", 0, ~0, &g_aArgHelp[0], ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'info help'." },430 { "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'." },431 { "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." },432 { "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." },433 { "log", 1, 1, &g_aArgLog[0], ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },434 { "logdest", 1, 1, &g_aArgLogDest[0], ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },435 { "logflags", 1, 1, &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags), NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },436 { "quit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },437 { "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." },438 { "set", 2, 2, &g_aArgSet[0], ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },439 { "showvars", 0, 0, NULL, 0, NULL, 0, dbgcCmdShowVars, "", "List all the defined variables." },440 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." },441 { "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },442 };443 444 445 81 /** 'ba' arguments. */ 446 82 static const DBGCVARDESC g_aArgBrkAcc[] = … … 476 112 477 113 114 /** 'br' arguments. */ 115 static const DBGCVARDESC g_aArgBrkREM[] = 116 { 117 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 118 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." }, 119 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" }, 120 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" }, 121 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" }, 122 }; 123 124 478 125 /** 'd?' arguments. */ 479 126 static const DBGCVARDESC g_aArgDumpMem[] = … … 481 128 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 482 129 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start dumping memory." }, 130 }; 131 132 133 /** 'dg', 'dga', 'dl', 'dla' arguments. */ 134 static const DBGCVARDESC g_aArgDumpDT[] = 135 { 136 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 137 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." }, 138 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." }, 139 }; 140 141 142 /** 'di', 'dia' arguments. */ 143 static const DBGCVARDESC g_aArgDumpIDT[] = 144 { 145 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 146 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." }, 147 }; 148 149 150 /** 'dpd*' arguments. */ 151 static const DBGCVARDESC g_aArgDumpPD[] = 152 { 153 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 154 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." }, 155 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." }, 156 }; 157 158 159 /** 'dpda' arguments. */ 160 static const DBGCVARDESC g_aArgDumpPDAddr[] = 161 { 162 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 163 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." }, 164 }; 165 166 167 /** 'dpt?' arguments. */ 168 static const DBGCVARDESC g_aArgDumpPT[] = 169 { 170 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 171 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." }, 172 }; 173 174 175 /** 'dpta' arguments. */ 176 static const DBGCVARDESC g_aArgDumpPTAddr[] = 177 { 178 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 179 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." }, 180 }; 181 182 183 /** 'dt' arguments. */ 184 static const DBGCVARDESC g_aArgDumpTSS[] = 185 { 186 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */ 187 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." }, 188 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." } 483 189 }; 484 190 … … 544 250 * The emulation isn't attempting to be identical, only somewhat similar. 545 251 */ 546 staticconst DBGCCMD g_aCmdsCodeView[] =252 const DBGCCMD g_aCmdsCodeView[] = 547 253 { 548 254 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */ … … 554 260 { "bl", 0, 0, NULL, 0, NULL, 0, dbgcCmdBrkList, "", "Lists all the breakpoints." }, 555 261 { "bp", 1, 4, &g_aArgBrkSet[0], RT_ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]", 556 "Sets a breakpoint (int 3)." }, 262 "Sets a breakpoint (int 3)." }, 263 { "br", 1, 4, &g_aArgBrkREM[0], RT_ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]", 264 "Sets a recompiler specific breakpoint." }, 557 265 { "d", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." }, 558 266 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." }, 559 267 { "db", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." }, 560 268 { "dd", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." }, 269 { "dg", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." }, 270 { "dga", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." }, 271 { "di", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." }, 272 { "dia", 0, ~0, &g_aArgDumpIDT[0], RT_ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." }, 273 { "dl", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." }, 274 { "dla", 0, ~0, &g_aArgDumpDT[0], RT_ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." }, 275 { "dpd", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." }, 276 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],RT_ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." }, 277 { "dpdb", 1, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " }, 278 { "dpdg", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." }, 279 { "dpdh", 0, 1, &g_aArgDumpPD[0], RT_ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " }, 280 { "dpt", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." }, 281 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],RT_ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." }, 282 { "dptb", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." }, 283 { "dptg", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." }, 284 { "dpth", 1, 1, &g_aArgDumpPT[0], RT_ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." }, 561 285 { "dq", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." }, 286 { "dt", 0, 1, &g_aArgDumpTSS[0], RT_ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." }, 562 287 { "dw", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." }, 563 288 { "g", 0, 0, NULL, 0, NULL, 0, dbgcCmdGo, "", "Continue execution." }, … … 583 308 }; 584 309 585 586 /** Operators. */ 587 static const DBGCOP g_aOps[] = 588 { 589 /* 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). */ 590 /* szName, cchName, fBinary, iPrecedence, pfnHandlerUnary, pfnHandlerBitwise */ 591 { {'-'}, 1, false, 1, dbgcOpMinus, NULL, "Unary minus." }, 592 { {'+'}, 1, false, 1, dbgcOpPluss, NULL, "Unary pluss." }, 593 { {'!'}, 1, false, 1, dbgcOpBooleanNot, NULL, "Boolean not." }, 594 { {'~'}, 1, false, 1, dbgcOpBitwiseNot, NULL, "Bitwise complement." }, 595 { {':'}, 1, true, 2, NULL, dbgcOpAddrFar, "Far pointer." }, 596 { {'%'}, 1, false, 3, dbgcOpAddrFlat, NULL, "Flat address." }, 597 { {'%','%'}, 2, false, 3, dbgcOpAddrPhys, NULL, "Physical address." }, 598 { {'#'}, 1, false, 3, dbgcOpAddrHost, NULL, "Flat host address." }, 599 { {'#','%','%'}, 3, false, 3, dbgcOpAddrHostPhys, NULL, "Physical host address." }, 600 { {'$'}, 1, false, 3, dbgcOpVar, NULL, "Reference a variable." }, 601 { {'*'}, 1, true, 10, NULL, dbgcOpMult, "Multiplication." }, 602 { {'/'}, 1, true, 11, NULL, dbgcOpDiv, "Division." }, 603 { {'%'}, 1, true, 12, NULL, dbgcOpMod, "Modulus." }, 604 { {'+'}, 1, true, 13, NULL, dbgcOpAdd, "Addition." }, 605 { {'-'}, 1, true, 14, NULL, dbgcOpSub, "Subtraction." }, 606 { {'<','<'}, 2, true, 15, NULL, dbgcOpBitwiseShiftLeft, "Bitwise left shift." }, 607 { {'>','>'}, 2, true, 16, NULL, dbgcOpBitwiseShiftRight, "Bitwise right shift." }, 608 { {'&'}, 1, true, 17, NULL, dbgcOpBitwiseAnd, "Bitwise and." }, 609 { {'^'}, 1, true, 18, NULL, dbgcOpBitwiseXor, "Bitwise exclusiv or." }, 610 { {'|'}, 1, true, 19, NULL, dbgcOpBitwiseOr, "Bitwise inclusive or." }, 611 { {'&','&'}, 2, true, 20, NULL, dbgcOpBooleanAnd, "Boolean and." }, 612 { {'|','|'}, 2, true, 21, NULL, dbgcOpBooleanOr, "Boolean or." }, 613 { {'L'}, 1, true, 22, NULL, dbgcOpRangeLength, "Range elements." }, 614 { {'L','B'}, 2, true, 23, NULL, dbgcOpRangeLengthBytes, "Range bytes." }, 615 { {'T'}, 1, true, 24, NULL, dbgcOpRangeTo, "Range to." } 616 }; 617 618 /** Bitmap where set bits indicates the characters the may start an operator name. */ 619 static uint32_t g_bmOperatorChars[256 / (4*8)]; 620 621 /** Register symbol uUser value. 622 * @{ 623 */ 624 /** If set the register set is the hypervisor and not the guest one. */ 625 #define SYMREG_FLAGS_HYPER RT_BIT(20) 626 /** If set a far conversion of the value will use the high 16 bit for the selector. 627 * If clear the low 16 bit will be used. */ 628 #define SYMREG_FLAGS_HIGH_SEL RT_BIT(21) 629 /** The shift value to calc the size of a register symbol from the uUser value. */ 630 #define SYMREG_SIZE_SHIFT (24) 631 /** Get the offset */ 632 #define SYMREG_OFFSET(uUser) (uUser & ((1 << 20) - 1)) 633 /** Get the size. */ 634 #define SYMREG_SIZE(uUser) ((uUser >> SYMREG_SIZE_SHIFT) & 0xff) 635 /** 1 byte. */ 636 #define SYMREG_SIZE_1 ( 1 << SYMREG_SIZE_SHIFT) 637 /** 2 byte. */ 638 #define SYMREG_SIZE_2 ( 2 << SYMREG_SIZE_SHIFT) 639 /** 4 byte. */ 640 #define SYMREG_SIZE_4 ( 4 << SYMREG_SIZE_SHIFT) 641 /** 6 byte. */ 642 #define SYMREG_SIZE_6 ( 6 << SYMREG_SIZE_SHIFT) 643 /** 8 byte. */ 644 #define SYMREG_SIZE_8 ( 8 << SYMREG_SIZE_SHIFT) 645 /** 12 byte. */ 646 #define SYMREG_SIZE_12 (12 << SYMREG_SIZE_SHIFT) 647 /** 16 byte. */ 648 #define SYMREG_SIZE_16 (16 << SYMREG_SIZE_SHIFT) 649 /** @} */ 650 651 /** Builtin Symbols. 652 * ASSUMES little endian register representation! 653 */ 654 static const DBGCSYM g_aSyms[] = 655 { 656 { "eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 }, 657 { "ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 }, 658 { "al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 }, 659 { "ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 }, 660 661 { "ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 }, 662 { "bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 }, 663 { "bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 }, 664 { "bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 }, 665 666 { "ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 }, 667 { "cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 }, 668 { "cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 }, 669 { "ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 }, 670 671 { "edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 }, 672 { "dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 }, 673 { "dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 }, 674 { "dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 }, 675 676 { "edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 }, 677 { "di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 }, 678 679 { "esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 }, 680 { "si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 }, 681 682 { "ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 }, 683 { "bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 }, 684 685 { "esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 }, 686 { "sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 }, 687 688 { "eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 }, 689 { "ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 }, 690 691 { "efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 692 { "eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 }, 693 { "fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 694 { "flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 }, 695 696 { "cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 }, 697 { "ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 }, 698 { "es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 }, 699 { "fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 }, 700 { "gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 }, 701 { "ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 }, 702 703 { "cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 }, 704 { "cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 }, 705 { "cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 }, 706 { "cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 }, 707 708 { "tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 }, 709 { "ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 }, 710 711 { "gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 }, 712 { "gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2 }, 713 { "gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 }, 714 715 { "idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 }, 716 { "idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2 }, 717 { "idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 }, 718 719 /* hypervisor */ 720 721 {".eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 722 {".ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 723 {".al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 724 {".ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 725 726 {".ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 727 {".bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 728 {".bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 729 {".bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 730 731 {".ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 732 {".cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 733 {".cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 734 {".ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 735 736 {".edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 737 {".dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 738 {".dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 739 {".dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER }, 740 741 {".edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 742 {".di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 743 744 {".esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 745 {".si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 746 747 {".ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 748 {".bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 749 750 {".esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 751 {".sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 752 753 {".eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 754 {".ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 755 756 {".efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 757 {".eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 758 {".fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 759 {".flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 760 761 {".cs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 762 {".ds", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ds) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 763 {".es", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, es) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 764 {".fs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, fs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 765 {".gs", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gs) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 766 {".ss", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ss) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 767 768 {".cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 769 {".cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 770 {".cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 771 {".cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 772 773 {".tr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, tr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 774 {".ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER }, 775 776 {".gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 777 {".gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 778 {".gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 779 780 {".idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER }, 781 {".idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER }, 782 {".idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER }, 783 784 }; 785 786 787 /** 788 * Prints full command help. 789 */ 790 static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal) 791 { 792 int rc; 793 794 /* the command */ 795 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 796 "%s%-*s %-30s %s", 797 fExternal ? "." : "", 798 fExternal ? 10 : 11, 799 pCmd->pszCmd, 800 pCmd->pszSyntax, 801 pCmd->pszDescription); 802 if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax) 803 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n"); 804 else if (pCmd->cArgsMin == pCmd->cArgsMax) 805 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin); 806 else if (pCmd->cArgsMax == ~0U) 807 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin); 808 else 809 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax); 810 811 /* argument descriptions. */ 812 for (unsigned i = 0; i < pCmd->cArgDescs; i++) 813 { 814 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, 815 " %-12s %s", 816 pCmd->paArgDescs[i].pszName, 817 pCmd->paArgDescs[i].pszDescription); 818 if (!pCmd->paArgDescs[i].cTimesMin) 819 { 820 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 821 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n"); 822 else 823 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax); 824 } 825 else 826 { 827 if (pCmd->paArgDescs[i].cTimesMax == ~0U) 828 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin); 829 else 830 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax); 831 } 832 } 833 return rc; 834 } 835 836 837 /** 838 * The 'help' command. 310 /** The number of commands in the CodeView/WinDbg emulation. */ 311 const unsigned g_cCmdsCodeView = RT_ELEMENTS(g_aCmdsCodeView); 312 313 314 315 /** 316 * The 'go' command. 839 317 * 840 318 * @returns VBox status. … … 845 323 * @param cArgs Number of arguments in the array. 846 324 */ 847 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)848 {849 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);850 int rc = VINF_SUCCESS;851 unsigned i;852 853 if (!cArgs)854 {855 /*856 * All the stuff.857 */858 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,859 "VirtualBox Debugger\n"860 "-------------------\n"861 "\n"862 "Commands and Functions:\n");863 for (i = 0; i < ELEMENTS(g_aCmds); i++)864 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,865 "%-11s %-30s %s\n",866 g_aCmds[i].pszCmd,867 g_aCmds[i].pszSyntax,868 g_aCmds[i].pszDescription);869 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,870 "\n"871 "Emulation: %s\n", pDbgc->pszEmulation);872 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;873 for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++)874 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,875 "%-11s %-30s %s\n",876 pCmd->pszCmd,877 pCmd->pszSyntax,878 pCmd->pszDescription);879 880 if (g_pExtCmdsHead)881 {882 DBGCEXTCMDS_LOCK_RD();883 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,884 "\n"885 "External Commands and Functions:\n");886 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)887 for (i = 0; i < pExtCmd->cCmds; i++)888 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,889 ".%-10s %-30s %s\n",890 pExtCmd->paCmds[i].pszCmd,891 pExtCmd->paCmds[i].pszSyntax,892 pExtCmd->paCmds[i].pszDescription);893 DBGCEXTCMDS_UNLOCK_RD();894 }895 896 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,897 "\n"898 "Operators:\n");899 unsigned iPrecedence = 0;900 unsigned cLeft = ELEMENTS(g_aOps);901 while (cLeft > 0)902 {903 for (i = 0; i < ELEMENTS(g_aOps); i++)904 if (g_aOps[i].iPrecedence == iPrecedence)905 {906 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,907 "%-10s %s %s\n",908 g_aOps[i].szName,909 g_aOps[i].fBinary ? "Binary" : "Unary ",910 g_aOps[i].pszDescription);911 cLeft--;912 }913 iPrecedence++;914 }915 }916 else917 {918 /*919 * Search for the arguments (strings).920 */921 for (unsigned iArg = 0; iArg < cArgs; iArg++)922 {923 Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);924 bool fFound = false;925 926 /* lookup in the emulation command list first */927 for (i = 0; i < pDbgc->cEmulationCmds; i++)928 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString))929 {930 rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);931 fFound = true;932 break;933 }934 935 /* lookup in the command list (even when found in the emulation) */936 for (i = 0; i < ELEMENTS(g_aCmds); i++)937 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString))938 {939 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);940 fFound = true;941 break;942 }943 944 /* external commands */945 if ( !fFound946 && g_pExtCmdsHead947 && paArgs[iArg].u.pszString[0] == '.')948 {949 DBGCEXTCMDS_LOCK_RD();950 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)951 for (i = 0; i < pExtCmd->cCmds; i++)952 if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1))953 {954 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true);955 fFound = true;956 break;957 }958 DBGCEXTCMDS_UNLOCK_RD();959 }960 961 /* operators */962 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))963 {964 for (i = 0; i < ELEMENTS(g_aOps); i++)965 if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))966 {967 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,968 "%-10s %s %s\n",969 g_aOps[i].szName,970 g_aOps[i].fBinary ? "Binary" : "Unary ",971 g_aOps[i].pszDescription);972 fFound = true;973 break;974 }975 }976 977 /* found? */978 if (!fFound)979 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,980 "error: '%s' was not found!\n",981 paArgs[iArg].u.pszString);982 } /* foreach argument */983 }984 985 NOREF(pCmd);986 NOREF(pVM);987 NOREF(pResult);988 return rc;989 }990 991 992 /**993 * The 'quit', 'exit' and 'bye' commands.994 *995 * @returns VBox status.996 * @param pCmd Pointer to the command descriptor (as registered).997 * @param pCmdHlp Pointer to command helper functions.998 * @param pVM Pointer to the current VM (if any).999 * @param paArgs Pointer to (readonly) array of arguments.1000 * @param cArgs Number of arguments in the array.1001 */1002 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1003 {1004 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");1005 NOREF(pCmd);1006 NOREF(pVM);1007 NOREF(paArgs);1008 NOREF(cArgs);1009 NOREF(pResult);1010 return VERR_DBGC_QUIT;1011 }1012 1013 1014 /**1015 * The 'go' command.1016 *1017 * @returns VBox status.1018 * @param pCmd Pointer to the command descriptor (as registered).1019 * @param pCmdHlp Pointer to command helper functions.1020 * @param pVM Pointer to the current VM (if any).1021 * @param paArgs Pointer to (readonly) array of arguments.1022 * @param cArgs Number of arguments in the array.1023 */1024 325 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1025 326 { … … 1041 342 NOREF(pResult); 1042 343 return 0; 1043 }1044 1045 /**1046 * The 'stop' command.1047 *1048 * @returns VBox status.1049 * @param pCmd Pointer to the command descriptor (as registered).1050 * @param pCmdHlp Pointer to command helper functions.1051 * @param pVM Pointer to the current VM (if any).1052 * @param paArgs Pointer to (readonly) array of arguments.1053 * @param cArgs Number of arguments in the array.1054 */1055 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1056 {1057 /*1058 * Check if the VM is halted or not before trying to halt it.1059 */1060 int rc;1061 if (DBGFR3IsHalted(pVM))1062 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");1063 else1064 {1065 rc = DBGFR3Halt(pVM);1066 if (VBOX_SUCCESS(rc))1067 rc = VWRN_DBGC_CMD_PENDING;1068 else1069 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");1070 }1071 1072 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);1073 return rc;1074 344 } 1075 345 … … 3542 2812 3543 2813 /** 3544 * The ' echo' command.2814 * The 's' command. 3545 2815 * 3546 2816 * @returns VBox status. … … 3551 2821 * @param cArgs Number of arguments in the array. 3552 2822 */ 3553 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3554 {3555 /*3556 * Loop thru the arguments and print them with one space between.3557 */3558 int rc = 0;3559 for (unsigned i = 0; i < cArgs; i++)3560 {3561 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)3562 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);3563 else3564 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");3565 if (VBOX_FAILURE(rc))3566 return rc;3567 }3568 NOREF(pCmd); NOREF(pResult); NOREF(pVM);3569 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");3570 }3571 3572 3573 /**3574 * The 'runscript' command.3575 *3576 * @returns VBox status.3577 * @param pCmd Pointer to the command descriptor (as registered).3578 * @param pCmdHlp Pointer to command helper functions.3579 * @param pVM Pointer to the current VM (if any).3580 * @param paArgs Pointer to (readonly) array of arguments.3581 * @param cArgs Number of arguments in the array.3582 */3583 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3584 {3585 /* check that the parser did what it's supposed to do. */3586 if ( cArgs != 13587 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)3588 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");3589 3590 /*3591 * Try open the script.3592 */3593 const char *pszFilename = paArgs[0].u.pszString;3594 FILE *pFile = fopen(pszFilename, "r");3595 if (!pFile)3596 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);3597 3598 /*3599 * Execute it line by line.3600 */3601 int rc = 0;3602 unsigned iLine = 0;3603 char szLine[8192];3604 while (fgets(szLine, sizeof(szLine), pFile))3605 {3606 /* check that the line isn't too long. */3607 char *pszEnd = strchr(szLine, '\0');3608 if (pszEnd == &szLine[sizeof(szLine) - 1])3609 {3610 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);3611 break;3612 }3613 iLine++;3614 3615 /* strip leading blanks and check for comment / blank line. */3616 char *psz = RTStrStripL(szLine);3617 if ( *psz == '\0'3618 || *psz == '\n'3619 || *psz == '#')3620 continue;3621 3622 /* strip trailing blanks and check for empty line (\r case). */3623 while ( pszEnd > psz3624 && isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */3625 *--pszEnd = '\0';3626 3627 /** @todo check for Control-C / Cancel at this point... */3628 3629 /*3630 * Execute the command.3631 *3632 * This is a bit wasteful with scratch space btw., can fix it later.3633 * The whole return code crap should be fixed too, so that it's possible3634 * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and3635 * more importantly why it failed.3636 */3637 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);3638 if (VBOX_FAILURE(rc))3639 {3640 if (rc == VERR_BUFFER_OVERFLOW)3641 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);3642 break;3643 }3644 if (rc == VWRN_DBGC_CMD_PENDING)3645 {3646 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);3647 break;3648 }3649 }3650 3651 fclose(pFile);3652 3653 NOREF(pCmd); NOREF(pResult); NOREF(pVM);3654 return rc;3655 }3656 3657 3658 /**3659 * The 's' command.3660 *3661 * @returns VBox status.3662 * @param pCmd Pointer to the command descriptor (as registered).3663 * @param pCmdHlp Pointer to command helper functions.3664 * @param pVM Pointer to the current VM (if any).3665 * @param paArgs Pointer to (readonly) array of arguments.3666 * @param cArgs Number of arguments in the array.3667 */3668 2823 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 3669 2824 { … … 3673 2828 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n"); 3674 2829 return -1; 3675 }3676 3677 3678 3679 /**3680 * Print formatted string.3681 *3682 * @param pHlp Pointer to this structure.3683 * @param pszFormat The format string.3684 * @param ... Arguments.3685 */3686 static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)3687 {3688 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);3689 va_list args;3690 va_start(args, pszFormat);3691 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);3692 va_end(args);3693 }3694 3695 3696 /**3697 * Print formatted string.3698 *3699 * @param pHlp Pointer to this structure.3700 * @param pszFormat The format string.3701 * @param args Argument list.3702 */3703 static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)3704 {3705 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);3706 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);3707 }3708 3709 3710 /**3711 * The 'info' command.3712 *3713 * @returns VBox status.3714 * @param pCmd Pointer to the command descriptor (as registered).3715 * @param pCmdHlp Pointer to command helper functions.3716 * @param pVM Pointer to the current VM (if any).3717 * @param paArgs Pointer to (readonly) array of arguments.3718 * @param cArgs Number of arguments in the array.3719 */3720 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3721 {3722 /*3723 * Validate input.3724 */3725 if ( cArgs < 13726 || cArgs > 23727 || paArgs[0].enmType != DBGCVAR_TYPE_STRING3728 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)3729 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");3730 if (!pVM)3731 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3732 3733 /*3734 * Dump it.3735 */3736 struct3737 {3738 DBGFINFOHLP Hlp;3739 PDBGCCMDHLP pCmdHlp;3740 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };3741 int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);3742 if (VBOX_FAILURE(rc))3743 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");3744 3745 NOREF(pCmd); NOREF(pResult);3746 return 0;3747 }3748 3749 3750 /**3751 * The 'log' command.3752 *3753 * @returns VBox status.3754 * @param pCmd Pointer to the command descriptor (as registered).3755 * @param pCmdHlp Pointer to command helper functions.3756 * @param pVM Pointer to the current VM (if any).3757 * @param paArgs Pointer to (readonly) array of arguments.3758 * @param cArgs Number of arguments in the array.3759 */3760 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3761 {3762 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);3763 if (VBOX_SUCCESS(rc))3764 return VINF_SUCCESS;3765 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3766 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);3767 }3768 3769 3770 /**3771 * The 'logdest' command.3772 *3773 * @returns VBox status.3774 * @param pCmd Pointer to the command descriptor (as registered).3775 * @param pCmdHlp Pointer to command helper functions.3776 * @param pVM Pointer to the current VM (if any).3777 * @param paArgs Pointer to (readonly) array of arguments.3778 * @param cArgs Number of arguments in the array.3779 */3780 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3781 {3782 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);3783 if (VBOX_SUCCESS(rc))3784 return VINF_SUCCESS;3785 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3786 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);3787 }3788 3789 3790 /**3791 * The 'logflags' command.3792 *3793 * @returns VBox status.3794 * @param pCmd Pointer to the command descriptor (as registered).3795 * @param pCmdHlp Pointer to command helper functions.3796 * @param pVM Pointer to the current VM (if any).3797 * @param paArgs Pointer to (readonly) array of arguments.3798 * @param cArgs Number of arguments in the array.3799 */3800 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3801 {3802 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);3803 if (VBOX_SUCCESS(rc))3804 return VINF_SUCCESS;3805 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3806 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);3807 }3808 3809 3810 /**3811 * The 'format' command.3812 *3813 * @returns VBox status.3814 * @param pCmd Pointer to the command descriptor (as registered).3815 * @param pCmdHlp Pointer to command helper functions.3816 * @param pVM Pointer to the current VM (if any).3817 * @param paArgs Pointer to (readonly) array of arguments.3818 * @param cArgs Number of arguments in the array.3819 */3820 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3821 {3822 LogFlow(("dbgcCmdFormat\n"));3823 static const char *apszRangeDesc[] =3824 {3825 "none", "bytes", "elements"3826 };3827 int rc;3828 3829 for (unsigned iArg = 0; iArg < cArgs; iArg++)3830 {3831 switch (paArgs[iArg].enmType)3832 {3833 case DBGCVAR_TYPE_UNKNOWN:3834 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3835 "Unknown variable type!\n");3836 break;3837 case DBGCVAR_TYPE_GC_FLAT:3838 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3839 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3840 "Guest flat address: %%%08x range %lld %s\n",3841 paArgs[iArg].u.GCFlat,3842 paArgs[iArg].u64Range,3843 apszRangeDesc[paArgs[iArg].enmRangeType]);3844 else3845 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3846 "Guest flat address: %%%08x\n",3847 paArgs[iArg].u.GCFlat);3848 break;3849 case DBGCVAR_TYPE_GC_FAR:3850 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3851 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3852 "Guest far address: %04x:%08x range %lld %s\n",3853 paArgs[iArg].u.GCFar.sel,3854 paArgs[iArg].u.GCFar.off,3855 paArgs[iArg].u64Range,3856 apszRangeDesc[paArgs[iArg].enmRangeType]);3857 else3858 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3859 "Guest far address: %04x:%08x\n",3860 paArgs[iArg].u.GCFar.sel,3861 paArgs[iArg].u.GCFar.off);3862 break;3863 case DBGCVAR_TYPE_GC_PHYS:3864 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3865 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3866 "Guest physical address: %%%%%08x range %lld %s\n",3867 paArgs[iArg].u.GCPhys,3868 paArgs[iArg].u64Range,3869 apszRangeDesc[paArgs[iArg].enmRangeType]);3870 else3871 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3872 "Guest physical address: %%%%%08x\n",3873 paArgs[iArg].u.GCPhys);3874 break;3875 case DBGCVAR_TYPE_HC_FLAT:3876 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3877 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3878 "Host flat address: %%%08x range %lld %s\n",3879 paArgs[iArg].u.pvHCFlat,3880 paArgs[iArg].u64Range,3881 apszRangeDesc[paArgs[iArg].enmRangeType]);3882 else3883 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3884 "Host flat address: %%%08x\n",3885 paArgs[iArg].u.pvHCFlat);3886 break;3887 case DBGCVAR_TYPE_HC_FAR:3888 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3889 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3890 "Host far address: %04x:%08x range %lld %s\n",3891 paArgs[iArg].u.HCFar.sel,3892 paArgs[iArg].u.HCFar.off,3893 paArgs[iArg].u64Range,3894 apszRangeDesc[paArgs[iArg].enmRangeType]);3895 else3896 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3897 "Host far address: %04x:%08x\n",3898 paArgs[iArg].u.HCFar.sel,3899 paArgs[iArg].u.HCFar.off);3900 break;3901 case DBGCVAR_TYPE_HC_PHYS:3902 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3903 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3904 "Host physical address: %VHp range %lld %s\n",3905 paArgs[iArg].u.HCPhys,3906 paArgs[iArg].u64Range,3907 apszRangeDesc[paArgs[iArg].enmRangeType]);3908 else3909 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3910 "Host physical address: %VHp\n",3911 paArgs[iArg].u.HCPhys);3912 break;3913 3914 case DBGCVAR_TYPE_STRING:3915 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3916 "String, %lld bytes long: %s\n",3917 paArgs[iArg].u64Range,3918 paArgs[iArg].u.pszString);3919 break;3920 3921 case DBGCVAR_TYPE_NUMBER:3922 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)3923 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3924 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",3925 paArgs[iArg].u.u64Number,3926 paArgs[iArg].u.u64Number,3927 paArgs[iArg].u.u64Number,3928 paArgs[iArg].u64Range,3929 apszRangeDesc[paArgs[iArg].enmRangeType]);3930 else3931 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3932 "Number: hex %llx dec 0i%lld oct 0t%llo\n",3933 paArgs[iArg].u.u64Number,3934 paArgs[iArg].u.u64Number,3935 paArgs[iArg].u.u64Number);3936 break;3937 3938 default:3939 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,3940 "Invalid argument type %d\n",3941 paArgs[iArg].enmType);3942 break;3943 }3944 } /* arg loop */3945 3946 NOREF(pCmd); NOREF(pVM); NOREF(pResult);3947 return 0;3948 2830 } 3949 2831 … … 4053 2935 } 4054 2936 4055 4056 /**4057 * The 'loadsyms' command.4058 *4059 * @returns VBox status.4060 * @param pCmd Pointer to the command descriptor (as registered).4061 * @param pCmdHlp Pointer to command helper functions.4062 * @param pVM Pointer to the current VM (if any).4063 * @param paArgs Pointer to (readonly) array of arguments.4064 * @param cArgs Number of arguments in the array.4065 */4066 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4067 {4068 /*4069 * Validate the parsing and make sense of the input.4070 * This is a mess as usual because we don't trust the parser yet.4071 */4072 if ( cArgs < 14073 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)4074 {4075 AssertMsgFailed(("Parse error, first argument required to be string!\n"));4076 return VERR_PARSE_INCORRECT_ARG_TYPE;4077 }4078 DBGCVAR AddrVar;4079 RTGCUINTPTR Delta = 0;4080 const char *pszModule = NULL;4081 RTGCUINTPTR ModuleAddress = 0;4082 unsigned cbModule = 0;4083 if (cArgs > 1)4084 {4085 unsigned iArg = 1;4086 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)4087 {4088 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;4089 iArg++;4090 }4091 if (iArg < cArgs)4092 {4093 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)4094 {4095 AssertMsgFailed(("Parse error, module argument required to be string!\n"));4096 return VERR_PARSE_INCORRECT_ARG_TYPE;4097 }4098 pszModule = paArgs[iArg].u.pszString;4099 iArg++;4100 if (iArg < cArgs)4101 {4102 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))4103 {4104 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));4105 return VERR_PARSE_INCORRECT_ARG_TYPE;4106 }4107 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);4108 if (VBOX_FAILURE(rc))4109 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);4110 ModuleAddress = paArgs[iArg].u.GCFlat;4111 iArg++;4112 if (iArg < cArgs)4113 {4114 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)4115 {4116 AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));4117 return VERR_PARSE_INCORRECT_ARG_TYPE;4118 }4119 cbModule = (unsigned)paArgs[iArg].u.u64Number;4120 iArg++;4121 if (iArg < cArgs)4122 {4123 AssertMsgFailed(("Parse error, too many arguments!\n"));4124 return VERR_PARSE_TOO_MANY_ARGUMENTS;4125 }4126 }4127 }4128 }4129 }4130 4131 /*4132 * Call the debug info manager about this loading...4133 */4134 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);4135 if (VBOX_FAILURE(rc))4136 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",4137 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);4138 4139 NOREF(pCmd); NOREF(pResult);4140 return VINF_SUCCESS;4141 }4142 4143 4144 /**4145 * The 'set' command.4146 *4147 * @returns VBox status.4148 * @param pCmd Pointer to the command descriptor (as registered).4149 * @param pCmdHlp Pointer to command helper functions.4150 * @param pVM Pointer to the current VM (if any).4151 * @param paArgs Pointer to (readonly) array of arguments.4152 * @param cArgs Number of arguments in the array.4153 */4154 static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4155 {4156 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4157 4158 /* parse sanity check. */4159 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));4160 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)4161 return VERR_PARSE_INCORRECT_ARG_TYPE;4162 4163 4164 /*4165 * A variable must start with an alpha chars and only contain alpha numerical chars.4166 */4167 const char *pszVar = paArgs[0].u.pszString;4168 if (!isalpha(*pszVar) || *pszVar == '_')4169 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,4170 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);4171 4172 while (isalnum(*pszVar) || *pszVar == '_')4173 *pszVar++;4174 if (*pszVar)4175 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,4176 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);4177 4178 4179 /*4180 * Calc variable size.4181 */4182 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);4183 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4184 cbVar += 1 + (size_t)paArgs[1].u64Range;4185 4186 /*4187 * Look for existing one.4188 */4189 pszVar = paArgs[0].u.pszString;4190 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4191 {4192 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))4193 {4194 /*4195 * Update existing variable.4196 */4197 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);4198 if (!pv)4199 return VERR_PARSE_NO_MEMORY;4200 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;4201 4202 pVar->Var = paArgs[1];4203 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);4204 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4205 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);4206 return 0;4207 }4208 }4209 4210 /*4211 * Allocate another.4212 */4213 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);4214 4215 pVar->Var = paArgs[1];4216 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);4217 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)4218 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);4219 4220 /* need to reallocate the pointer array too? */4221 if (!(pDbgc->cVars % 0x20))4222 {4223 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));4224 if (!pv)4225 {4226 RTMemFree(pVar);4227 return VERR_PARSE_NO_MEMORY;4228 }4229 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;4230 }4231 pDbgc->papVars[pDbgc->cVars++] = pVar;4232 4233 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);4234 return 0;4235 }4236 4237 4238 /**4239 * The 'unset' command.4240 *4241 * @returns VBox status.4242 * @param pCmd Pointer to the command descriptor (as registered).4243 * @param pCmdHlp Pointer to command helper functions.4244 * @param pVM Pointer to the current VM (if any).4245 * @param paArgs Pointer to (readonly) array of arguments.4246 * @param cArgs Number of arguments in the array.4247 */4248 static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4249 {4250 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4251 4252 /*4253 * Don't trust the parser.4254 */4255 for (unsigned i = 0; i < cArgs; i++)4256 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)4257 {4258 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));4259 return VERR_PARSE_INCORRECT_ARG_TYPE;4260 }4261 4262 /*4263 * Iterate the variables and unset them.4264 */4265 for (unsigned iArg = 0; iArg < cArgs; iArg++)4266 {4267 const char *pszVar = paArgs[iArg].u.pszString;4268 4269 /*4270 * Look up the variable.4271 */4272 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4273 {4274 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))4275 {4276 /*4277 * Shuffle the array removing this entry.4278 */4279 void *pvFree = pDbgc->papVars[iVar];4280 if (iVar + 1 < pDbgc->cVars)4281 memmove(&pDbgc->papVars[iVar],4282 &pDbgc->papVars[iVar + 1],4283 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));4284 pDbgc->papVars[--pDbgc->cVars] = NULL;4285 4286 RTMemFree(pvFree);4287 }4288 } /* lookup */4289 } /* arg loop */4290 4291 NOREF(pCmd); NOREF(pVM); NOREF(pResult);4292 return 0;4293 }4294 4295 4296 /**4297 * The 'loadvars' command.4298 *4299 * @returns VBox status.4300 * @param pCmd Pointer to the command descriptor (as registered).4301 * @param pCmdHlp Pointer to command helper functions.4302 * @param pVM Pointer to the current VM (if any).4303 * @param paArgs Pointer to (readonly) array of arguments.4304 * @param cArgs Number of arguments in the array.4305 */4306 static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4307 {4308 /*4309 * Don't trust the parser.4310 */4311 if ( cArgs != 14312 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)4313 {4314 AssertMsgFailed(("Expected one string exactly!\n"));4315 return VERR_PARSE_INCORRECT_ARG_TYPE;4316 }4317 4318 /*4319 * Iterate the variables and unset them.4320 */4321 FILE *pFile = fopen(paArgs[0].u.pszString, "r");4322 if (pFile)4323 {4324 char szLine[4096];4325 while (fgets(szLine, sizeof(szLine), pFile))4326 {4327 /* Strip it. */4328 char *psz = szLine;4329 while (isblank(*psz))4330 psz++;4331 int i = (int)strlen(psz) - 1;4332 while (i >= 0 && isspace(psz[i]))4333 psz[i--] ='\0';4334 /* Execute it if not comment or empty line. */4335 if ( *psz != '\0'4336 && *psz != '#'4337 && *psz != ';')4338 {4339 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);4340 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);4341 }4342 }4343 fclose(pFile);4344 }4345 else4346 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);4347 4348 NOREF(pCmd); NOREF(pVM); NOREF(pResult);4349 return 0;4350 }4351 4352 4353 /**4354 * The 'showvars' command.4355 *4356 * @returns VBox status.4357 * @param pCmd Pointer to the command descriptor (as registered).4358 * @param pCmdHlp Pointer to command helper functions.4359 * @param pVM Pointer to the current VM (if any).4360 * @param paArgs Pointer to (readonly) array of arguments.4361 * @param cArgs Number of arguments in the array.4362 */4363 static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4364 {4365 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4366 4367 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4368 {4369 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);4370 if (!rc)4371 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);4372 if (rc)4373 return rc;4374 }4375 4376 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);4377 return 0;4378 }4379 4380 4381 /**4382 * The 'harakiri' command.4383 *4384 * @returns VBox status.4385 * @param pCmd Pointer to the command descriptor (as registered).4386 * @param pCmdHlp Pointer to command helper functions.4387 * @param pVM Pointer to the current VM (if any).4388 * @param paArgs Pointer to (readonly) array of arguments.4389 * @param cArgs Number of arguments in the array.4390 */4391 static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4392 {4393 Log(("dbgcCmdHarakiri\n"));4394 for (;;)4395 exit(126);4396 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);4397 }4398 4399 4400 4401 4402 4403 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4404 //4405 //4406 // B u l t i n S y m b o l s4407 //4408 //4409 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4410 4411 4412 4413 /**4414 * Get builtin register symbol.4415 *4416 * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.4417 *4418 * @returns 0 on success.4419 * @returns VBox evaluation / parsing error code on failure.4420 * The caller does the bitching.4421 * @param pSymDesc Pointer to the symbol descriptor.4422 * @param pCmdHlp Pointer to the command callback structure.4423 * @param enmType The result type.4424 * @param pResult Where to store the result.4425 */4426 static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)4427 {4428 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));4429 4430 /*4431 * pVM is required.4432 */4433 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4434 Assert(pDbgc->pVM);4435 4436 /*4437 * Get the right CPU context.4438 */4439 PCPUMCTX pCtx;4440 int rc;4441 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))4442 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);4443 else4444 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);4445 if (VBOX_FAILURE(rc))4446 return rc;4447 4448 /*4449 * Get the value.4450 */4451 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);4452 uint64_t u64;4453 switch (SYMREG_SIZE(pSymDesc->uUser))4454 {4455 case 1: u64 = *(uint8_t *)pvValue; break;4456 case 2: u64 = *(uint16_t *)pvValue; break;4457 case 4: u64 = *(uint32_t *)pvValue; break;4458 case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;4459 case 8: u64 = *(uint64_t *)pvValue; break;4460 default:4461 return VERR_PARSE_NOT_IMPLEMENTED;4462 }4463 4464 /*4465 * Construct the desired result.4466 */4467 if (enmType == DBGCVAR_TYPE_ANY)4468 enmType = DBGCVAR_TYPE_NUMBER;4469 pResult->pDesc = NULL;4470 pResult->pNext = NULL;4471 pResult->enmType = enmType;4472 pResult->enmRangeType = DBGCVAR_RANGE_NONE;4473 pResult->u64Range = 0;4474 4475 switch (enmType)4476 {4477 case DBGCVAR_TYPE_GC_FLAT:4478 pResult->u.GCFlat = (RTGCPTR)u64;4479 break;4480 4481 case DBGCVAR_TYPE_GC_FAR:4482 switch (SYMREG_SIZE(pSymDesc->uUser))4483 {4484 case 4:4485 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4486 {4487 pResult->u.GCFar.off = (uint16_t)u64;4488 pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);4489 }4490 else4491 {4492 pResult->u.GCFar.sel = (uint16_t)u64;4493 pResult->u.GCFar.off = (uint16_t)(u64 >> 16);4494 }4495 break;4496 case 6:4497 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4498 {4499 pResult->u.GCFar.off = (uint32_t)u64;4500 pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);4501 }4502 else4503 {4504 pResult->u.GCFar.sel = (uint32_t)u64;4505 pResult->u.GCFar.off = (uint16_t)(u64 >> 32);4506 }4507 break;4508 4509 default:4510 return VERR_PARSE_BAD_RESULT_TYPE;4511 }4512 break;4513 4514 case DBGCVAR_TYPE_GC_PHYS:4515 pResult->u.GCPhys = (RTGCPHYS)u64;4516 break;4517 4518 case DBGCVAR_TYPE_HC_FLAT:4519 pResult->u.pvHCFlat = (void *)(uintptr_t)u64;4520 break;4521 4522 case DBGCVAR_TYPE_HC_FAR:4523 switch (SYMREG_SIZE(pSymDesc->uUser))4524 {4525 case 4:4526 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4527 {4528 pResult->u.HCFar.off = (uint16_t)u64;4529 pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);4530 }4531 else4532 {4533 pResult->u.HCFar.sel = (uint16_t)u64;4534 pResult->u.HCFar.off = (uint16_t)(u64 >> 16);4535 }4536 break;4537 case 6:4538 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))4539 {4540 pResult->u.HCFar.off = (uint32_t)u64;4541 pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);4542 }4543 else4544 {4545 pResult->u.HCFar.sel = (uint32_t)u64;4546 pResult->u.HCFar.off = (uint16_t)(u64 >> 32);4547 }4548 break;4549 4550 default:4551 return VERR_PARSE_BAD_RESULT_TYPE;4552 }4553 break;4554 4555 case DBGCVAR_TYPE_HC_PHYS:4556 pResult->u.GCPhys = (RTGCPHYS)u64;4557 break;4558 4559 case DBGCVAR_TYPE_NUMBER:4560 pResult->u.u64Number = u64;4561 break;4562 4563 case DBGCVAR_TYPE_STRING:4564 case DBGCVAR_TYPE_UNKNOWN:4565 default:4566 return VERR_PARSE_BAD_RESULT_TYPE;4567 4568 }4569 4570 return 0;4571 }4572 4573 4574 /**4575 * Set builtin register symbol.4576 *4577 * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.4578 *4579 * @returns 0 on success.4580 * @returns VBox evaluation / parsing error code on failure.4581 * The caller does the bitching.4582 * @param pSymDesc Pointer to the symbol descriptor.4583 * @param pCmdHlp Pointer to the command callback structure.4584 * @param pValue The value to assign the symbol.4585 */4586 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)4587 {4588 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));4589 4590 /*4591 * pVM is required.4592 */4593 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);4594 Assert(pDbgc->pVM);4595 4596 /*4597 * Get the right CPU context.4598 */4599 PCPUMCTX pCtx;4600 int rc;4601 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))4602 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);4603 else4604 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);4605 if (VBOX_FAILURE(rc))4606 return rc;4607 4608 /*4609 * Check the new value.4610 */4611 if (pValue->enmType != DBGCVAR_TYPE_NUMBER)4612 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;4613 4614 /*4615 * Set the value.4616 */4617 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);4618 switch (SYMREG_SIZE(pSymDesc->uUser))4619 {4620 case 1:4621 *(uint8_t *)pvValue = (uint8_t)pValue->u.u64Number;4622 break;4623 case 2:4624 *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;4625 break;4626 case 4:4627 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;4628 break;4629 case 6:4630 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;4631 ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);4632 break;4633 case 8:4634 *(uint64_t *)pvValue = pValue->u.u64Number;4635 break;4636 default:4637 return VERR_PARSE_NOT_IMPLEMENTED;4638 }4639 4640 return VINF_SUCCESS;4641 }4642 4643 4644 4645 4646 4647 4648 4649 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4650 //4651 //4652 // O p e r a t o r s4653 //4654 //4655 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//4656 4657 4658 /**4659 * Minus (unary).4660 *4661 * @returns 0 on success.4662 * @returns VBox evaluation / parsing error code on failure.4663 * The caller does the bitching.4664 * @param pDbgc Debugger console instance data.4665 * @param pArg The argument.4666 * @param pResult Where to store the result.4667 */4668 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4669 {4670 // LogFlow(("dbgcOpMinus\n"));4671 *pResult = *pArg;4672 switch (pArg->enmType)4673 {4674 case DBGCVAR_TYPE_GC_FLAT:4675 pResult->u.GCFlat = -(RTGCINTPTR)pResult->u.GCFlat;4676 break;4677 case DBGCVAR_TYPE_GC_FAR:4678 pResult->u.GCFar.off = -(int32_t)pResult->u.GCFar.off;4679 break;4680 case DBGCVAR_TYPE_GC_PHYS:4681 pResult->u.GCPhys = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;4682 break;4683 case DBGCVAR_TYPE_HC_FLAT:4684 pResult->u.pvHCFlat = (void *) -(intptr_t)pResult->u.pvHCFlat;4685 break;4686 case DBGCVAR_TYPE_HC_FAR:4687 pResult->u.HCFar.off = -(int32_t)pResult->u.HCFar.off;4688 break;4689 case DBGCVAR_TYPE_HC_PHYS:4690 pResult->u.HCPhys = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;4691 break;4692 case DBGCVAR_TYPE_NUMBER:4693 pResult->u.u64Number = -(int64_t)pResult->u.u64Number;4694 break;4695 4696 case DBGCVAR_TYPE_UNKNOWN:4697 case DBGCVAR_TYPE_STRING:4698 default:4699 return VERR_PARSE_INCORRECT_ARG_TYPE;4700 }4701 NOREF(pDbgc);4702 return 0;4703 }4704 4705 4706 /**4707 * Pluss (unary).4708 *4709 * @returns 0 on success.4710 * @returns VBox evaluation / parsing error code on failure.4711 * The caller does the bitching.4712 * @param pDbgc Debugger console instance data.4713 * @param pArg The argument.4714 * @param pResult Where to store the result.4715 */4716 static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4717 {4718 // LogFlow(("dbgcOpPluss\n"));4719 *pResult = *pArg;4720 switch (pArg->enmType)4721 {4722 case DBGCVAR_TYPE_GC_FLAT:4723 case DBGCVAR_TYPE_GC_FAR:4724 case DBGCVAR_TYPE_GC_PHYS:4725 case DBGCVAR_TYPE_HC_FLAT:4726 case DBGCVAR_TYPE_HC_FAR:4727 case DBGCVAR_TYPE_HC_PHYS:4728 case DBGCVAR_TYPE_NUMBER:4729 break;4730 4731 case DBGCVAR_TYPE_UNKNOWN:4732 case DBGCVAR_TYPE_STRING:4733 default:4734 return VERR_PARSE_INCORRECT_ARG_TYPE;4735 }4736 NOREF(pDbgc);4737 return 0;4738 }4739 4740 4741 /**4742 * Boolean not (unary).4743 *4744 * @returns 0 on success.4745 * @returns VBox evaluation / parsing error code on failure.4746 * The caller does the bitching.4747 * @param pDbgc Debugger console instance data.4748 * @param pArg The argument.4749 * @param pResult Where to store the result.4750 */4751 static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4752 {4753 // LogFlow(("dbgcOpBooleanNot\n"));4754 *pResult = *pArg;4755 switch (pArg->enmType)4756 {4757 case DBGCVAR_TYPE_GC_FLAT:4758 pResult->u.u64Number = !pResult->u.GCFlat;4759 break;4760 case DBGCVAR_TYPE_GC_FAR:4761 pResult->u.u64Number = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;4762 break;4763 case DBGCVAR_TYPE_GC_PHYS:4764 pResult->u.u64Number = !pResult->u.GCPhys;4765 break;4766 case DBGCVAR_TYPE_HC_FLAT:4767 pResult->u.u64Number = !pResult->u.pvHCFlat;4768 break;4769 case DBGCVAR_TYPE_HC_FAR:4770 pResult->u.u64Number = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;4771 break;4772 case DBGCVAR_TYPE_HC_PHYS:4773 pResult->u.u64Number = !pResult->u.HCPhys;4774 break;4775 case DBGCVAR_TYPE_NUMBER:4776 pResult->u.u64Number = !pResult->u.u64Number;4777 break;4778 case DBGCVAR_TYPE_STRING:4779 pResult->u.u64Number = !pResult->u64Range;4780 break;4781 4782 case DBGCVAR_TYPE_UNKNOWN:4783 default:4784 return VERR_PARSE_INCORRECT_ARG_TYPE;4785 }4786 pResult->enmType = DBGCVAR_TYPE_NUMBER;4787 NOREF(pDbgc);4788 return 0;4789 }4790 4791 4792 /**4793 * Bitwise not (unary).4794 *4795 * @returns 0 on success.4796 * @returns VBox evaluation / parsing error code on failure.4797 * The caller does the bitching.4798 * @param pDbgc Debugger console instance data.4799 * @param pArg The argument.4800 * @param pResult Where to store the result.4801 */4802 static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4803 {4804 // LogFlow(("dbgcOpBitwiseNot\n"));4805 *pResult = *pArg;4806 switch (pArg->enmType)4807 {4808 case DBGCVAR_TYPE_GC_FLAT:4809 pResult->u.GCFlat = ~pResult->u.GCFlat;4810 break;4811 case DBGCVAR_TYPE_GC_FAR:4812 pResult->u.GCFar.off = ~pResult->u.GCFar.off;4813 break;4814 case DBGCVAR_TYPE_GC_PHYS:4815 pResult->u.GCPhys = ~pResult->u.GCPhys;4816 break;4817 case DBGCVAR_TYPE_HC_FLAT:4818 pResult->u.pvHCFlat = (void *)~(uintptr_t)pResult->u.pvHCFlat;4819 break;4820 case DBGCVAR_TYPE_HC_FAR:4821 pResult->u.HCFar.off= ~pResult->u.HCFar.off;4822 break;4823 case DBGCVAR_TYPE_HC_PHYS:4824 pResult->u.HCPhys = ~pResult->u.HCPhys;4825 break;4826 case DBGCVAR_TYPE_NUMBER:4827 pResult->u.u64Number = ~pResult->u.u64Number;4828 break;4829 4830 case DBGCVAR_TYPE_UNKNOWN:4831 case DBGCVAR_TYPE_STRING:4832 default:4833 return VERR_PARSE_INCORRECT_ARG_TYPE;4834 }4835 NOREF(pDbgc);4836 return 0;4837 }4838 4839 4840 /**4841 * Reference variable (unary).4842 *4843 * @returns 0 on success.4844 * @returns VBox evaluation / parsing error code on failure.4845 * The caller does the bitching.4846 * @param pDbgc Debugger console instance data.4847 * @param pArg The argument.4848 * @param pResult Where to store the result.4849 */4850 static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4851 {4852 // LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));4853 /*4854 * Parse sanity.4855 */4856 if (pArg->enmType != DBGCVAR_TYPE_STRING)4857 return VERR_PARSE_INCORRECT_ARG_TYPE;4858 4859 /*4860 * Lookup the variable.4861 */4862 const char *pszVar = pArg->u.pszString;4863 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)4864 {4865 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))4866 {4867 *pResult = pDbgc->papVars[iVar]->Var;4868 return 0;4869 }4870 }4871 4872 return VERR_PARSE_VARIABLE_NOT_FOUND;4873 }4874 4875 4876 /**4877 * Flat address (unary).4878 *4879 * @returns VINF_SUCCESS on success.4880 * @returns VBox evaluation / parsing error code on failure.4881 * The caller does the bitching.4882 * @param pDbgc Debugger console instance data.4883 * @param pArg The argument.4884 * @param pResult Where to store the result.4885 */4886 static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4887 {4888 // LogFlow(("dbgcOpAddrFlat\n"));4889 int rc;4890 *pResult = *pArg;4891 4892 switch (pArg->enmType)4893 {4894 case DBGCVAR_TYPE_GC_FLAT:4895 return VINF_SUCCESS;4896 4897 case DBGCVAR_TYPE_GC_FAR:4898 {4899 Assert(pDbgc->pVM);4900 DBGFADDRESS Address;4901 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);4902 if (VBOX_SUCCESS(rc))4903 {4904 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;4905 pResult->u.GCFlat = Address.FlatPtr;4906 return VINF_SUCCESS;4907 }4908 return VERR_PARSE_CONVERSION_FAILED;4909 }4910 4911 case DBGCVAR_TYPE_GC_PHYS:4912 //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.4913 return VERR_PARSE_INCORRECT_ARG_TYPE;4914 4915 case DBGCVAR_TYPE_HC_FLAT:4916 return VINF_SUCCESS;4917 4918 case DBGCVAR_TYPE_HC_FAR:4919 return VERR_PARSE_INCORRECT_ARG_TYPE;4920 4921 case DBGCVAR_TYPE_HC_PHYS:4922 Assert(pDbgc->pVM);4923 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;4924 rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);4925 if (VBOX_SUCCESS(rc))4926 return VINF_SUCCESS;4927 return VERR_PARSE_CONVERSION_FAILED;4928 4929 case DBGCVAR_TYPE_NUMBER:4930 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;4931 pResult->u.GCFlat = (RTGCPTR)pResult->u.u64Number;4932 return VINF_SUCCESS;4933 4934 case DBGCVAR_TYPE_STRING:4935 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);4936 4937 case DBGCVAR_TYPE_UNKNOWN:4938 default:4939 return VERR_PARSE_INCORRECT_ARG_TYPE;4940 }4941 }4942 4943 4944 /**4945 * Physical address (unary).4946 *4947 * @returns 0 on success.4948 * @returns VBox evaluation / parsing error code on failure.4949 * The caller does the bitching.4950 * @param pDbgc Debugger console instance data.4951 * @param pArg The argument.4952 * @param pResult Where to store the result.4953 */4954 static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)4955 {4956 // LogFlow(("dbgcOpAddrPhys\n"));4957 int rc;4958 4959 *pResult = *pArg;4960 switch (pArg->enmType)4961 {4962 case DBGCVAR_TYPE_GC_FLAT:4963 Assert(pDbgc->pVM);4964 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;4965 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);4966 if (VBOX_SUCCESS(rc))4967 return 0;4968 /** @todo more memory types! */4969 return VERR_PARSE_CONVERSION_FAILED;4970 4971 case DBGCVAR_TYPE_GC_FAR:4972 {4973 Assert(pDbgc->pVM);4974 DBGFADDRESS Address;4975 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);4976 if (VBOX_SUCCESS(rc))4977 {4978 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;4979 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);4980 if (VBOX_SUCCESS(rc))4981 return 0;4982 /** @todo more memory types! */4983 }4984 return VERR_PARSE_CONVERSION_FAILED;4985 }4986 4987 case DBGCVAR_TYPE_GC_PHYS:4988 return 0;4989 4990 case DBGCVAR_TYPE_HC_FLAT:4991 Assert(pDbgc->pVM);4992 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;4993 rc = PGMR3DbgHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);4994 if (VBOX_SUCCESS(rc))4995 return 0;4996 /** @todo more memory types! */4997 return VERR_PARSE_CONVERSION_FAILED;4998 4999 case DBGCVAR_TYPE_HC_FAR:5000 return VERR_PARSE_INCORRECT_ARG_TYPE;5001 5002 case DBGCVAR_TYPE_HC_PHYS:5003 return 0;5004 5005 case DBGCVAR_TYPE_NUMBER:5006 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;5007 pResult->u.GCPhys = (RTGCPHYS)pResult->u.u64Number;5008 return 0;5009 5010 case DBGCVAR_TYPE_STRING:5011 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);5012 5013 case DBGCVAR_TYPE_UNKNOWN:5014 default:5015 return VERR_PARSE_INCORRECT_ARG_TYPE;5016 }5017 return 0;5018 }5019 5020 5021 /**5022 * Physical host address (unary).5023 *5024 * @returns 0 on success.5025 * @returns VBox evaluation / parsing error code on failure.5026 * The caller does the bitching.5027 * @param pDbgc Debugger console instance data.5028 * @param pArg The argument.5029 * @param pResult Where to store the result.5030 */5031 static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5032 {5033 // LogFlow(("dbgcOpAddrPhys\n"));5034 int rc;5035 5036 *pResult = *pArg;5037 switch (pArg->enmType)5038 {5039 case DBGCVAR_TYPE_GC_FLAT:5040 Assert(pDbgc->pVM);5041 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5042 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);5043 if (VBOX_SUCCESS(rc))5044 return 0;5045 /** @todo more memory types. */5046 return VERR_PARSE_CONVERSION_FAILED;5047 5048 case DBGCVAR_TYPE_GC_FAR:5049 {5050 Assert(pDbgc->pVM);5051 DBGFADDRESS Address;5052 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5053 if (VBOX_SUCCESS(rc))5054 {5055 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5056 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);5057 if (VBOX_SUCCESS(rc))5058 return 0;5059 /** @todo more memory types. */5060 }5061 return VERR_PARSE_CONVERSION_FAILED;5062 }5063 5064 case DBGCVAR_TYPE_GC_PHYS:5065 Assert(pDbgc->pVM);5066 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5067 rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);5068 if (VBOX_SUCCESS(rc))5069 return 0;5070 return VERR_PARSE_CONVERSION_FAILED;5071 5072 case DBGCVAR_TYPE_HC_FLAT:5073 Assert(pDbgc->pVM);5074 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5075 rc = PGMR3DbgHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);5076 if (VBOX_SUCCESS(rc))5077 return 0;5078 /** @todo more memory types! */5079 return VERR_PARSE_CONVERSION_FAILED;5080 5081 case DBGCVAR_TYPE_HC_FAR:5082 return VERR_PARSE_INCORRECT_ARG_TYPE;5083 5084 case DBGCVAR_TYPE_HC_PHYS:5085 return 0;5086 5087 case DBGCVAR_TYPE_NUMBER:5088 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;5089 pResult->u.HCPhys = (RTGCPHYS)pResult->u.u64Number;5090 return 0;5091 5092 case DBGCVAR_TYPE_STRING:5093 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);5094 5095 case DBGCVAR_TYPE_UNKNOWN:5096 default:5097 return VERR_PARSE_INCORRECT_ARG_TYPE;5098 }5099 return 0;5100 }5101 5102 5103 /**5104 * Host address (unary).5105 *5106 * @returns 0 on success.5107 * @returns VBox evaluation / parsing error code on failure.5108 * The caller does the bitching.5109 * @param pDbgc Debugger console instance data.5110 * @param pArg The argument.5111 * @param pResult Where to store the result.5112 */5113 static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)5114 {5115 // LogFlow(("dbgcOpAddrHost\n"));5116 int rc;5117 5118 *pResult = *pArg;5119 switch (pArg->enmType)5120 {5121 case DBGCVAR_TYPE_GC_FLAT:5122 Assert(pDbgc->pVM);5123 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5124 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);5125 if (VBOX_SUCCESS(rc))5126 return 0;5127 /** @todo more memory types. */5128 return VERR_PARSE_CONVERSION_FAILED;5129 5130 case DBGCVAR_TYPE_GC_FAR:5131 {5132 Assert(pDbgc->pVM);5133 DBGFADDRESS Address;5134 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);5135 if (VBOX_SUCCESS(rc))5136 {5137 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5138 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);5139 if (VBOX_SUCCESS(rc))5140 return 0;5141 /** @todo more memory types. */5142 }5143 return VERR_PARSE_CONVERSION_FAILED;5144 }5145 5146 case DBGCVAR_TYPE_GC_PHYS:5147 Assert(pDbgc->pVM);5148 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5149 rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);5150 if (VBOX_SUCCESS(rc))5151 return 0;5152 return VERR_PARSE_CONVERSION_FAILED;5153 5154 case DBGCVAR_TYPE_HC_FLAT:5155 return 0;5156 5157 case DBGCVAR_TYPE_HC_FAR:5158 case DBGCVAR_TYPE_HC_PHYS:5159 /** @todo !*/5160 return VERR_PARSE_CONVERSION_FAILED;5161 5162 case DBGCVAR_TYPE_NUMBER:5163 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;5164 pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;5165 return 0;5166 5167 case DBGCVAR_TYPE_STRING:5168 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);5169 5170 case DBGCVAR_TYPE_UNKNOWN:5171 default:5172 return VERR_PARSE_INCORRECT_ARG_TYPE;5173 }5174 }5175 5176 /**5177 * Bitwise not (unary).5178 *5179 * @returns 0 on success.5180 * @returns VBox evaluation / parsing error code on failure.5181 * The caller does the bitching.5182 * @param pDbgc Debugger console instance data.5183 * @param pArg The argument.5184 * @param pResult Where to store the result.5185 */5186 static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5187 {5188 // LogFlow(("dbgcOpAddrFar\n"));5189 int rc;5190 5191 switch (pArg1->enmType)5192 {5193 case DBGCVAR_TYPE_STRING:5194 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);5195 if (VBOX_FAILURE(rc))5196 return rc;5197 break;5198 case DBGCVAR_TYPE_NUMBER:5199 *pResult = *pArg1;5200 break;5201 5202 case DBGCVAR_TYPE_GC_FLAT:5203 case DBGCVAR_TYPE_GC_FAR:5204 case DBGCVAR_TYPE_GC_PHYS:5205 case DBGCVAR_TYPE_HC_FLAT:5206 case DBGCVAR_TYPE_HC_FAR:5207 case DBGCVAR_TYPE_HC_PHYS:5208 case DBGCVAR_TYPE_UNKNOWN:5209 default:5210 return VERR_PARSE_INCORRECT_ARG_TYPE;5211 }5212 pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;5213 5214 /* common code for the two types we support. */5215 switch (pArg2->enmType)5216 {5217 case DBGCVAR_TYPE_GC_FLAT:5218 pResult->u.GCFar.off = pArg2->u.GCFlat;5219 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5220 break;5221 5222 case DBGCVAR_TYPE_HC_FLAT:5223 pResult->u.HCFar.off = pArg2->u.GCFlat;5224 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5225 break;5226 5227 case DBGCVAR_TYPE_NUMBER:5228 pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;5229 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5230 break;5231 5232 case DBGCVAR_TYPE_STRING:5233 {5234 DBGCVAR Var;5235 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);5236 if (VBOX_FAILURE(rc))5237 return rc;5238 pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;5239 pResult->enmType = DBGCVAR_TYPE_GC_FAR;5240 break;5241 }5242 5243 case DBGCVAR_TYPE_GC_FAR:5244 case DBGCVAR_TYPE_GC_PHYS:5245 case DBGCVAR_TYPE_HC_FAR:5246 case DBGCVAR_TYPE_HC_PHYS:5247 case DBGCVAR_TYPE_UNKNOWN:5248 default:5249 return VERR_PARSE_INCORRECT_ARG_TYPE;5250 }5251 return 0;5252 5253 }5254 5255 5256 /**5257 * Multiplication operator (binary).5258 *5259 * @returns 0 on success.5260 * @returns VBox evaluation / parsing error code on failure.5261 * The caller does the bitching.5262 * @param pDbgc Debugger console instance data.5263 * @param pArg1 The first argument.5264 * @param pArg2 The 2nd argument.5265 * @param pResult Where to store the result.5266 */5267 static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5268 {5269 // LogFlow(("dbgcOpMult\n"));5270 int rc;5271 5272 /*5273 * Switch the factors so we preserve pointers, far pointers are considered more5274 * important that physical and flat pointers.5275 */5276 if ( DBGCVAR_ISPOINTER(pArg2->enmType)5277 && ( !DBGCVAR_ISPOINTER(pArg1->enmType)5278 || ( DBGCVAR_IS_FAR_PTR(pArg2->enmType)5279 && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))5280 {5281 PCDBGCVAR pTmp = pArg1;5282 pArg2 = pArg1;5283 pArg1 = pTmp;5284 }5285 5286 /*5287 * Convert the 2nd number into a number we use multiply the first with.5288 */5289 DBGCVAR Factor2 = *pArg2;5290 if ( Factor2.enmType == DBGCVAR_TYPE_STRING5291 || Factor2.enmType == DBGCVAR_TYPE_SYMBOL)5292 {5293 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);5294 if (VBOX_FAILURE(rc))5295 return rc;5296 }5297 uint64_t u64Factor;5298 switch (Factor2.enmType)5299 {5300 case DBGCVAR_TYPE_GC_FLAT: u64Factor = Factor2.u.GCFlat; break;5301 case DBGCVAR_TYPE_GC_FAR: u64Factor = Factor2.u.GCFar.off; break;5302 case DBGCVAR_TYPE_GC_PHYS: u64Factor = Factor2.u.GCPhys; break;5303 case DBGCVAR_TYPE_HC_FLAT: u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;5304 case DBGCVAR_TYPE_HC_FAR: u64Factor = Factor2.u.HCFar.off; break;5305 case DBGCVAR_TYPE_HC_PHYS: u64Factor = Factor2.u.HCPhys; break;5306 case DBGCVAR_TYPE_NUMBER: u64Factor = Factor2.u.u64Number; break;5307 default:5308 return VERR_PARSE_INCORRECT_ARG_TYPE;5309 }5310 5311 /*5312 * Fix symbols in the 1st factor.5313 */5314 *pResult = *pArg1;5315 if ( pResult->enmType == DBGCVAR_TYPE_STRING5316 || pResult->enmType == DBGCVAR_TYPE_SYMBOL)5317 {5318 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);5319 if (VBOX_FAILURE(rc))5320 return rc;5321 }5322 5323 /*5324 * Do the multiplication.5325 */5326 switch (pArg1->enmType)5327 {5328 case DBGCVAR_TYPE_GC_FLAT: pResult->u.GCFlat *= u64Factor; break;5329 case DBGCVAR_TYPE_GC_FAR: pResult->u.GCFar.off *= u64Factor; break;5330 case DBGCVAR_TYPE_GC_PHYS: pResult->u.GCPhys *= u64Factor; break;5331 case DBGCVAR_TYPE_HC_FLAT:5332 pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);5333 break;5334 case DBGCVAR_TYPE_HC_FAR: pResult->u.HCFar.off *= u64Factor; break;5335 case DBGCVAR_TYPE_HC_PHYS: pResult->u.HCPhys *= u64Factor; break;5336 case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number *= u64Factor; break;5337 default:5338 return VERR_PARSE_INCORRECT_ARG_TYPE;5339 }5340 return 0;5341 }5342 5343 5344 /**5345 * Division operator (binary).5346 *5347 * @returns 0 on success.5348 * @returns VBox evaluation / parsing error code on failure.5349 * The caller does the bitching.5350 * @param pDbgc Debugger console instance data.5351 * @param pArg1 The first argument.5352 * @param pArg2 The 2nd argument.5353 * @param pResult Where to store the result.5354 */5355 static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5356 {5357 LogFlow(("dbgcOpDiv\n"));5358 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5359 return -1;5360 }5361 5362 5363 /**5364 * Modulus operator (binary).5365 *5366 * @returns 0 on success.5367 * @returns VBox evaluation / parsing error code on failure.5368 * The caller does the bitching.5369 * @param pDbgc Debugger console instance data.5370 * @param pArg1 The first argument.5371 * @param pArg2 The 2nd argument.5372 * @param pResult Where to store the result.5373 */5374 static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5375 {5376 LogFlow(("dbgcOpMod\n"));5377 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5378 return -1;5379 }5380 5381 5382 /**5383 * Addition operator (binary).5384 *5385 * @returns 0 on success.5386 * @returns VBox evaluation / parsing error code on failure.5387 * The caller does the bitching.5388 * @param pDbgc Debugger console instance data.5389 * @param pArg1 The first argument.5390 * @param pArg2 The 2nd argument.5391 * @param pResult Where to store the result.5392 */5393 static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5394 {5395 // LogFlow(("dbgcOpAdd\n"));5396 5397 /*5398 * An addition operation will return (when possible) the left side type in the5399 * expression. We make an omission for numbers, where we'll take the right side5400 * type instead. An expression where only the left hand side is a string we'll5401 * use the right hand type assuming that the string is a symbol.5402 */5403 if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)5404 || (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))5405 {5406 PCDBGCVAR pTmp = pArg2;5407 pArg2 = pArg1;5408 pArg1 = pTmp;5409 }5410 DBGCVAR Sym1, Sym2;5411 if (pArg1->enmType == DBGCVAR_TYPE_STRING)5412 {5413 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);5414 if (VBOX_FAILURE(rc))5415 return rc;5416 pArg1 = &Sym1;5417 5418 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);5419 if (VBOX_FAILURE(rc))5420 return rc;5421 pArg2 = &Sym2;5422 }5423 5424 int rc;5425 DBGCVAR Var;5426 DBGCVAR Var2;5427 switch (pArg1->enmType)5428 {5429 /*5430 * GC Flat5431 */5432 case DBGCVAR_TYPE_GC_FLAT:5433 switch (pArg2->enmType)5434 {5435 case DBGCVAR_TYPE_HC_FLAT:5436 case DBGCVAR_TYPE_HC_FAR:5437 case DBGCVAR_TYPE_HC_PHYS:5438 return VERR_PARSE_INVALID_OPERATION;5439 default:5440 *pResult = *pArg1;5441 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5442 if (VBOX_FAILURE(rc))5443 return rc;5444 pResult->u.GCFlat += pArg2->u.GCFlat;5445 break;5446 }5447 break;5448 5449 /*5450 * GC Far5451 */5452 case DBGCVAR_TYPE_GC_FAR:5453 switch (pArg2->enmType)5454 {5455 case DBGCVAR_TYPE_HC_FLAT:5456 case DBGCVAR_TYPE_HC_FAR:5457 case DBGCVAR_TYPE_HC_PHYS:5458 return VERR_PARSE_INVALID_OPERATION;5459 case DBGCVAR_TYPE_NUMBER:5460 *pResult = *pArg1;5461 pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;5462 break;5463 default:5464 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5465 if (VBOX_FAILURE(rc))5466 return rc;5467 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5468 if (VBOX_FAILURE(rc))5469 return rc;5470 pResult->u.GCFlat += pArg2->u.GCFlat;5471 break;5472 }5473 break;5474 5475 /*5476 * GC Phys5477 */5478 case DBGCVAR_TYPE_GC_PHYS:5479 switch (pArg2->enmType)5480 {5481 case DBGCVAR_TYPE_HC_FLAT:5482 case DBGCVAR_TYPE_HC_FAR:5483 case DBGCVAR_TYPE_HC_PHYS:5484 return VERR_PARSE_INVALID_OPERATION;5485 default:5486 *pResult = *pArg1;5487 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);5488 if (VBOX_FAILURE(rc))5489 return rc;5490 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)5491 return VERR_PARSE_INVALID_OPERATION;5492 pResult->u.GCPhys += Var.u.GCPhys;5493 break;5494 }5495 break;5496 5497 /*5498 * HC Flat5499 */5500 case DBGCVAR_TYPE_HC_FLAT:5501 *pResult = *pArg1;5502 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5503 if (VBOX_FAILURE(rc))5504 return rc;5505 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5506 if (VBOX_FAILURE(rc))5507 return rc;5508 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;5509 break;5510 5511 /*5512 * HC Far5513 */5514 case DBGCVAR_TYPE_HC_FAR:5515 switch (pArg2->enmType)5516 {5517 case DBGCVAR_TYPE_NUMBER:5518 *pResult = *pArg1;5519 pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;5520 break;5521 5522 default:5523 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5524 if (VBOX_FAILURE(rc))5525 return rc;5526 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5527 if (VBOX_FAILURE(rc))5528 return rc;5529 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5530 if (VBOX_FAILURE(rc))5531 return rc;5532 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;5533 break;5534 }5535 break;5536 5537 /*5538 * HC Phys5539 */5540 case DBGCVAR_TYPE_HC_PHYS:5541 *pResult = *pArg1;5542 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);5543 if (VBOX_FAILURE(rc))5544 return rc;5545 pResult->u.HCPhys += Var.u.HCPhys;5546 break;5547 5548 /*5549 * Numbers (see start of function)5550 */5551 case DBGCVAR_TYPE_NUMBER:5552 *pResult = *pArg1;5553 switch (pArg2->enmType)5554 {5555 case DBGCVAR_TYPE_SYMBOL:5556 case DBGCVAR_TYPE_STRING:5557 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);5558 if (VBOX_FAILURE(rc))5559 return rc;5560 case DBGCVAR_TYPE_NUMBER:5561 pResult->u.u64Number += pArg2->u.u64Number;5562 break;5563 default:5564 return VERR_PARSE_INVALID_OPERATION;5565 }5566 break;5567 5568 default:5569 return VERR_PARSE_INVALID_OPERATION;5570 5571 }5572 return 0;5573 }5574 5575 5576 /**5577 * Subtration operator (binary).5578 *5579 * @returns 0 on success.5580 * @returns VBox evaluation / parsing error code on failure.5581 * The caller does the bitching.5582 * @param pDbgc Debugger console instance data.5583 * @param pArg1 The first argument.5584 * @param pArg2 The 2nd argument.5585 * @param pResult Where to store the result.5586 */5587 static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5588 {5589 // LogFlow(("dbgcOpSub\n"));5590 5591 /*5592 * An subtraction operation will return the left side type in the expression.5593 * However, if the left hand side is a number and the right hand a pointer of5594 * some kind we'll convert the left hand side to the same type as the right hand.5595 * Any strings will be attempted resolved as symbols.5596 */5597 DBGCVAR Sym1, Sym2;5598 if ( pArg2->enmType == DBGCVAR_TYPE_STRING5599 && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER5600 || pArg1->enmType == DBGCVAR_TYPE_STRING))5601 {5602 int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);5603 if (VBOX_FAILURE(rc))5604 return rc;5605 pArg2 = &Sym2;5606 }5607 5608 if (pArg1->enmType == DBGCVAR_TYPE_STRING)5609 {5610 DBGCVARTYPE enmType;5611 switch (pArg2->enmType)5612 {5613 case DBGCVAR_TYPE_NUMBER:5614 enmType = DBGCVAR_TYPE_ANY;5615 break;5616 case DBGCVAR_TYPE_GC_FLAT:5617 case DBGCVAR_TYPE_GC_PHYS:5618 case DBGCVAR_TYPE_HC_FLAT:5619 case DBGCVAR_TYPE_HC_PHYS:5620 enmType = pArg2->enmType;5621 break;5622 case DBGCVAR_TYPE_GC_FAR:5623 enmType = DBGCVAR_TYPE_GC_FLAT;5624 break;5625 case DBGCVAR_TYPE_HC_FAR:5626 enmType = DBGCVAR_TYPE_HC_FLAT;5627 break;5628 5629 default:5630 case DBGCVAR_TYPE_STRING:5631 AssertMsgFailed(("Can't happen\n"));5632 enmType = DBGCVAR_TYPE_STRING;5633 break;5634 }5635 if (enmType != DBGCVAR_TYPE_STRING)5636 {5637 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);5638 if (VBOX_FAILURE(rc))5639 return rc;5640 pArg1 = &Sym1;5641 }5642 }5643 else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)5644 {5645 PFNDBGCOPUNARY pOp = NULL;5646 switch (pArg2->enmType)5647 {5648 case DBGCVAR_TYPE_GC_FAR:5649 case DBGCVAR_TYPE_GC_FLAT:5650 pOp = dbgcOpAddrFlat;5651 break;5652 case DBGCVAR_TYPE_GC_PHYS:5653 pOp = dbgcOpAddrPhys;5654 break;5655 case DBGCVAR_TYPE_HC_FAR:5656 case DBGCVAR_TYPE_HC_FLAT:5657 pOp = dbgcOpAddrHost;5658 break;5659 case DBGCVAR_TYPE_HC_PHYS:5660 pOp = dbgcOpAddrHostPhys;5661 break;5662 case DBGCVAR_TYPE_NUMBER:5663 break;5664 default:5665 case DBGCVAR_TYPE_STRING:5666 AssertMsgFailed(("Can't happen\n"));5667 break;5668 }5669 if (pOp)5670 {5671 int rc = pOp(pDbgc, pArg1, &Sym1);5672 if (VBOX_FAILURE(rc))5673 return rc;5674 pArg1 = &Sym1;5675 }5676 }5677 5678 5679 /*5680 * Normal processing.5681 */5682 int rc;5683 DBGCVAR Var;5684 DBGCVAR Var2;5685 switch (pArg1->enmType)5686 {5687 /*5688 * GC Flat5689 */5690 case DBGCVAR_TYPE_GC_FLAT:5691 switch (pArg2->enmType)5692 {5693 case DBGCVAR_TYPE_HC_FLAT:5694 case DBGCVAR_TYPE_HC_FAR:5695 case DBGCVAR_TYPE_HC_PHYS:5696 return VERR_PARSE_INVALID_OPERATION;5697 default:5698 *pResult = *pArg1;5699 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5700 if (VBOX_FAILURE(rc))5701 return rc;5702 pResult->u.GCFlat -= pArg2->u.GCFlat;5703 break;5704 }5705 break;5706 5707 /*5708 * GC Far5709 */5710 case DBGCVAR_TYPE_GC_FAR:5711 switch (pArg2->enmType)5712 {5713 case DBGCVAR_TYPE_HC_FLAT:5714 case DBGCVAR_TYPE_HC_FAR:5715 case DBGCVAR_TYPE_HC_PHYS:5716 return VERR_PARSE_INVALID_OPERATION;5717 case DBGCVAR_TYPE_NUMBER:5718 *pResult = *pArg1;5719 pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;5720 break;5721 default:5722 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5723 if (VBOX_FAILURE(rc))5724 return rc;5725 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);5726 if (VBOX_FAILURE(rc))5727 return rc;5728 pResult->u.GCFlat -= pArg2->u.GCFlat;5729 break;5730 }5731 break;5732 5733 /*5734 * GC Phys5735 */5736 case DBGCVAR_TYPE_GC_PHYS:5737 switch (pArg2->enmType)5738 {5739 case DBGCVAR_TYPE_HC_FLAT:5740 case DBGCVAR_TYPE_HC_FAR:5741 case DBGCVAR_TYPE_HC_PHYS:5742 return VERR_PARSE_INVALID_OPERATION;5743 default:5744 *pResult = *pArg1;5745 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);5746 if (VBOX_FAILURE(rc))5747 return rc;5748 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)5749 return VERR_PARSE_INVALID_OPERATION;5750 pResult->u.GCPhys -= Var.u.GCPhys;5751 break;5752 }5753 break;5754 5755 /*5756 * HC Flat5757 */5758 case DBGCVAR_TYPE_HC_FLAT:5759 *pResult = *pArg1;5760 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5761 if (VBOX_FAILURE(rc))5762 return rc;5763 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5764 if (VBOX_FAILURE(rc))5765 return rc;5766 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;5767 break;5768 5769 /*5770 * HC Far5771 */5772 case DBGCVAR_TYPE_HC_FAR:5773 switch (pArg2->enmType)5774 {5775 case DBGCVAR_TYPE_NUMBER:5776 *pResult = *pArg1;5777 pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;5778 break;5779 5780 default:5781 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);5782 if (VBOX_FAILURE(rc))5783 return rc;5784 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);5785 if (VBOX_FAILURE(rc))5786 return rc;5787 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);5788 if (VBOX_FAILURE(rc))5789 return rc;5790 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;5791 break;5792 }5793 break;5794 5795 /*5796 * HC Phys5797 */5798 case DBGCVAR_TYPE_HC_PHYS:5799 *pResult = *pArg1;5800 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);5801 if (VBOX_FAILURE(rc))5802 return rc;5803 pResult->u.HCPhys -= Var.u.HCPhys;5804 break;5805 5806 /*5807 * Numbers (see start of function)5808 */5809 case DBGCVAR_TYPE_NUMBER:5810 *pResult = *pArg1;5811 switch (pArg2->enmType)5812 {5813 case DBGCVAR_TYPE_SYMBOL:5814 case DBGCVAR_TYPE_STRING:5815 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);5816 if (VBOX_FAILURE(rc))5817 return rc;5818 case DBGCVAR_TYPE_NUMBER:5819 pResult->u.u64Number -= pArg2->u.u64Number;5820 break;5821 default:5822 return VERR_PARSE_INVALID_OPERATION;5823 }5824 break;5825 5826 default:5827 return VERR_PARSE_INVALID_OPERATION;5828 5829 }5830 return 0;5831 }5832 5833 5834 /**5835 * Bitwise shift left operator (binary).5836 *5837 * @returns 0 on success.5838 * @returns VBox evaluation / parsing error code on failure.5839 * The caller does the bitching.5840 * @param pDbgc Debugger console instance data.5841 * @param pArg1 The first argument.5842 * @param pArg2 The 2nd argument.5843 * @param pResult Where to store the result.5844 */5845 static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5846 {5847 LogFlow(("dbgcOpBitwiseShiftLeft\n"));5848 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5849 return -1;5850 }5851 5852 5853 /**5854 * Bitwise shift right operator (binary).5855 *5856 * @returns 0 on success.5857 * @returns VBox evaluation / parsing error code on failure.5858 * The caller does the bitching.5859 * @param pDbgc Debugger console instance data.5860 * @param pArg1 The first argument.5861 * @param pArg2 The 2nd argument.5862 * @param pResult Where to store the result.5863 */5864 static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5865 {5866 LogFlow(("dbgcOpBitwiseShiftRight\n"));5867 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5868 return -1;5869 }5870 5871 5872 /**5873 * Bitwise and operator (binary).5874 *5875 * @returns 0 on success.5876 * @returns VBox evaluation / parsing error code on failure.5877 * The caller does the bitching.5878 * @param pDbgc Debugger console instance data.5879 * @param pArg1 The first argument.5880 * @param pArg2 The 2nd argument.5881 * @param pResult Where to store the result.5882 */5883 static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5884 {5885 LogFlow(("dbgcOpBitwiseAnd\n"));5886 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5887 return -1;5888 }5889 5890 5891 /**5892 * Bitwise exclusive or operator (binary).5893 *5894 * @returns 0 on success.5895 * @returns VBox evaluation / parsing error code on failure.5896 * The caller does the bitching.5897 * @param pDbgc Debugger console instance data.5898 * @param pArg1 The first argument.5899 * @param pArg2 The 2nd argument.5900 * @param pResult Where to store the result.5901 */5902 static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5903 {5904 LogFlow(("dbgcOpBitwiseXor\n"));5905 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5906 return -1;5907 }5908 5909 5910 /**5911 * Bitwise inclusive or operator (binary).5912 *5913 * @returns 0 on success.5914 * @returns VBox evaluation / parsing error code on failure.5915 * The caller does the bitching.5916 * @param pDbgc Debugger console instance data.5917 * @param pArg1 The first argument.5918 * @param pArg2 The 2nd argument.5919 * @param pResult Where to store the result.5920 */5921 static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5922 {5923 LogFlow(("dbgcOpBitwiseOr\n"));5924 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5925 return -1;5926 }5927 5928 5929 /**5930 * Boolean and operator (binary).5931 *5932 * @returns 0 on success.5933 * @returns VBox evaluation / parsing error code on failure.5934 * The caller does the bitching.5935 * @param pDbgc Debugger console instance data.5936 * @param pArg1 The first argument.5937 * @param pArg2 The 2nd argument.5938 * @param pResult Where to store the result.5939 */5940 static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5941 {5942 LogFlow(("dbgcOpBooleanAnd\n"));5943 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5944 return -1;5945 }5946 5947 5948 /**5949 * Boolean or operator (binary).5950 *5951 * @returns 0 on success.5952 * @returns VBox evaluation / parsing error code on failure.5953 * The caller does the bitching.5954 * @param pDbgc Debugger console instance data.5955 * @param pArg1 The first argument.5956 * @param pArg2 The 2nd argument.5957 * @param pResult Where to store the result.5958 */5959 static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5960 {5961 LogFlow(("dbgcOpBooleanOr\n"));5962 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);5963 return -1;5964 }5965 5966 5967 /**5968 * Range to operator (binary).5969 *5970 * @returns 0 on success.5971 * @returns VBox evaluation / parsing error code on failure.5972 * The caller does the bitching.5973 * @param pDbgc Debugger console instance data.5974 * @param pArg1 The first argument.5975 * @param pArg2 The 2nd argument.5976 * @param pResult Where to store the result.5977 */5978 static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)5979 {5980 // LogFlow(("dbgcOpRangeLength\n"));5981 /*5982 * Make result. Strings needs to be resolved into symbols.5983 */5984 if (pArg1->enmType == DBGCVAR_TYPE_STRING)5985 {5986 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);5987 if (VBOX_FAILURE(rc))5988 return rc;5989 }5990 else5991 *pResult = *pArg1;5992 5993 /*5994 * Convert 2nd argument to element count.5995 */5996 pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;5997 switch (pArg2->enmType)5998 {5999 case DBGCVAR_TYPE_NUMBER:6000 pResult->u64Range = pArg2->u.u64Number;6001 break;6002 6003 case DBGCVAR_TYPE_STRING:6004 {6005 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);6006 if (VBOX_FAILURE(rc))6007 return rc;6008 pResult->u64Range = pArg2->u.u64Number;6009 break;6010 }6011 6012 default:6013 return VERR_PARSE_INVALID_OPERATION;6014 }6015 6016 return VINF_SUCCESS;6017 }6018 6019 6020 /**6021 * Range to operator (binary).6022 *6023 * @returns 0 on success.6024 * @returns VBox evaluation / parsing error code on failure.6025 * The caller does the bitching.6026 * @param pDbgc Debugger console instance data.6027 * @param pArg1 The first argument.6028 * @param pArg2 The 2nd argument.6029 * @param pResult Where to store the result.6030 */6031 static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6032 {6033 // LogFlow(("dbgcOpRangeLengthBytes\n"));6034 int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);6035 if (VBOX_SUCCESS(rc))6036 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;6037 return rc;6038 }6039 6040 6041 /**6042 * Range to operator (binary).6043 *6044 * @returns 0 on success.6045 * @returns VBox evaluation / parsing error code on failure.6046 * The caller does the bitching.6047 * @param pDbgc Debugger console instance data.6048 * @param pArg1 The first argument.6049 * @param pArg2 The 2nd argument.6050 * @param pResult Where to store the result.6051 */6052 static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)6053 {6054 // LogFlow(("dbgcOpRangeTo\n"));6055 /*6056 * Calc number of bytes between the two args.6057 */6058 DBGCVAR Diff;6059 int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);6060 if (VBOX_FAILURE(rc))6061 return rc;6062 6063 /*6064 * Use the diff as the range of Arg1.6065 */6066 *pResult = *pArg1;6067 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;6068 switch (Diff.enmType)6069 {6070 case DBGCVAR_TYPE_GC_FLAT:6071 pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;6072 break;6073 case DBGCVAR_TYPE_GC_PHYS:6074 pResult->u64Range = Diff.u.GCPhys;6075 break;6076 case DBGCVAR_TYPE_HC_FLAT:6077 pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;6078 break;6079 case DBGCVAR_TYPE_HC_PHYS:6080 pResult->u64Range = Diff.u.HCPhys;6081 break;6082 case DBGCVAR_TYPE_NUMBER:6083 pResult->u64Range = Diff.u.u64Number;6084 break;6085 6086 case DBGCVAR_TYPE_GC_FAR:6087 case DBGCVAR_TYPE_STRING:6088 case DBGCVAR_TYPE_HC_FAR:6089 default:6090 AssertMsgFailed(("Impossible!\n"));6091 return VERR_PARSE_INVALID_OPERATION;6092 }6093 6094 return 0;6095 }6096 6097 6098 6099 6100 6101 /**6102 * Output callback.6103 *6104 * @returns number of bytes written.6105 * @param pvArg User argument.6106 * @param pachChars Pointer to an array of utf-8 characters.6107 * @param cbChars Number of bytes in the character array pointed to by pachChars.6108 */6109 static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)6110 {6111 PDBGC pDbgc = (PDBGC)pvArg;6112 if (cbChars)6113 {6114 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);6115 if (VBOX_FAILURE(rc))6116 {6117 pDbgc->rcOutput = rc;6118 cbChars = 0;6119 }6120 }6121 6122 return cbChars;6123 }6124 6125 6126 6127 6128 6129 6130 6131 6132 6133 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6134 //6135 //6136 // C a l l b a c k H e l p e r s6137 //6138 //6139 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6140 6141 6142 6143 /**6144 * Command helper for writing text to the debug console.6145 *6146 * @returns VBox status.6147 * @param pCmdHlp Pointer to the command callback structure.6148 * @param pvBuf What to write.6149 * @param cbBuf Number of bytes to write.6150 * @param pcbWritten Where to store the number of bytes actually written.6151 * If NULL the entire buffer must be successfully written.6152 */6153 static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)6154 {6155 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6156 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);6157 }6158 6159 6160 /**6161 * Command helper for writing formatted text to the debug console.6162 *6163 * @returns VBox status.6164 * @param pCmdHlp Pointer to the command callback structure.6165 * @param pcb Where to store the number of bytes written.6166 * @param pszFormat The format string.6167 * This is using the log formatter, so it's format extensions can be used.6168 * @param ... Arguments specified in the format string.6169 */6170 static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)6171 {6172 /*6173 * Do the formatting and output.6174 */6175 va_list args;6176 va_start(args, pszFormat);6177 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);6178 va_end(args);6179 6180 return rc;6181 }6182 6183 /**6184 * Callback to format non-standard format specifiers.6185 *6186 * @returns The number of bytes formatted.6187 * @param pvArg Formatter argument.6188 * @param pfnOutput Pointer to output function.6189 * @param pvArgOutput Argument for the output function.6190 * @param ppszFormat Pointer to the format string pointer. Advance this till the char6191 * after the format specifier.6192 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.6193 * @param cchWidth Format Width. -1 if not specified.6194 * @param cchPrecision Format Precision. -1 if not specified.6195 * @param fFlags Flags (RTSTR_NTFS_*).6196 * @param chArgSize The argument size specifier, 'l' or 'L'.6197 */6198 static DECLCALLBACK(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,6199 const char **ppszFormat, va_list *pArgs, int cchWidth,6200 int cchPrecision, unsigned fFlags, char chArgSize)6201 {6202 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);6203 if (**ppszFormat != 'D')6204 {6205 (*ppszFormat)++;6206 return 0;6207 }6208 6209 (*ppszFormat)++;6210 switch (**ppszFormat)6211 {6212 /*6213 * Print variable without range.6214 * The argument is a const pointer to the variable.6215 */6216 case 'V':6217 {6218 (*ppszFormat)++;6219 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);6220 switch (pVar->enmType)6221 {6222 case DBGCVAR_TYPE_GC_FLAT:6223 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);6224 case DBGCVAR_TYPE_GC_FAR:6225 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);6226 case DBGCVAR_TYPE_GC_PHYS:6227 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);6228 case DBGCVAR_TYPE_HC_FLAT:6229 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);6230 case DBGCVAR_TYPE_HC_FAR:6231 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);6232 case DBGCVAR_TYPE_HC_PHYS:6233 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);6234 case DBGCVAR_TYPE_STRING:6235 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);6236 case DBGCVAR_TYPE_NUMBER:6237 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);6238 6239 case DBGCVAR_TYPE_UNKNOWN:6240 default:6241 return pfnOutput(pvArgOutput, "??", 2);6242 }6243 }6244 6245 /*6246 * Print variable with range.6247 * The argument is a const pointer to the variable.6248 */6249 case 'v':6250 {6251 (*ppszFormat)++;6252 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);6253 6254 char szRange[32];6255 switch (pVar->enmRangeType)6256 {6257 case DBGCVAR_RANGE_NONE:6258 szRange[0] = '\0';6259 break;6260 case DBGCVAR_RANGE_ELEMENTS:6261 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);6262 break;6263 case DBGCVAR_RANGE_BYTES:6264 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);6265 break;6266 }6267 6268 switch (pVar->enmType)6269 {6270 case DBGCVAR_TYPE_GC_FLAT:6271 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);6272 case DBGCVAR_TYPE_GC_FAR:6273 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);6274 case DBGCVAR_TYPE_GC_PHYS:6275 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);6276 case DBGCVAR_TYPE_HC_FLAT:6277 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);6278 case DBGCVAR_TYPE_HC_FAR:6279 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);6280 case DBGCVAR_TYPE_HC_PHYS:6281 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);6282 case DBGCVAR_TYPE_STRING:6283 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);6284 case DBGCVAR_TYPE_NUMBER:6285 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);6286 6287 case DBGCVAR_TYPE_UNKNOWN:6288 default:6289 return pfnOutput(pvArgOutput, "??", 2);6290 }6291 }6292 6293 default:6294 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));6295 return 0;6296 }6297 }6298 6299 6300 /**6301 * Command helper for writing formatted text to the debug console.6302 *6303 * @returns VBox status.6304 * @param pCmdHlp Pointer to the command callback structure.6305 * @param pcb Where to store the number of bytes written.6306 * @param pszFormat The format string.6307 * This is using the log formatter, so it's format extensions can be used.6308 * @param args Arguments specified in the format string.6309 */6310 static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)6311 {6312 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6313 6314 /*6315 * Do the formatting and output.6316 */6317 pDbgc->rcOutput = 0;6318 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);6319 6320 if (pcbWritten)6321 *pcbWritten = cb;6322 6323 return pDbgc->rcOutput;6324 }6325 6326 6327 /**6328 * Reports an error from a DBGF call.6329 *6330 * @returns VBox status code appropriate to return from a command.6331 * @param pCmdHlp Pointer to command helpers.6332 * @param rc The VBox status code returned by a DBGF call.6333 * @param pszFormat Format string for additional messages. Can be NULL.6334 * @param ... Format arguments, optional.6335 */6336 static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)6337 {6338 switch (rc)6339 {6340 case VINF_SUCCESS:6341 break;6342 6343 default:6344 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");6345 if (VBOX_SUCCESS(rc) && pszFormat)6346 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);6347 break;6348 }6349 return rc;6350 }6351 6352 6353 /**6354 * Reports an error from a DBGF call.6355 *6356 * @returns VBox status code appropriate to return from a command.6357 * @param pCmdHlp Pointer to command helpers.6358 * @param rc The VBox status code returned by a DBGF call.6359 * @param pszFormat Format string for additional messages. Can be NULL.6360 * @param ... Format arguments, optional.6361 */6362 static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)6363 {6364 va_list args;6365 va_start(args, pszFormat);6366 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);6367 va_end(args);6368 return rcRet;6369 }6370 6371 6372 /**6373 * Command helper for reading memory specified by a DBGC variable.6374 *6375 * @returns VBox status code appropriate to return from a command.6376 * @param pCmdHlp Pointer to the command callback structure.6377 * @param pVM VM handle if GC or physical HC address.6378 * @param pvBuffer Where to store the read data.6379 * @param cbRead Number of bytes to read.6380 * @param pVarPointer DBGC variable specifying where to start reading.6381 * @param pcbRead Where to store the number of bytes actually read.6382 * This optional, but it's useful when read GC virtual memory where a6383 * page in the requested range might not be present.6384 * If not specified not-present failure or end of a HC physical page6385 * will cause failure.6386 */6387 static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)6388 {6389 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6390 6391 /*6392 * Dummy check.6393 */6394 if (cbRead == 0)6395 {6396 if (*pcbRead)6397 *pcbRead = 0;6398 return VINF_SUCCESS;6399 }6400 6401 /*6402 * Convert Far addresses getting size and the correct base address.6403 * Getting and checking the size is what makes this messy and slow.6404 */6405 DBGCVAR Var = *pVarPointer;6406 switch (pVarPointer->enmType)6407 {6408 case DBGCVAR_TYPE_GC_FAR:6409 {6410 /* Use DBGFR3AddrFromSelOff for the conversion. */6411 Assert(pDbgc->pVM);6412 DBGFADDRESS Address;6413 int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);6414 if (VBOX_FAILURE(rc))6415 return rc;6416 6417 /* don't bother with flat selectors (for now). */6418 if (!DBGFADDRESS_IS_FLAT(&Address))6419 {6420 SELMSELINFO SelInfo;6421 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);6422 if (VBOX_SUCCESS(rc))6423 {6424 RTGCUINTPTR cb; /* -1 byte */6425 if (SELMSelInfoIsExpandDown(&SelInfo))6426 {6427 if ( !SelInfo.Raw.Gen.u1Granularity6428 && Address.off > UINT16_C(0xffff))6429 return VERR_OUT_OF_SELECTOR_BOUNDS;6430 if (Address.off <= SelInfo.cbLimit)6431 return VERR_OUT_OF_SELECTOR_BOUNDS;6432 cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;6433 }6434 else6435 {6436 if (Address.off > SelInfo.cbLimit)6437 return VERR_OUT_OF_SELECTOR_BOUNDS;6438 cb = SelInfo.cbLimit - Address.off;6439 }6440 if (cbRead - 1 > cb)6441 {6442 if (!pcbRead)6443 return VERR_OUT_OF_SELECTOR_BOUNDS;6444 cbRead = cb + 1;6445 }6446 }6447 6448 Var.enmType = DBGCVAR_TYPE_GC_FLAT;6449 Var.u.GCFlat = Address.FlatPtr;6450 }6451 break;6452 }6453 6454 case DBGCVAR_TYPE_GC_FLAT:6455 case DBGCVAR_TYPE_GC_PHYS:6456 case DBGCVAR_TYPE_HC_FLAT:6457 case DBGCVAR_TYPE_HC_PHYS:6458 break;6459 6460 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */6461 default:6462 return VERR_NOT_IMPLEMENTED;6463 }6464 6465 6466 6467 /*6468 * Copy page by page.6469 */6470 size_t cbLeft = cbRead;6471 for (;;)6472 {6473 /*6474 * Calc read size.6475 */6476 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);6477 switch (pVarPointer->enmType)6478 {6479 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;6480 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;6481 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;6482 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! */6483 default: break;6484 }6485 6486 /*6487 * Perform read.6488 */6489 int rc;6490 switch (Var.enmType)6491 {6492 case DBGCVAR_TYPE_GC_FLAT:6493 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);6494 break;6495 case DBGCVAR_TYPE_GC_PHYS:6496 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);6497 break;6498 6499 case DBGCVAR_TYPE_HC_PHYS:6500 case DBGCVAR_TYPE_HC_FLAT:6501 case DBGCVAR_TYPE_HC_FAR:6502 {6503 DBGCVAR Var2;6504 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);6505 if (VBOX_SUCCESS(rc))6506 {6507 /** @todo protect this!!! */6508 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);6509 rc = 0;6510 }6511 else6512 rc = VERR_INVALID_POINTER;6513 break;6514 }6515 6516 default:6517 rc = VERR_PARSE_INCORRECT_ARG_TYPE;6518 }6519 6520 /*6521 * Check for failure.6522 */6523 if (VBOX_FAILURE(rc))6524 {6525 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)6526 return VINF_SUCCESS;6527 return rc;6528 }6529 6530 /*6531 * Next.6532 */6533 cbLeft -= cb;6534 if (!cbLeft)6535 break;6536 pvBuffer = (char *)pvBuffer + cb;6537 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);6538 if (VBOX_FAILURE(rc))6539 {6540 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)6541 return VINF_SUCCESS;6542 return rc;6543 }6544 }6545 6546 /*6547 * Done6548 */6549 if (pcbRead)6550 *pcbRead = cbRead;6551 return 0;6552 }6553 6554 /**6555 * Command helper for writing memory specified by a DBGC variable.6556 *6557 * @returns VBox status code appropriate to return from a command.6558 * @param pCmdHlp Pointer to the command callback structure.6559 * @param pVM VM handle if GC or physical HC address.6560 * @param pvBuffer What to write.6561 * @param cbWrite Number of bytes to write.6562 * @param pVarPointer DBGC variable specifying where to start reading.6563 * @param pcbWritten Where to store the number of bytes written.6564 * This is optional. If NULL be aware that some of the buffer6565 * might have been written to the specified address.6566 */6567 static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)6568 {6569 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);6570 return VERR_NOT_IMPLEMENTED;6571 }6572 6573 6574 /**6575 * Evaluates an expression.6576 * (Hopefully the parser and functions are fully reentrant.)6577 *6578 * @returns VBox status code appropriate to return from a command.6579 * @param pCmdHlp Pointer to the command callback structure.6580 * @param pResult Where to store the result.6581 * @param pszExpr The expression. Format string with the format DBGC extensions.6582 * @param ... Format arguments.6583 */6584 static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)6585 {6586 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6587 6588 /*6589 * Format the expression.6590 */6591 char szExprFormatted[2048];6592 va_list args;6593 va_start(args, pszExpr);6594 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);6595 va_end(args);6596 /* ignore overflows. */6597 6598 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);6599 }6600 6601 6602 /**6603 * Executes one command expression.6604 * (Hopefully the parser and functions are fully reentrant.)6605 *6606 * @returns VBox status code appropriate to return from a command.6607 * @param pCmdHlp Pointer to the command callback structure.6608 * @param pszExpr The expression. Format string with the format DBGC extensions.6609 * @param ... Format arguments.6610 */6611 static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)6612 {6613 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6614 /* Save the scratch state. */6615 char *pszScratch = pDbgc->pszScratch;6616 unsigned iArg = pDbgc->iArg;6617 6618 /*6619 * Format the expression.6620 */6621 va_list args;6622 va_start(args, pszExpr);6623 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);6624 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);6625 va_end(args);6626 if (cb >= cbScratch)6627 return VERR_BUFFER_OVERFLOW;6628 6629 /*6630 * Execute the command.6631 * We save and restore the arg index and scratch buffer pointer.6632 */6633 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;6634 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);6635 6636 /* Restore the scratch state. */6637 pDbgc->iArg = iArg;6638 pDbgc->pszScratch = pszScratch;6639 6640 return rc;6641 }6642 6643 6644 /**6645 * Converts a DBGC variable to a DBGF address structure.6646 *6647 * @returns VBox status code.6648 * @param pCmdHlp Pointer to the command callback structure.6649 * @param pVar The variable to convert.6650 * @param pAddress The target address.6651 */6652 static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)6653 {6654 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6655 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);6656 }6657 6658 6659 /**6660 * Converts a DBGC variable to a boolean.6661 *6662 * @returns VBox status code.6663 * @param pCmdHlp Pointer to the command callback structure.6664 * @param pVar The variable to convert.6665 * @param pf Where to store the boolean.6666 */6667 static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)6668 {6669 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);6670 NOREF(pDbgc);6671 6672 switch (pVar->enmType)6673 {6674 case DBGCVAR_TYPE_STRING:6675 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */6676 if ( !strcmp(pVar->u.pszString, "true")6677 || !strcmp(pVar->u.pszString, "True")6678 || !strcmp(pVar->u.pszString, "TRUE")6679 || !strcmp(pVar->u.pszString, "on")6680 || !strcmp(pVar->u.pszString, "On")6681 || !strcmp(pVar->u.pszString, "oN")6682 || !strcmp(pVar->u.pszString, "ON")6683 || !strcmp(pVar->u.pszString, "enabled")6684 || !strcmp(pVar->u.pszString, "Enabled")6685 || !strcmp(pVar->u.pszString, "DISABLED"))6686 {6687 *pf = true;6688 return VINF_SUCCESS;6689 }6690 if ( !strcmp(pVar->u.pszString, "false")6691 || !strcmp(pVar->u.pszString, "False")6692 || !strcmp(pVar->u.pszString, "FALSE")6693 || !strcmp(pVar->u.pszString, "off")6694 || !strcmp(pVar->u.pszString, "Off")6695 || !strcmp(pVar->u.pszString, "OFF")6696 || !strcmp(pVar->u.pszString, "disabled")6697 || !strcmp(pVar->u.pszString, "Disabled")6698 || !strcmp(pVar->u.pszString, "DISABLED"))6699 {6700 *pf = false;6701 return VINF_SUCCESS;6702 }6703 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */6704 6705 case DBGCVAR_TYPE_GC_FLAT:6706 case DBGCVAR_TYPE_GC_PHYS:6707 case DBGCVAR_TYPE_HC_FLAT:6708 case DBGCVAR_TYPE_HC_PHYS:6709 case DBGCVAR_TYPE_NUMBER:6710 *pf = pVar->u.u64Number != 0;6711 return VINF_SUCCESS;6712 6713 case DBGCVAR_TYPE_HC_FAR:6714 case DBGCVAR_TYPE_GC_FAR:6715 case DBGCVAR_TYPE_SYMBOL:6716 default:6717 return VERR_PARSE_INCORRECT_ARG_TYPE;6718 }6719 }6720 6721 6722 6723 6724 6725 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6726 //6727 //6728 // V a r i a b l e M a n i p u l a t i o n6729 //6730 //6731 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6732 6733 6734 6735 /** @todo move me!*/6736 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)6737 {6738 if (pVar)6739 {6740 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;6741 pVar->u.GCFlat = GCFlat;6742 pVar->enmRangeType = DBGCVAR_RANGE_NONE;6743 pVar->u64Range = 0;6744 }6745 }6746 6747 6748 /** @todo move me!*/6749 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)6750 {6751 if (pVar)6752 {6753 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;6754 pVar->u.GCFlat = GCFlat;6755 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;6756 pVar->u64Range = cb;6757 }6758 }6759 6760 6761 /** @todo move me!*/6762 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)6763 {6764 if (pVar)6765 {6766 if (pVar2)6767 *pVar = *pVar2;6768 else6769 {6770 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;6771 memset(&pVar->u, 0, sizeof(pVar->u));6772 pVar->enmRangeType = DBGCVAR_RANGE_NONE;6773 pVar->u64Range = 0;6774 }6775 }6776 }6777 6778 6779 /** @todo move me!*/6780 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)6781 {6782 if (pVar)6783 {6784 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;6785 pVar->u64Range = cb;6786 }6787 }6788 6789 6790 /** @todo move me!*/6791 static void dbgcVarSetNoRange(PDBGCVAR pVar)6792 {6793 if (pVar)6794 {6795 pVar->enmRangeType = DBGCVAR_RANGE_NONE;6796 pVar->u64Range = 0;6797 }6798 }6799 6800 6801 /**6802 * Converts a DBGC variable to a DBGF address.6803 *6804 * @returns VBox status code.6805 * @param pDbgc The DBGC instance.6806 * @param pVar The variable.6807 * @param pAddress Where to store the address.6808 */6809 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)6810 {6811 AssertReturn(pVar, VERR_INVALID_PARAMETER);6812 switch (pVar->enmType)6813 {6814 case DBGCVAR_TYPE_GC_FLAT:6815 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);6816 return VINF_SUCCESS;6817 6818 case DBGCVAR_TYPE_NUMBER:6819 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);6820 return VINF_SUCCESS;6821 6822 case DBGCVAR_TYPE_GC_FAR:6823 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);6824 6825 case DBGCVAR_TYPE_STRING:6826 case DBGCVAR_TYPE_SYMBOL:6827 {6828 DBGCVAR Var;6829 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);6830 if (VBOX_FAILURE(rc))6831 return rc;6832 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);6833 }6834 6835 case DBGCVAR_TYPE_GC_PHYS:6836 case DBGCVAR_TYPE_HC_FLAT:6837 case DBGCVAR_TYPE_HC_FAR:6838 case DBGCVAR_TYPE_HC_PHYS:6839 default:6840 return VERR_PARSE_CONVERSION_FAILED;6841 }6842 }6843 6844 6845 6846 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6847 //6848 //6849 // B r e a k p o i n t M a n a g e m e n t6850 //6851 //6852 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//6853 6854 6855 /**6856 * Adds a breakpoint to the DBGC breakpoint list.6857 */6858 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)6859 {6860 /*6861 * Check if it already exists.6862 */6863 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);6864 if (pBp)6865 return VERR_DBGC_BP_EXISTS;6866 6867 /*6868 * Add the breakpoint.6869 */6870 if (pszCmd)6871 pszCmd = RTStrStripL(pszCmd);6872 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;6873 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));6874 if (!pBp)6875 return VERR_NO_MEMORY;6876 if (cchCmd)6877 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);6878 else6879 pBp->szCmd[0] = '\0';6880 pBp->cchCmd = cchCmd;6881 pBp->iBp = iBp;6882 pBp->pNext = pDbgc->pFirstBp;6883 pDbgc->pFirstBp = pBp;6884 6885 return VINF_SUCCESS;6886 }6887 6888 /**6889 * Updates the a breakpoint.6890 *6891 * @returns VBox status code.6892 * @param pDbgc The DBGC instance.6893 * @param iBp The breakpoint to update.6894 * @param pszCmd The new command.6895 */6896 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)6897 {6898 /*6899 * Find the breakpoint.6900 */6901 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);6902 if (!pBp)6903 return VERR_DBGC_BP_NOT_FOUND;6904 6905 /*6906 * Do we need to reallocate?6907 */6908 if (pszCmd)6909 pszCmd = RTStrStripL(pszCmd);6910 if (!pszCmd || !*pszCmd)6911 pBp->szCmd[0] = '\0';6912 else6913 {6914 size_t cchCmd = strlen(pszCmd);6915 if (strlen(pBp->szCmd) >= cchCmd)6916 {6917 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);6918 pBp->cchCmd = cchCmd;6919 }6920 else6921 {6922 /*6923 * Yes, let's do it the simple way...6924 */6925 int rc = dbgcBpDelete(pDbgc, iBp);6926 AssertRC(rc);6927 return dbgcBpAdd(pDbgc, iBp, pszCmd);6928 }6929 }6930 return VINF_SUCCESS;6931 }6932 6933 6934 /**6935 * Deletes a breakpoint.6936 *6937 * @returns VBox status code.6938 * @param pDbgc The DBGC instance.6939 * @param iBp The breakpoint to delete.6940 */6941 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)6942 {6943 /*6944 * Search thru the list, when found unlink and free it.6945 */6946 PDBGCBP pBpPrev = NULL;6947 PDBGCBP pBp = pDbgc->pFirstBp;6948 for (; pBp; pBp = pBp->pNext)6949 {6950 if (pBp->iBp == iBp)6951 {6952 if (pBpPrev)6953 pBpPrev->pNext = pBp->pNext;6954 else6955 pDbgc->pFirstBp = pBp->pNext;6956 RTMemFree(pBp);6957 return VINF_SUCCESS;6958 }6959 pBpPrev = pBp;6960 }6961 6962 return VERR_DBGC_BP_NOT_FOUND;6963 }6964 6965 6966 /**6967 * Get a breakpoint.6968 *6969 * @returns Pointer to the breakpoint.6970 * @returns NULL if the breakpoint wasn't found.6971 * @param pDbgc The DBGC instance.6972 * @param iBp The breakpoint to get.6973 */6974 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)6975 {6976 /*6977 * Enumerate the list.6978 */6979 PDBGCBP pBp = pDbgc->pFirstBp;6980 for (; pBp; pBp = pBp->pNext)6981 if (pBp->iBp == iBp)6982 return pBp;6983 return NULL;6984 }6985 6986 6987 /**6988 * Executes the command of a breakpoint.6989 *6990 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.6991 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.6992 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.6993 * @returns VBox status code from dbgcProcessCommand() other wise.6994 * @param pDbgc The DBGC instance.6995 * @param iBp The breakpoint to execute.6996 */6997 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)6998 {6999 /*7000 * Find the breakpoint.7001 */7002 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);7003 if (!pBp)7004 return VERR_DBGC_BP_NOT_FOUND;7005 7006 /*7007 * Anything to do?7008 */7009 if (!pBp->cchCmd)7010 return VINF_DBGC_BP_NO_COMMAND;7011 7012 /*7013 * Execute the command.7014 * This means copying it to the scratch buffer and process it as if it7015 * were user input. We must save and restore the state of the scratch buffer.7016 */7017 /* Save the scratch state. */7018 char *pszScratch = pDbgc->pszScratch;7019 unsigned iArg = pDbgc->iArg;7020 7021 /* Copy the command to the scratch buffer. */7022 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);7023 if (pBp->cchCmd >= cbScratch)7024 return VERR_BUFFER_OVERFLOW;7025 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);7026 7027 /* Execute the command. */7028 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;7029 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);7030 7031 /* Restore the scratch state. */7032 pDbgc->iArg = iArg;7033 pDbgc->pszScratch = pszScratch;7034 7035 return rc;7036 }7037 7038 7039 7040 7041 7042 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7043 //7044 //7045 // I n p u t , p a r s i n g a n d l o g g i n g7046 //7047 //7048 //\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//7049 7050 7051 7052 /**7053 * Prints any log lines from the log buffer.7054 *7055 * The caller must not call function this unless pDbgc->fLog is set.7056 *7057 * @returns VBox status. (output related)7058 * @param pDbgc Debugger console instance data.7059 */7060 static int dbgcProcessLog(PDBGC pDbgc)7061 {7062 /** @todo */7063 NOREF(pDbgc);7064 return 0;7065 }7066 7067 7068 7069 /**7070 * Handle input buffer overflow.7071 *7072 * Will read any available input looking for a '\n' to reset the buffer on.7073 *7074 * @returns VBox status.7075 * @param pDbgc Debugger console instance data.7076 */7077 static int dbgcInputOverflow(PDBGC pDbgc)7078 {7079 /*7080 * Assert overflow status and reset the input buffer.7081 */7082 if (!pDbgc->fInputOverflow)7083 {7084 pDbgc->fInputOverflow = true;7085 pDbgc->iRead = pDbgc->iWrite = 0;7086 pDbgc->cInputLines = 0;7087 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");7088 }7089 7090 /*7091 * Eat input till no more or there is a '\n'.7092 * When finding a '\n' we'll continue normal processing.7093 */7094 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))7095 {7096 size_t cbRead;7097 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);7098 if (VBOX_FAILURE(rc))7099 return rc;7100 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);7101 if (psz)7102 {7103 pDbgc->fInputOverflow = false;7104 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;7105 pDbgc->iWrite = (unsigned)cbRead;7106 pDbgc->cInputLines = 0;7107 break;7108 }7109 }7110 7111 return 0;7112 }7113 7114 7115 7116 /**7117 * Read input and do some preprocessing.7118 *7119 * @returns VBox status.7120 * In addition to the iWrite and achInput, cInputLines is maintained.7121 * In case of an input overflow the fInputOverflow flag will be set.7122 * @param pDbgc Debugger console instance data.7123 */7124 static int dbgcInputRead(PDBGC pDbgc)7125 {7126 /*7127 * We have ready input.7128 * Read it till we don't have any or we have a full input buffer.7129 */7130 int rc = 0;7131 do7132 {7133 /*7134 * More available buffer space?7135 */7136 size_t cbLeft;7137 if (pDbgc->iWrite > pDbgc->iRead)7138 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);7139 else7140 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;7141 if (!cbLeft)7142 {7143 /* overflow? */7144 if (!pDbgc->cInputLines)7145 rc = dbgcInputOverflow(pDbgc);7146 break;7147 }7148 7149 /*7150 * Read one char and interpret it.7151 */7152 char achRead[128];7153 size_t cbRead;7154 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);7155 if (VBOX_FAILURE(rc))7156 return rc;7157 char *psz = &achRead[0];7158 while (cbRead-- > 0)7159 {7160 char ch = *psz++;7161 switch (ch)7162 {7163 /*7164 * Ignore.7165 */7166 case '\0':7167 case '\r':7168 case '\a':7169 break;7170 7171 /*7172 * Backspace.7173 */7174 case '\b':7175 Log2(("DBGC: backspace\n"));7176 if (pDbgc->iRead != pDbgc->iWrite)7177 {7178 unsigned iWriteUndo = pDbgc->iWrite;7179 if (pDbgc->iWrite)7180 pDbgc->iWrite--;7181 else7182 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;7183 7184 if (pDbgc->achInput[pDbgc->iWrite] == '\n')7185 pDbgc->iWrite = iWriteUndo;7186 }7187 break;7188 7189 /*7190 * Add char to buffer.7191 */7192 case '\t':7193 case '\n':7194 case ';':7195 switch (ch)7196 {7197 case '\t': ch = ' '; break;7198 case '\n': pDbgc->cInputLines++; break;7199 }7200 default:7201 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));7202 pDbgc->achInput[pDbgc->iWrite] = ch;7203 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))7204 pDbgc->iWrite = 0;7205 break;7206 }7207 }7208 7209 /* Terminate it to make it easier to read in the debugger. */7210 pDbgc->achInput[pDbgc->iWrite] = '\0';7211 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));7212 7213 return rc;7214 }7215 7216 7217 /**7218 * Finds a builtin symbol.7219 * @returns Pointer to symbol descriptor on success.7220 * @returns NULL on failure.7221 * @param pDbgc The debug console instance.7222 * @param pszSymbol The symbol name.7223 */7224 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)7225 {7226 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)7227 if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))7228 return &g_aSyms[iSym];7229 7230 /** @todo externally registered symbols. */7231 NOREF(pDbgc);7232 return NULL;7233 }7234 7235 7236 /**7237 * Resolves a symbol (or tries to do so at least).7238 *7239 * @returns 0 on success.7240 * @returns VBox status on failure.7241 * @param pDbgc The debug console instance.7242 * @param pszSymbol The symbol name.7243 * @param enmType The result type.7244 * @param pResult Where to store the result.7245 */7246 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)7247 {7248 /*7249 * Builtin?7250 */7251 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);7252 if (pSymDesc)7253 {7254 if (!pSymDesc->pfnGet)7255 return VERR_PARSE_WRITEONLY_SYMBOL;7256 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);7257 }7258 7259 7260 /*7261 * Ask PDM.7262 */7263 /** @todo resolve symbols using PDM. */7264 7265 7266 /*7267 * Ask the debug info manager.7268 */7269 DBGFSYMBOL Symbol;7270 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);7271 if (VBOX_SUCCESS(rc))7272 {7273 /*7274 * Default return is a flat gc address.7275 */7276 memset(pResult, 0, sizeof(*pResult));7277 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;7278 pResult->u64Range = Symbol.cb;7279 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;7280 pResult->u.GCFlat = Symbol.Value;7281 DBGCVAR VarTmp;7282 switch (enmType)7283 {7284 /* nothing to do. */7285 case DBGCVAR_TYPE_GC_FLAT:7286 case DBGCVAR_TYPE_GC_FAR:7287 case DBGCVAR_TYPE_ANY:7288 return VINF_SUCCESS;7289 7290 /* simply make it numeric. */7291 case DBGCVAR_TYPE_NUMBER:7292 pResult->enmType = DBGCVAR_TYPE_NUMBER;7293 pResult->u.u64Number = Symbol.Value;7294 return VINF_SUCCESS;7295 7296 /* cast it. */7297 7298 case DBGCVAR_TYPE_GC_PHYS:7299 VarTmp = *pResult;7300 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);7301 7302 case DBGCVAR_TYPE_HC_FAR:7303 case DBGCVAR_TYPE_HC_FLAT:7304 VarTmp = *pResult;7305 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);7306 7307 case DBGCVAR_TYPE_HC_PHYS:7308 VarTmp = *pResult;7309 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);7310 7311 default:7312 AssertMsgFailed(("Internal error enmType=%d\n", enmType));7313 return VERR_INVALID_PARAMETER;7314 }7315 }7316 7317 return VERR_PARSE_NOT_IMPLEMENTED;7318 }7319 7320 7321 7322 /**7323 * Finds a routine.7324 *7325 * @returns Pointer to the command descriptor.7326 * If the request was for an external command, the caller is responsible for7327 * unlocking the external command list.7328 * @returns NULL if not found.7329 * @param pDbgc The debug console instance.7330 * @param pachName Pointer to the routine string (not terminated).7331 * @param cchName Length of the routine name.7332 * @param fExternal Whether or not the routine is external.7333 */7334 static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)7335 {7336 if (!fExternal)7337 {7338 /* emulation first, so commands can be overloaded (info ++). */7339 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;7340 unsigned cLeft = pDbgc->cEmulationCmds;7341 while (cLeft-- > 0)7342 {7343 if ( !strncmp(pachName, pCmd->pszCmd, cchName)7344 && !pCmd->pszCmd[cchName])7345 return pCmd;7346 pCmd++;7347 }7348 7349 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)7350 {7351 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)7352 && !g_aCmds[iCmd].pszCmd[cchName])7353 return &g_aCmds[iCmd];7354 }7355 }7356 else7357 {7358 DBGCEXTCMDS_LOCK_RD();7359 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)7360 {7361 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)7362 {7363 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)7364 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])7365 return &pExtCmds->paCmds[iCmd];7366 }7367 }7368 DBGCEXTCMDS_UNLOCK_RD();7369 }7370 7371 NOREF(pDbgc);7372 return NULL;7373 }7374 7375 7376 /**7377 * Searches for an operator descriptor which matches the start of7378 * the expression given us.7379 *7380 * @returns Pointer to the operator on success.7381 * @param pDbgc The debug console instance.7382 * @param pszExpr Pointer to the expression string which might start with an operator.7383 * @param fPreferBinary Whether to favour binary or unary operators.7384 * Caller must assert that it's the disired type! Both types will still7385 * be returned, this is only for resolving duplicates.7386 * @param chPrev The previous char. Some operators requires a blank in front of it.7387 */7388 static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)7389 {7390 PCDBGCOP pOp = NULL;7391 for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)7392 {7393 if ( g_aOps[iOp].szName[0] == pszExpr[0]7394 && (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])7395 && (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))7396 {7397 /*7398 * Check that we don't mistake it for some other operator which have more chars.7399 */7400 unsigned j;7401 for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)7402 if ( g_aOps[j].cchName > g_aOps[iOp].cchName7403 && g_aOps[j].szName[0] == pszExpr[0]7404 && (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])7405 && (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )7406 break;7407 if (j < ELEMENTS(g_aOps))7408 continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */7409 pOp = &g_aOps[iOp];7410 7411 /*7412 * Prefered type?7413 */7414 if (g_aOps[iOp].fBinary == fPreferBinary)7415 break;7416 }7417 }7418 7419 if (pOp)7420 Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));7421 NOREF(pDbgc); NOREF(chPrev);7422 return pOp;7423 }7424 7425 7426 /**7427 * Initalizes g_bmOperatorChars.7428 */7429 static void dbgcInitOpCharBitMap(void)7430 {7431 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));7432 for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)7433 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);7434 }7435 7436 7437 /**7438 * Checks whether the character may be the start of an operator.7439 *7440 * @returns true/false.7441 * @param ch The character.7442 */7443 DECLINLINE(bool) dbgcIsOpChar(char ch)7444 {7445 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);7446 }7447 7448 7449 static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)7450 {7451 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));7452 7453 /*7454 * Removing any quoting and escapings.7455 */7456 char ch = *pszExpr;7457 if (ch == '"' || ch == '\'' || ch == '`')7458 {7459 if (pszExpr[--cchExpr] != ch)7460 return VERR_PARSE_UNBALANCED_QUOTE;7461 cchExpr--;7462 pszExpr++;7463 7464 /** @todo string unescaping. */7465 }7466 pszExpr[cchExpr] = '\0';7467 7468 /*7469 * Make the argument.7470 */7471 pArg->pDesc = NULL;7472 pArg->pNext = NULL;7473 pArg->enmType = DBGCVAR_TYPE_STRING;7474 pArg->u.pszString = pszExpr;7475 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;7476 pArg->u64Range = cchExpr;7477 7478 NOREF(pDbgc);7479 return 0;7480 }7481 7482 7483 static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)7484 {7485 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));7486 /*7487 * Convert to number.7488 */7489 uint64_t u64 = 0;7490 char ch;7491 while ((ch = *pszExpr) != '\0')7492 {7493 uint64_t u64Prev = u64;7494 unsigned u = ch - '0';7495 if (u < 10 && u < uBase)7496 u64 = u64 * uBase + u;7497 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)7498 u64 = u64 * uBase + u;7499 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)7500 u64 = u64 * uBase + u;7501 else7502 return VERR_PARSE_INVALID_NUMBER;7503 7504 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */7505 if (u64Prev != u64 / uBase)7506 return VERR_PARSE_NUMBER_TOO_BIG;7507 7508 /* next */7509 pszExpr++;7510 }7511 7512 /*7513 * Initialize the argument.7514 */7515 pArg->pDesc = NULL;7516 pArg->pNext = NULL;7517 pArg->enmType = DBGCVAR_TYPE_NUMBER;7518 pArg->u.u64Number = u64;7519 pArg->enmRangeType = DBGCVAR_RANGE_NONE;7520 pArg->u64Range = 0;7521 7522 return 0;7523 }7524 7525 7526 /**7527 * Match variable and variable descriptor, promoting the variable if necessary.7528 *7529 * @returns VBox status code.7530 * @param pDbgc Debug console instanace.7531 * @param pVar Variable.7532 * @param pVarDesc Variable descriptor.7533 */7534 static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)7535 {7536 /*7537 * (If match or promoted to match, return, else break.)7538 */7539 switch (pVarDesc->enmCategory)7540 {7541 /*7542 * Anything goes7543 */7544 case DBGCVAR_CAT_ANY:7545 return VINF_SUCCESS;7546 7547 /*7548 * Pointer with and without range.7549 * We can try resolve strings and symbols as symbols and7550 * promote numbers to flat GC pointers.7551 */7552 case DBGCVAR_CAT_POINTER_NO_RANGE:7553 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7554 return VERR_PARSE_NO_RANGE_ALLOWED;7555 /* fallthru */7556 case DBGCVAR_CAT_POINTER:7557 switch (pVar->enmType)7558 {7559 case DBGCVAR_TYPE_GC_FLAT:7560 case DBGCVAR_TYPE_GC_FAR:7561 case DBGCVAR_TYPE_GC_PHYS:7562 case DBGCVAR_TYPE_HC_FLAT:7563 case DBGCVAR_TYPE_HC_FAR:7564 case DBGCVAR_TYPE_HC_PHYS:7565 return VINF_SUCCESS;7566 7567 case DBGCVAR_TYPE_SYMBOL:7568 case DBGCVAR_TYPE_STRING:7569 {7570 DBGCVAR Var;7571 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);7572 if (VBOX_SUCCESS(rc))7573 {7574 /* deal with range */7575 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7576 {7577 Var.enmRangeType = pVar->enmRangeType;7578 Var.u64Range = pVar->u64Range;7579 }7580 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)7581 Var.enmRangeType = DBGCVAR_RANGE_NONE;7582 *pVar = Var;7583 return rc;7584 }7585 break;7586 }7587 7588 case DBGCVAR_TYPE_NUMBER:7589 {7590 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;7591 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7592 pVar->u.GCFlat = GCPtr;7593 return VINF_SUCCESS;7594 }7595 7596 default:7597 break;7598 }7599 break;7600 7601 /*7602 * GC pointer with and without range.7603 * We can try resolve strings and symbols as symbols and7604 * promote numbers to flat GC pointers.7605 */7606 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:7607 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7608 return VERR_PARSE_NO_RANGE_ALLOWED;7609 /* fallthru */7610 case DBGCVAR_CAT_GC_POINTER:7611 switch (pVar->enmType)7612 {7613 case DBGCVAR_TYPE_GC_FLAT:7614 case DBGCVAR_TYPE_GC_FAR:7615 case DBGCVAR_TYPE_GC_PHYS:7616 return VINF_SUCCESS;7617 7618 case DBGCVAR_TYPE_HC_FLAT:7619 case DBGCVAR_TYPE_HC_FAR:7620 case DBGCVAR_TYPE_HC_PHYS:7621 return VERR_PARSE_CONVERSION_FAILED;7622 7623 case DBGCVAR_TYPE_SYMBOL:7624 case DBGCVAR_TYPE_STRING:7625 {7626 DBGCVAR Var;7627 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);7628 if (VBOX_SUCCESS(rc))7629 {7630 /* deal with range */7631 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7632 {7633 Var.enmRangeType = pVar->enmRangeType;7634 Var.u64Range = pVar->u64Range;7635 }7636 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)7637 Var.enmRangeType = DBGCVAR_RANGE_NONE;7638 *pVar = Var;7639 return rc;7640 }7641 break;7642 }7643 7644 case DBGCVAR_TYPE_NUMBER:7645 {7646 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;7647 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;7648 pVar->u.GCFlat = GCPtr;7649 return VINF_SUCCESS;7650 }7651 7652 default:7653 break;7654 }7655 break;7656 7657 /*7658 * Number with or without a range.7659 * Numbers can be resolved from symbols, but we cannot demote a pointer7660 * to a number.7661 */7662 case DBGCVAR_CAT_NUMBER_NO_RANGE:7663 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)7664 return VERR_PARSE_NO_RANGE_ALLOWED;7665 /* fallthru */7666 case DBGCVAR_CAT_NUMBER:7667 switch (pVar->enmType)7668 {7669 case DBGCVAR_TYPE_NUMBER:7670 return VINF_SUCCESS;7671 7672 case DBGCVAR_TYPE_SYMBOL:7673 case DBGCVAR_TYPE_STRING:7674 {7675 DBGCVAR Var;7676 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);7677 if (VBOX_SUCCESS(rc))7678 {7679 *pVar = Var;7680 return rc;7681 }7682 break;7683 }7684 default:7685 break;7686 }7687 break;7688 7689 /*7690 * Strings can easily be made from symbols (and of course strings).7691 * We could consider reformatting the addresses and numbers into strings later...7692 */7693 case DBGCVAR_CAT_STRING:7694 switch (pVar->enmType)7695 {7696 case DBGCVAR_TYPE_SYMBOL:7697 pVar->enmType = DBGCVAR_TYPE_STRING;7698 /* fallthru */7699 case DBGCVAR_TYPE_STRING:7700 return VINF_SUCCESS;7701 default:7702 break;7703 }7704 break;7705 7706 /*7707 * Symol is pretty much the same thing as a string (at least until we actually implement it).7708 */7709 case DBGCVAR_CAT_SYMBOL:7710 switch (pVar->enmType)7711 {7712 case DBGCVAR_TYPE_STRING:7713 pVar->enmType = DBGCVAR_TYPE_SYMBOL;7714 /* fallthru */7715 case DBGCVAR_TYPE_SYMBOL:7716 return VINF_SUCCESS;7717 default:7718 break;7719 }7720 break;7721 7722 /*7723 * Anything else is illegal.7724 */7725 default:7726 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));7727 break;7728 }7729 7730 return VERR_PARSE_NO_ARGUMENT_MATCH;7731 }7732 7733 7734 /**7735 * Matches a set of variables with a description set.7736 *7737 * This is typically used for routine arguments before a call. The effects in7738 * addition to the validation, is that some variables might be propagated to7739 * other types in order to match the description. The following transformations7740 * are supported:7741 * - String reinterpreted as a symbol and resolved to a number or pointer.7742 * - Number to a pointer.7743 * - Pointer to a number.7744 * @returns 0 on success with paVars.7745 * @returns VBox error code for match errors.7746 */7747 static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,7748 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,7749 PDBGCVAR paVars, unsigned cVars)7750 {7751 /*7752 * Just do basic min / max checks first.7753 */7754 if (cVars < cVarsMin)7755 return VERR_PARSE_TOO_FEW_ARGUMENTS;7756 if (cVars > cVarsMax)7757 return VERR_PARSE_TOO_MANY_ARGUMENTS;7758 7759 /*7760 * Match the descriptors and actual variables.7761 */7762 PCDBGCVARDESC pPrevDesc = NULL;7763 unsigned cCurDesc = 0;7764 unsigned iVar = 0;7765 unsigned iVarDesc = 0;7766 while (iVar < cVars)7767 {7768 /* walk the descriptors */7769 if (iVarDesc >= cVarDescs)7770 return VERR_PARSE_TOO_MANY_ARGUMENTS;7771 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV7772 && &paVarDescs[iVarDesc - 1] != pPrevDesc)7773 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)7774 {7775 iVarDesc++;7776 if (iVarDesc >= cVarDescs)7777 return VERR_PARSE_TOO_MANY_ARGUMENTS;7778 cCurDesc = 0;7779 }7780 7781 /*7782 * Skip thru optional arguments until we find something which matches7783 * or can easily be promoted to what the descriptor want.7784 */7785 for (;;)7786 {7787 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);7788 if (VBOX_SUCCESS(rc))7789 {7790 paVars[iVar].pDesc = &paVarDescs[iVarDesc];7791 cCurDesc++;7792 break;7793 }7794 7795 /* can we advance? */7796 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)7797 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;7798 if (++iVarDesc >= cVarDescs)7799 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;7800 cCurDesc = 0;7801 }7802 7803 /* next var */7804 iVar++;7805 }7806 7807 /*7808 * Check that the rest of the descriptors are optional.7809 */7810 while (iVarDesc < cVarDescs)7811 {7812 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)7813 return VERR_PARSE_TOO_FEW_ARGUMENTS;7814 cCurDesc = 0;7815 7816 /* next */7817 iVarDesc++;7818 }7819 7820 return 0;7821 }7822 7823 7824 /**7825 * Evaluates one argument with respect to unary operators.7826 *7827 * @returns 0 on success. pResult contains the result.7828 * @returns VBox error code on parse or other evaluation error.7829 *7830 * @param pDbgc Debugger console instance data.7831 * @param pszExpr The expression string.7832 * @param pResult Where to store the result of the expression evaluation.7833 */7834 static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)7835 {7836 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));7837 7838 /*7839 * The state of the expression is now such that it will start by zero or more7840 * unary operators and being followed by an expression of some kind.7841 * The expression is either plain or in parenthesis.7842 *7843 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)7844 * ASSUME: unary operators are all of equal precedence.7845 */7846 int rc = 0;7847 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');7848 if (pOp)7849 {7850 /* binary operators means syntax error. */7851 if (pOp->fBinary)7852 return VERR_PARSE_UNEXPECTED_OPERATOR;7853 7854 /*7855 * If the next expression (the one following the unary operator) is in a7856 * parenthesis a full eval is needed. If not the unary eval will suffice.7857 */7858 /* calc and strip next expr. */7859 char *pszExpr2 = pszExpr + pOp->cchName;7860 while (isblank(*pszExpr2))7861 pszExpr2++;7862 7863 if (!*pszExpr2)7864 rc = VERR_PARSE_EMPTY_ARGUMENT;7865 else7866 {7867 DBGCVAR Arg;7868 if (*pszExpr2 == '(')7869 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);7870 else7871 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);7872 if (VBOX_SUCCESS(rc))7873 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);7874 }7875 }7876 else7877 {7878 /*7879 * Didn't find any operators, so it we have to check if this can be an7880 * function call before assuming numeric or string expression.7881 *7882 * (ASSUMPTIONS:)7883 * A function name only contains alphanumerical chars and it can not start7884 * with a numerical character.7885 * Immediately following the name is a parenthesis which must over7886 * the remaining part of the expression.7887 */7888 bool fExternal = *pszExpr == '.';7889 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;7890 char *pszFunEnd = NULL;7891 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))7892 {7893 pszFunEnd = pszExpr + 1;7894 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))7895 pszFunEnd++;7896 if (*pszFunEnd != '(')7897 pszFunEnd = NULL;7898 }7899 7900 if (pszFunEnd)7901 {7902 /*7903 * Ok, it's a function call.7904 */7905 if (fExternal)7906 pszExpr++, cchExpr--;7907 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);7908 if (!pFun)7909 return VERR_PARSE_FUNCTION_NOT_FOUND;7910 if (!pFun->pResultDesc)7911 return VERR_PARSE_NOT_A_FUNCTION;7912 7913 /*7914 * Parse the expression in parenthesis.7915 */7916 cchExpr -= pszFunEnd - pszExpr;7917 pszExpr = pszFunEnd;7918 /** @todo implement multiple arguments. */7919 DBGCVAR Arg;7920 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);7921 if (!rc)7922 {7923 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);7924 if (!rc)7925 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);7926 }7927 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)7928 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);7929 }7930 else7931 {7932 /*7933 * Didn't find any operators, so it must be a plain expression.7934 * This might be numeric or a string expression.7935 */7936 char ch = pszExpr[0];7937 char ch2 = pszExpr[1];7938 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))7939 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);7940 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))7941 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);7942 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))7943 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);7944 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.7945 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))7946 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);7947 else7948 {7949 /*7950 * Hexadecimal number or a string?7951 */7952 char *psz = pszExpr;7953 while (isxdigit(*psz))7954 psz++;7955 if (!*psz)7956 rc = dbgcEvalSubNum(pszExpr, 16, pResult);7957 else if ((*psz == 'h' || *psz == 'H') && !psz[1])7958 {7959 *psz = '\0';7960 rc = dbgcEvalSubNum(pszExpr, 16, pResult);7961 }7962 else7963 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);7964 }7965 }7966 }7967 7968 return rc;7969 }7970 7971 7972 /**7973 * Evaluates one argument.7974 *7975 * @returns 0 on success. pResult contains the result.7976 * @returns VBox error code on parse or other evaluation error.7977 *7978 * @param pDbgc Debugger console instance data.7979 * @param pszExpr The expression string.7980 * @param pResult Where to store the result of the expression evaluation.7981 */7982 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)7983 {7984 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));7985 /*7986 * First we need to remove blanks in both ends.7987 * ASSUMES: There is no quoting unless the entire expression is a string.7988 */7989 7990 /* stripping. */7991 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))7992 pszExpr[--cchExpr] = '\0';7993 while (isblank(*pszExpr))7994 pszExpr++, cchExpr--;7995 if (!*pszExpr)7996 return VERR_PARSE_EMPTY_ARGUMENT;7997 7998 /* it there is any kind of quoting in the expression, it's string meat. */7999 if (strpbrk(pszExpr, "\"'`"))8000 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);8001 8002 /*8003 * Check if there are any parenthesis which needs removing.8004 */8005 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')8006 {8007 do8008 {8009 unsigned cPar = 1;8010 char *psz = pszExpr + 1;8011 char ch;8012 while ((ch = *psz) != '\0')8013 {8014 if (ch == '(')8015 cPar++;8016 else if (ch == ')')8017 {8018 if (cPar <= 0)8019 return VERR_PARSE_UNBALANCED_PARENTHESIS;8020 cPar--;8021 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */8022 break;8023 }8024 /* next */8025 psz++;8026 }8027 if (ch)8028 break;8029 8030 /* remove the parenthesis. */8031 pszExpr++;8032 cchExpr -= 2;8033 pszExpr[cchExpr] = '\0';8034 8035 /* strip blanks. */8036 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))8037 pszExpr[--cchExpr] = '\0';8038 while (isblank(*pszExpr))8039 pszExpr++, cchExpr--;8040 if (!*pszExpr)8041 return VERR_PARSE_EMPTY_ARGUMENT;8042 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');8043 }8044 8045 /* tabs to spaces. */8046 char *psz = pszExpr;8047 while ((psz = strchr(psz, '\t')) != NULL)8048 *psz = ' ';8049 8050 /*8051 * Now, we need to look for the binary operator with the lowest precedence.8052 *8053 * If there are no operators we're left with a simple expression which we8054 * evaluate with respect to unary operators8055 */8056 char *pszOpSplit = NULL;8057 PCDBGCOP pOpSplit = NULL;8058 unsigned cBinaryOps = 0;8059 unsigned cPar = 0;8060 char ch;8061 char chPrev = ' ';8062 bool fBinary = false;8063 psz = pszExpr;8064 8065 while ((ch = *psz) != '\0')8066 {8067 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));8068 /*8069 * Parenthesis.8070 */8071 if (ch == '(')8072 {8073 cPar++;8074 fBinary = false;8075 }8076 else if (ch == ')')8077 {8078 if (cPar <= 0)8079 return VERR_PARSE_UNBALANCED_PARENTHESIS;8080 cPar--;8081 fBinary = true;8082 }8083 /*8084 * Potential operator.8085 */8086 else if (cPar == 0 && !isblank(ch))8087 {8088 PCDBGCOP pOp = dbgcIsOpChar(ch)8089 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)8090 : NULL;8091 if (pOp)8092 {8093 /* If not the right kind of operator we've got a syntax error. */8094 if (pOp->fBinary != fBinary)8095 return VERR_PARSE_UNEXPECTED_OPERATOR;8096 8097 /*8098 * Update the parse state and skip the operator.8099 */8100 if (!pOpSplit)8101 {8102 pOpSplit = pOp;8103 pszOpSplit = psz;8104 cBinaryOps = fBinary;8105 }8106 else if (fBinary)8107 {8108 cBinaryOps++;8109 if (pOp->iPrecedence >= pOpSplit->iPrecedence)8110 {8111 pOpSplit = pOp;8112 pszOpSplit = psz;8113 }8114 }8115 8116 psz += pOp->cchName - 1;8117 fBinary = false;8118 }8119 else8120 fBinary = true;8121 }8122 8123 /* next */8124 psz++;8125 chPrev = ch;8126 } /* parse loop. */8127 8128 8129 /*8130 * Either we found an operator to divide the expression by8131 * or we didn't find any. In the first case it's divide and8132 * conquer. In the latter it's a single expression which8133 * needs dealing with its unary operators if any.8134 */8135 int rc;8136 if ( cBinaryOps8137 && pOpSplit->fBinary)8138 {8139 /* process 1st sub expression. */8140 *pszOpSplit = '\0';8141 DBGCVAR Arg1;8142 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);8143 if (VBOX_SUCCESS(rc))8144 {8145 /* process 2nd sub expression. */8146 char *psz2 = pszOpSplit + pOpSplit->cchName;8147 DBGCVAR Arg2;8148 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);8149 if (VBOX_SUCCESS(rc))8150 /* apply the operator. */8151 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);8152 }8153 }8154 else if (cBinaryOps)8155 {8156 /* process sub expression. */8157 pszOpSplit += pOpSplit->cchName;8158 DBGCVAR Arg;8159 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);8160 if (VBOX_SUCCESS(rc))8161 /* apply the operator. */8162 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);8163 }8164 else8165 /* plain expression or using unary operators perhaps with paratheses. */8166 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);8167 8168 return rc;8169 }8170 8171 8172 /**8173 * Parses the arguments of one command.8174 *8175 * @returns 0 on success.8176 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.8177 * @param pDbgc Debugger console instance data.8178 * @param pCmd Pointer to the command descriptor.8179 * @param pszArg Pointer to the arguments to parse.8180 * @param paArgs Where to store the parsed arguments.8181 * @param cArgs Size of the paArgs array.8182 * @param pcArgs Where to store the number of arguments.8183 * In the event of an error this is used to store the index of the offending argument.8184 */8185 static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)8186 {8187 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));8188 /*8189 * Check if we have any argument and if the command takes any.8190 */8191 *pcArgs = 0;8192 /* strip leading blanks. */8193 while (*pszArgs && isblank(*pszArgs))8194 pszArgs++;8195 if (!*pszArgs)8196 {8197 if (!pCmd->cArgsMin)8198 return 0;8199 return VERR_PARSE_TOO_FEW_ARGUMENTS;8200 }8201 /** @todo fixme - foo() doesn't work. */8202 if (!pCmd->cArgsMax)8203 return VERR_PARSE_TOO_MANY_ARGUMENTS;8204 8205 /*8206 * This is a hack, it's "temporary" and should go away "when" the parser is8207 * modified to match arguments while parsing.8208 */8209 if ( pCmd->cArgsMax == 18210 && pCmd->cArgsMin == 18211 && pCmd->cArgDescs == 18212 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING8213 && cArgs >= 1)8214 {8215 *pcArgs = 1;8216 RTStrStripR(pszArgs);8217 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);8218 }8219 8220 8221 /*8222 * The parse loop.8223 */8224 PDBGCVAR pArg0 = &paArgs[0];8225 PDBGCVAR pArg = pArg0;8226 *pcArgs = 0;8227 do8228 {8229 /*8230 * Can we have another argument?8231 */8232 if (*pcArgs >= pCmd->cArgsMax)8233 return VERR_PARSE_TOO_MANY_ARGUMENTS;8234 if (pArg >= &paArgs[cArgs])8235 return VERR_PARSE_ARGUMENT_OVERFLOW;8236 8237 /*8238 * Find the end of the argument.8239 */8240 int cPar = 0;8241 char chQuote = '\0';8242 char *pszEnd = NULL;8243 char *psz = pszArgs;8244 char ch;8245 bool fBinary = false;8246 for (;;)8247 {8248 /*8249 * Check for the end.8250 */8251 if ((ch = *psz) == '\0')8252 {8253 if (chQuote)8254 return VERR_PARSE_UNBALANCED_QUOTE;8255 if (cPar)8256 return VERR_PARSE_UNBALANCED_PARENTHESIS;8257 pszEnd = psz;8258 break;8259 }8260 /*8261 * When quoted we ignore everything but the quotation char.8262 * We use the REXX way of escaping the quotation char, i.e. double occurence.8263 */8264 else if (ch == '\'' || ch == '"' || ch == '`')8265 {8266 if (chQuote)8267 {8268 /* end quote? */8269 if (ch == chQuote)8270 {8271 if (psz[1] == ch)8272 psz++; /* skip the escaped quote char */8273 else8274 chQuote = '\0'; /* end of quoted string. */8275 }8276 }8277 else8278 chQuote = ch; /* open new quote */8279 }8280 /*8281 * Parenthesis can of course be nested.8282 */8283 else if (ch == '(')8284 {8285 cPar++;8286 fBinary = false;8287 }8288 else if (ch == ')')8289 {8290 if (!cPar)8291 return VERR_PARSE_UNBALANCED_PARENTHESIS;8292 cPar--;8293 fBinary = true;8294 }8295 else if (!chQuote && !cPar)8296 {8297 /*8298 * Encountering blanks may mean the end of it all. A binary operator8299 * will force continued parsing.8300 */8301 if (isblank(*psz))8302 {8303 pszEnd = psz++; /* just in case. */8304 while (isblank(*psz))8305 psz++;8306 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');8307 if (!pOp || pOp->fBinary != fBinary)8308 break; /* the end. */8309 psz += pOp->cchName;8310 while (isblank(*psz)) /* skip blanks so we don't get here again */8311 psz++;8312 fBinary = false;8313 continue;8314 }8315 8316 /*8317 * Look for operators without a space up front.8318 */8319 if (dbgcIsOpChar(*psz))8320 {8321 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');8322 if (pOp)8323 {8324 if (pOp->fBinary != fBinary)8325 {8326 pszEnd = psz;8327 /** @todo this is a parsing error really. */8328 break; /* the end. */8329 }8330 psz += pOp->cchName;8331 while (isblank(*psz)) /* skip blanks so we don't get here again */8332 psz++;8333 fBinary = false;8334 continue;8335 }8336 }8337 fBinary = true;8338 }8339 8340 /* next char */8341 psz++;8342 }8343 *pszEnd = '\0';8344 /* (psz = next char to process) */8345 8346 /*8347 * Parse and evaluate the argument.8348 */8349 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);8350 if (VBOX_FAILURE(rc))8351 return rc;8352 8353 /*8354 * Next.8355 */8356 pArg++;8357 (*pcArgs)++;8358 pszArgs = psz;8359 while (*pszArgs && isblank(*pszArgs))8360 pszArgs++;8361 } while (*pszArgs);8362 8363 /*8364 * Match the arguments.8365 */8366 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);8367 }8368 8369 8370 /**8371 * Process one command.8372 *8373 * @returns VBox status code. Any error indicates the termination of the console session.8374 * @param pDbgc Debugger console instance data.8375 * @param pszCmd Pointer to the command.8376 * @param cchCmd Length of the command.8377 */8378 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)8379 {8380 char *pszCmdInput = pszCmd;8381 8382 /*8383 * Skip blanks.8384 */8385 while (isblank(*pszCmd))8386 pszCmd++, cchCmd--;8387 8388 /* external command? */8389 bool fExternal = *pszCmd == '.';8390 if (fExternal)8391 pszCmd++, cchCmd--;8392 8393 /*8394 * Find arguments.8395 */8396 char *pszArgs = pszCmd;8397 while (isalnum(*pszArgs))8398 pszArgs++;8399 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))8400 {8401 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);8402 return 0;8403 }8404 8405 /*8406 * Find the command.8407 */8408 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);8409 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))8410 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);8411 8412 /*8413 * Parse arguments (if any).8414 */8415 unsigned cArgs;8416 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);8417 8418 /*8419 * Execute the command.8420 */8421 if (!rc)8422 {8423 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);8424 }8425 else8426 {8427 /* report parse / eval error. */8428 switch (rc)8429 {8430 case VERR_PARSE_TOO_FEW_ARGUMENTS:8431 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8432 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);8433 break;8434 case VERR_PARSE_TOO_MANY_ARGUMENTS:8435 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8436 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);8437 break;8438 case VERR_PARSE_ARGUMENT_OVERFLOW:8439 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8440 "Syntax error: Too many arguments.\n");8441 break;8442 case VERR_PARSE_UNBALANCED_QUOTE:8443 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8444 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);8445 break;8446 case VERR_PARSE_UNBALANCED_PARENTHESIS:8447 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8448 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);8449 break;8450 case VERR_PARSE_EMPTY_ARGUMENT:8451 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8452 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);8453 break;8454 case VERR_PARSE_UNEXPECTED_OPERATOR:8455 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8456 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);8457 break;8458 case VERR_PARSE_INVALID_NUMBER:8459 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8460 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);8461 break;8462 case VERR_PARSE_NUMBER_TOO_BIG:8463 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8464 "Error: Numeric overflow (argument %d).\n", cArgs);8465 break;8466 case VERR_PARSE_INVALID_OPERATION:8467 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8468 "Error: Invalid operation attempted (argument %d).\n", cArgs);8469 break;8470 case VERR_PARSE_FUNCTION_NOT_FOUND:8471 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8472 "Error: Function not found (argument %d).\n", cArgs);8473 break;8474 case VERR_PARSE_NOT_A_FUNCTION:8475 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8476 "Error: The function specified is not a function (argument %d).\n", cArgs);8477 break;8478 case VERR_PARSE_NO_MEMORY:8479 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8480 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);8481 break;8482 case VERR_PARSE_INCORRECT_ARG_TYPE:8483 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8484 "Error: Incorrect argument type (argument %d?).\n", cArgs);8485 break;8486 case VERR_PARSE_VARIABLE_NOT_FOUND:8487 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8488 "Error: An undefined variable was referenced (argument %d).\n", cArgs);8489 break;8490 case VERR_PARSE_CONVERSION_FAILED:8491 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8492 "Error: A conversion between two types failed (argument %d).\n", cArgs);8493 break;8494 case VERR_PARSE_NOT_IMPLEMENTED:8495 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8496 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);8497 break;8498 case VERR_PARSE_BAD_RESULT_TYPE:8499 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8500 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);8501 break;8502 case VERR_PARSE_WRITEONLY_SYMBOL:8503 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8504 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);8505 break;8506 8507 default:8508 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8509 "Error: Unknown error %d!\n", rc);8510 return rc;8511 }8512 8513 /*8514 * Parse errors are non fatal.8515 */8516 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)8517 rc = 0;8518 }8519 8520 return rc;8521 }8522 8523 8524 /**8525 * Process all commands current in the buffer.8526 *8527 * @returns VBox status code. Any error indicates the termination of the console session.8528 * @param pDbgc Debugger console instance data.8529 */8530 static int dbgcProcessCommands(PDBGC pDbgc)8531 {8532 int rc = 0;8533 while (pDbgc->cInputLines)8534 {8535 /*8536 * Empty the log buffer if we're hooking the log.8537 */8538 if (pDbgc->fLog)8539 {8540 rc = dbgcProcessLog(pDbgc);8541 if (VBOX_FAILURE(rc))8542 break;8543 }8544 8545 if (pDbgc->iRead == pDbgc->iWrite)8546 {8547 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));8548 pDbgc->cInputLines = 0;8549 return 0;8550 }8551 8552 /*8553 * Copy the command to the parse buffer.8554 */8555 char ch;8556 char *psz = &pDbgc->achInput[pDbgc->iRead];8557 char *pszTrg = &pDbgc->achScratch[0];8558 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )8559 {8560 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])8561 psz = &pDbgc->achInput[0];8562 8563 if (psz == &pDbgc->achInput[pDbgc->iWrite])8564 {8565 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));8566 pDbgc->cInputLines = 0;8567 return 0;8568 }8569 8570 pszTrg++;8571 }8572 *pszTrg = '\0';8573 8574 /*8575 * Advance the buffer.8576 */8577 pDbgc->iRead = psz - &pDbgc->achInput[0];8578 if (ch == '\n')8579 pDbgc->cInputLines--;8580 8581 /*8582 * Parse and execute this command.8583 */8584 pDbgc->pszScratch = psz;8585 pDbgc->iArg = 0;8586 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);8587 if (rc)8588 break;8589 }8590 8591 return rc;8592 }8593 8594 8595 /**8596 * Reads input, parses it and executes commands on '\n'.8597 *8598 * @returns VBox status.8599 * @param pDbgc Debugger console instance data.8600 */8601 static int dbgcProcessInput(PDBGC pDbgc)8602 {8603 /*8604 * We know there's input ready, so let's read it first.8605 */8606 int rc = dbgcInputRead(pDbgc);8607 if (VBOX_FAILURE(rc))8608 return rc;8609 8610 /*8611 * Now execute any ready commands.8612 */8613 if (pDbgc->cInputLines)8614 {8615 /** @todo this fReady stuff is broken. */8616 pDbgc->fReady = false;8617 rc = dbgcProcessCommands(pDbgc);8618 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)8619 pDbgc->fReady = true;8620 if ( VBOX_SUCCESS(rc)8621 && pDbgc->iRead == pDbgc->iWrite8622 && pDbgc->fReady)8623 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");8624 }8625 8626 return rc;8627 }8628 8629 8630 /**8631 * Gets the event context identifier string.8632 * @returns Read only string.8633 * @param enmCtx The context.8634 */8635 static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)8636 {8637 switch (enmCtx)8638 {8639 case DBGFEVENTCTX_RAW: return "raw";8640 case DBGFEVENTCTX_REM: return "rem";8641 case DBGFEVENTCTX_HWACCL: return "hwaccl";8642 case DBGFEVENTCTX_HYPER: return "hyper";8643 case DBGFEVENTCTX_OTHER: return "other";8644 8645 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";8646 default:8647 AssertMsgFailed(("enmCtx=%d\n", enmCtx));8648 return "!Unknown Event Ctx!";8649 }8650 }8651 8652 8653 /**8654 * Processes debugger events.8655 *8656 * @returns VBox status.8657 * @param pDbgc DBGC Instance data.8658 * @param pEvent Pointer to event data.8659 */8660 static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)8661 {8662 /*8663 * Flush log first.8664 */8665 if (pDbgc->fLog)8666 {8667 int rc = dbgcProcessLog(pDbgc);8668 if (VBOX_FAILURE(rc))8669 return rc;8670 }8671 8672 /*8673 * Process the event.8674 */8675 pDbgc->pszScratch = &pDbgc->achInput[0];8676 pDbgc->iArg = 0;8677 bool fPrintPrompt = true;8678 int rc = VINF_SUCCESS;8679 switch (pEvent->enmType)8680 {8681 /*8682 * The first part is events we have initiated with commands.8683 */8684 case DBGFEVENT_HALT_DONE:8685 {8686 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",8687 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));8688 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */8689 if (VBOX_SUCCESS(rc))8690 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8691 break;8692 }8693 8694 8695 /*8696 * The second part is events which can occur at any time.8697 */8698 case DBGFEVENT_FATAL_ERROR:8699 {8700 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",8701 dbgcGetEventCtx(pEvent->enmCtx));8702 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */8703 if (VBOX_SUCCESS(rc))8704 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8705 break;8706 }8707 8708 case DBGFEVENT_BREAKPOINT:8709 case DBGFEVENT_BREAKPOINT_HYPER:8710 {8711 bool fRegCtxGuest = pDbgc->fRegCtxGuest;8712 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;8713 8714 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);8715 switch (rc)8716 {8717 case VERR_DBGC_BP_NOT_FOUND:8718 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",8719 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));8720 break;8721 8722 case VINF_DBGC_BP_NO_COMMAND:8723 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",8724 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));8725 break;8726 8727 case VINF_BUFFER_OVERFLOW:8728 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",8729 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));8730 break;8731 8732 default:8733 break;8734 }8735 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))8736 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8737 else8738 pDbgc->fRegCtxGuest = fRegCtxGuest;8739 break;8740 }8741 8742 case DBGFEVENT_STEPPED:8743 case DBGFEVENT_STEPPED_HYPER:8744 {8745 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;8746 8747 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));8748 if (VBOX_SUCCESS(rc))8749 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8750 break;8751 }8752 8753 case DBGFEVENT_ASSERTION_HYPER:8754 {8755 pDbgc->fRegCtxGuest = false;8756 8757 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8758 "\ndbgf event: Hypervisor Assertion! (%s)\n"8759 "%s"8760 "%s"8761 "\n",8762 dbgcGetEventCtx(pEvent->enmCtx),8763 pEvent->u.Assert.pszMsg1,8764 pEvent->u.Assert.pszMsg2);8765 if (VBOX_SUCCESS(rc))8766 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8767 break;8768 }8769 8770 case DBGFEVENT_DEV_STOP:8771 {8772 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8773 "\n"8774 "dbgf event: DBGFSTOP (%s)\n"8775 "File: %s\n"8776 "Line: %d\n"8777 "Function: %s\n",8778 dbgcGetEventCtx(pEvent->enmCtx),8779 pEvent->u.Src.pszFile,8780 pEvent->u.Src.uLine,8781 pEvent->u.Src.pszFunction);8782 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)8783 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8784 "Message: %s\n",8785 pEvent->u.Src.pszMessage);8786 if (VBOX_SUCCESS(rc))8787 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");8788 break;8789 }8790 8791 8792 case DBGFEVENT_INVALID_COMMAND:8793 {8794 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");8795 fPrintPrompt = !pDbgc->fReady;8796 break;8797 }8798 8799 case DBGFEVENT_TERMINATING:8800 {8801 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");8802 rc = VERR_GENERAL_FAILURE;8803 break;8804 }8805 8806 8807 default:8808 {8809 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);8810 fPrintPrompt = !pDbgc->fReady;8811 break;8812 }8813 }8814 8815 /*8816 * Prompt, anyone?8817 */8818 if (fPrintPrompt && VBOX_SUCCESS(rc))8819 {8820 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");8821 }8822 8823 return rc;8824 }8825 8826 8827 8828 8829 8830 /**8831 * Make a console instance.8832 *8833 * This will not return until either an 'exit' command is issued or a error code8834 * indicating connection loss is encountered.8835 *8836 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.8837 * @returns The VBox status code causing the console termination.8838 *8839 * @param pVM VM Handle.8840 * @param pBack Pointer to the backend structure. This must contain8841 * a full set of function pointers to service the console.8842 * @param fFlags Reserved, must be zero.8843 * @remark A forced termination of the console is easiest done by forcing the8844 * callbacks to return fatal failures.8845 */8846 DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)8847 {8848 /*8849 * Validate input.8850 */8851 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);8852 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);8853 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);8854 8855 /*8856 * Allocate and initialize instance data8857 */8858 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));8859 if (!pDbgc)8860 return VERR_NO_MEMORY;8861 8862 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;8863 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;8864 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;8865 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;8866 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;8867 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;8868 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;8869 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;8870 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;8871 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;8872 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;8873 pDbgc->pBack = pBack;8874 pDbgc->pVM = NULL;8875 pDbgc->pszEmulation = "CodeView/WinDbg";8876 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0];8877 pDbgc->cEmulationCmds = RT_ELEMENTS(g_aCmdsCodeView);8878 //pDbgc->fLog = false;8879 pDbgc->fRegCtxGuest = true;8880 pDbgc->fRegTerse = true;8881 //pDbgc->DisasmPos = {0};8882 //pDbgc->SourcePos = {0};8883 //pDbgc->DumpPos = {0};8884 //pDbgc->cbDumpElement = 0;8885 //pDbgc->cVars = 0;8886 //pDbgc->paVars = NULL;8887 //pDbgc->pFirstBp = NULL;8888 //pDbgc->uInputZero = 0;8889 //pDbgc->iRead = 0;8890 //pDbgc->iWrite = 0;8891 //pDbgc->cInputLines = 0;8892 //pDbgc->fInputOverflow = false;8893 pDbgc->fReady = true;8894 pDbgc->pszScratch = &pDbgc->achScratch[0];8895 //pDbgc->iArg = 0;8896 //pDbgc->rcOutput = 0;8897 8898 dbgcInitOpCharBitMap();8899 8900 /*8901 * Print welcome message.8902 */8903 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8904 "Welcome to the VirtualBox Debugger!\n");8905 if (VBOX_FAILURE(rc))8906 goto l_failure;8907 8908 /*8909 * Attach to the VM.8910 */8911 rc = DBGFR3Attach(pVM);8912 if (VBOX_FAILURE(rc))8913 {8914 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);8915 goto l_failure;8916 }8917 pDbgc->pVM = pVM;8918 8919 /*8920 * Print commandline and auto select result.8921 */8922 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,8923 "Current VM is %08x\n" /** @todo get and print the VM name! */8924 "VBoxDbg> ",8925 pDbgc->pVM);8926 if (VBOX_FAILURE(rc))8927 goto l_failure;8928 8929 /*8930 * Main Debugger Loop.8931 *8932 * This loop will either block on waiting for input or on waiting on8933 * debug events. If we're forwarding the log we cannot wait for long8934 * before we must flush the log.8935 */8936 for (rc = 0;;)8937 {8938 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))8939 {8940 /*8941 * Wait for a debug event.8942 */8943 PCDBGFEVENT pEvent;8944 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);8945 if (VBOX_SUCCESS(rc))8946 {8947 rc = dbgcProcessEvent(pDbgc, pEvent);8948 if (VBOX_FAILURE(rc))8949 break;8950 }8951 else if (rc != VERR_TIMEOUT)8952 break;8953 8954 /*8955 * Check for input.8956 */8957 if (pBack->pfnInput(pDbgc->pBack, 0))8958 {8959 rc = dbgcProcessInput(pDbgc);8960 if (VBOX_FAILURE(rc))8961 break;8962 }8963 }8964 else8965 {8966 /*8967 * Wait for input. If Logging is enabled we'll only wait very briefly.8968 */8969 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))8970 {8971 rc = dbgcProcessInput(pDbgc);8972 if (VBOX_FAILURE(rc))8973 break;8974 }8975 }8976 8977 /*8978 * Forward log output.8979 */8980 if (pDbgc->fLog)8981 {8982 rc = dbgcProcessLog(pDbgc);8983 if (VBOX_FAILURE(rc))8984 break;8985 }8986 }8987 8988 8989 l_failure:8990 /*8991 * Cleanup console debugger session.8992 */8993 /* Disable log hook. */8994 if (pDbgc->fLog)8995 {8996 8997 }8998 8999 /* Detach from the VM. */9000 if (pDbgc->pVM)9001 DBGFR3Detach(pDbgc->pVM);9002 9003 /* finally, free the instance memory. */9004 RTMemFree(pDbgc);9005 9006 return rc;9007 }9008 9009 9010 9011 /**9012 * Register one or more external commands.9013 *9014 * @returns VBox status.9015 * @param paCommands Pointer to an array of command descriptors.9016 * The commands must be unique. It's not possible9017 * to register the same commands more than once.9018 * @param cCommands Number of commands.9019 */9020 DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)9021 {9022 /*9023 * Lock the list.9024 */9025 DBGCEXTCMDS_LOCK_WR();9026 PDBGCEXTCMDS pCur = g_pExtCmdsHead;9027 while (pCur)9028 {9029 if (paCommands == pCur->paCmds)9030 {9031 DBGCEXTCMDS_UNLOCK_WR();9032 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));9033 return VWRN_DBGC_ALREADY_REGISTERED;9034 }9035 pCur = pCur->pNext;9036 }9037 9038 /*9039 * Allocate new chunk.9040 */9041 int rc = 0;9042 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));9043 if (pCur)9044 {9045 pCur->cCmds = cCommands;9046 pCur->paCmds = paCommands;9047 pCur->pNext = g_pExtCmdsHead;9048 g_pExtCmdsHead = pCur;9049 }9050 else9051 rc = VERR_NO_MEMORY;9052 DBGCEXTCMDS_UNLOCK_WR();9053 9054 return rc;9055 }9056 9057 9058 /**9059 * Deregister one or more external commands previously registered by9060 * DBGCRegisterCommands().9061 *9062 * @returns VBox status.9063 * @param paCommands Pointer to an array of command descriptors9064 * as given to DBGCRegisterCommands().9065 * @param cCommands Number of commands.9066 */9067 DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)9068 {9069 /*9070 * Lock the list.9071 */9072 DBGCEXTCMDS_LOCK_WR();9073 PDBGCEXTCMDS pPrev = NULL;9074 PDBGCEXTCMDS pCur = g_pExtCmdsHead;9075 while (pCur)9076 {9077 if (paCommands == pCur->paCmds)9078 {9079 if (pPrev)9080 pPrev->pNext = pCur->pNext;9081 else9082 g_pExtCmdsHead = pCur->pNext;9083 DBGCEXTCMDS_UNLOCK_WR();9084 9085 RTMemFree(pCur);9086 return VINF_SUCCESS;9087 }9088 pPrev = pCur;9089 pCur = pCur->pNext;9090 }9091 DBGCEXTCMDS_UNLOCK_WR();9092 9093 NOREF(cCommands);9094 return VERR_DBGC_COMMANDS_NOT_REGISTERED;9095 }9096 -
trunk/src/VBox/Debugger/DBGCInternal.h
r5668 r5669 337 337 * Internal Functions * 338 338 *******************************************************************************/ 339 #if 0 340 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat); 341 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb); 342 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2); 343 static void dbgcVarSetNoRange(PDBGCVAR pVar); 344 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb); 345 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress); 346 347 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd); 348 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd); 349 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp); 350 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp); 351 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp); 352 353 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol); 354 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult); 355 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult); 356 static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd); 339 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd); 340 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd); 341 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp); 342 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp); 343 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp); 344 345 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat); 346 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb); 347 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2); 348 void dbgcVarSetNoRange(PDBGCVAR pVar); 349 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb); 350 int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress); 351 352 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol); 353 354 355 /******************************************************************************* 356 * Global Variables * 357 *******************************************************************************/ 358 extern const DBGCCMD g_aCmds[]; 359 extern const DBGCCMD g_aCmdsCodeView[]; 360 extern const unsigned g_cCmdsCodeView; 361 357 362 #endif 358 359 360 /*******************************************************************************361 * Global Variables *362 *******************************************************************************/363 /** Command descriptors for the basic commands. */364 extern const DBGCCMD g_aCmds[];365 /** Command descriptors for the CodeView / WinDbg emulation.366 * The emulation isn't attempting to be identical, only somewhat similar.367 */368 extern const DBGCCMD g_aCmdsCodeView[];369 370 #endif -
trunk/src/VBox/Debugger/DBGConsole.cpp
r5668 r5669 131 131 * Internal Functions * 132 132 *******************************************************************************/ 133 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);134 133 static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 135 134 static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 136 135 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 137 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);138 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);139 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);140 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);141 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);142 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);143 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);144 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);145 136 static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 146 137 static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 147 138 static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 148 139 static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 149 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);150 140 static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 151 141 static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); … … 157 147 static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 158 148 static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult); 159 160 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);161 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);162 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);163 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);164 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);165 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);166 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);167 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);168 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);169 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);170 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);171 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);172 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);173 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);174 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);175 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);176 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);177 149 178 150 static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult); … … 206 178 static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue); 207 179 208 static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat);209 static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb);210 static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2);211 static void dbgcVarSetNoRange(PDBGCVAR pVar);212 static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb);213 static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress);214 215 static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd);216 static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd);217 static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp);218 static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp);219 static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp);220 221 static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol);222 180 static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult); 223 181 static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult); … … 264 222 265 223 266 /** 'br' arguments. */267 static const DBGCVARDESC g_aArgBrkREM[] =268 {269 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */270 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },271 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },272 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },273 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },274 };275 276 277 /** 'dg', 'dga', 'dl', 'dla' arguments. */278 static const DBGCVARDESC g_aArgDumpDT[] =279 {280 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */281 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "sel", "Selector or selector range." },282 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Far address which selector should be dumped." },283 };284 285 286 /** 'di', 'dia' arguments. */287 static const DBGCVARDESC g_aArgDumpIDT[] =288 {289 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */290 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "int", "The interrupt vector or interrupt vector range." },291 };292 293 294 /** 'dpd*' arguments. */295 static const DBGCVARDESC g_aArgDumpPD[] =296 {297 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */298 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "index", "Index into the page directory." },299 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },300 };301 302 303 /** 'dpda' arguments. */304 static const DBGCVARDESC g_aArgDumpPDAddr[] =305 {306 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */307 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },308 };309 310 311 /** 'dpt?' arguments. */312 static const DBGCVARDESC g_aArgDumpPT[] =313 {314 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */315 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },316 };317 318 319 /** 'dpta' arguments. */320 static const DBGCVARDESC g_aArgDumpPTAddr[] =321 {322 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */323 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },324 };325 326 327 /** 'dt' arguments. */328 static const DBGCVARDESC g_aArgDumpTSS[] =329 {330 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */331 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "tss", "TSS selector number." },332 { 0, 1, DBGCVAR_CAT_POINTER, 0, "tss:ign|addr", "TSS address. If the selector is a TSS selector, the offset will be ignored." }333 };334 335 336 224 /** 'help' arguments. */ 337 225 static const DBGCVARDESC g_aArgHelp[] = … … 403 291 { 404 292 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */ 405 { "br", 1, 4, &g_aArgBrkREM[0], ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]",406 "Sets a recompiler specific breakpoint." },407 293 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." }, 408 { "dg", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT)." },409 { "dga", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the global descriptor table (GDT) including not-present entries." },410 { "di", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT)." },411 { "dia", 0, ~0, &g_aArgDumpIDT[0], ELEMENTS(g_aArgDumpIDT), NULL, 0, dbgcCmdDumpIDT, "[int [..]]", "Dump the interrupt descriptor table (IDT) including not-present entries." },412 { "dl", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT)." },413 { "dla", 0, ~0, &g_aArgDumpDT[0], ELEMENTS(g_aArgDumpDT), NULL, 0, dbgcCmdDumpDT, "[sel [..]]", "Dump the local descriptor table (LDT) including not-present entries." },414 { "dpd", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." },415 { "dpda", 0, 1, &g_aArgDumpPDAddr[0],ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." },416 { "dpdb", 1, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " },417 { "dpdg", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." },418 { "dpdh", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " },419 { "dpt", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." },420 { "dpta", 1, 1, &g_aArgDumpPTAddr[0],ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." },421 { "dptb", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." },422 { "dptg", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." },423 { "dpth", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." },424 { "dt", 0, 1, &g_aArgDumpTSS[0], ELEMENTS(g_aArgDumpTSS), NULL, 0, dbgcCmdDumpTSS, "[tss|tss:ign|addr]", "Dump the task state segment (TSS)." },425 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." }, 426 295 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." }, … … 440 309 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." }, 441 310 { "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." }, 442 };443 444 445 /** 'ba' arguments. */446 static const DBGCVARDESC g_aArgBrkAcc[] =447 {448 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */449 { 1, 1, DBGCVAR_CAT_STRING, 0, "access", "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." },450 { 1, 1, DBGCVAR_CAT_NUMBER, 0, "size", "The access size: 1, 2, 4, or 8. 'x' access requires 1, and 8 requires amd64 long mode." },451 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },452 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },453 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },454 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },455 };456 457 458 /** 'bc', 'bd', 'be' arguments. */459 static const DBGCVARDESC g_aArgBrks[] =460 {461 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */462 { 0, ~0, DBGCVAR_CAT_NUMBER, 0, "#bp", "Breakpoint number." },463 { 0, 1, DBGCVAR_CAT_STRING, 0, "all", "All breakpoints." },464 };465 466 467 /** 'bp' arguments. */468 static const DBGCVARDESC g_aArgBrkSet[] =469 {470 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */471 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "address", "The address." },472 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },473 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },474 { 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },475 };476 477 478 /** 'd?' arguments. */479 static const DBGCVARDESC g_aArgDumpMem[] =480 {481 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */482 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start dumping memory." },483 };484 485 486 /** 'ln' arguments. */487 static const DBGCVARDESC g_aArgListNear[] =488 {489 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */490 { 0, ~0, DBGCVAR_CAT_POINTER, 0, "address", "Address of the symbol to look up." },491 { 0, ~0, DBGCVAR_CAT_SYMBOL, 0, "symbol", "Symbol to lookup." },492 };493 494 /** 'ln' return. */495 static const DBGCVARDESC g_RetListNear =496 {497 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The last resolved symbol/address with adjusted range."498 };499 500 501 /** 'ls' arguments. */502 static const DBGCVARDESC g_aArgListSource[] =503 {504 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */505 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start looking for source lines." },506 };507 508 509 /** 'm' argument. */510 static const DBGCVARDESC g_aArgMemoryInfo[] =511 {512 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */513 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Pointer to obtain info about." },514 };515 516 517 /** 'r' arguments. */518 static const DBGCVARDESC g_aArgReg[] =519 {520 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */521 { 0, 1, DBGCVAR_CAT_SYMBOL, 0, "register", "Register to show or set." },522 { 0, 1, DBGCVAR_CAT_NUMBER_NO_RANGE, DBGCVD_FLAGS_DEP_PREV, "value", "New register value." },523 };524 525 526 /** 's' arguments. */527 static const DBGCVARDESC g_aArgSearchMem[] =528 {529 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */530 { 1, 1, DBGCVAR_CAT_GC_POINTER, 0, "range", "Register to show or set." },531 { 1, ~0, DBGCVAR_CAT_ANY, 0, "pattern", "Pattern to search for." },532 };533 534 535 /** 'u' arguments. */536 static const DBGCVARDESC g_aArgUnassemble[] =537 {538 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */539 { 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address where to start disassembling." },540 };541 542 543 /** Command descriptors for the CodeView / WinDbg emulation.544 * The emulation isn't attempting to be identical, only somewhat similar.545 */546 static const DBGCCMD g_aCmdsCodeView[] =547 {548 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */549 { "ba", 3, 6, &g_aArgBrkAcc[0], RT_ELEMENTS(g_aArgBrkAcc), NULL, 0, dbgcCmdBrkAccess, "<access> <size> <address> [passes [max passes]] [cmds]",550 "Sets a data access breakpoint." },551 { "bc", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkClear, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },552 { "bd", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkDisable, "all | <bp#> [bp# []]", "Disables a set of breakpoints." },553 { "be", 1, ~0, &g_aArgBrks[0], RT_ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkEnable, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },554 { "bl", 0, 0, NULL, 0, NULL, 0, dbgcCmdBrkList, "", "Lists all the breakpoints." },555 { "bp", 1, 4, &g_aArgBrkSet[0], RT_ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]",556 "Sets a breakpoint (int 3)." },557 { "d", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." },558 { "da", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." },559 { "db", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." },560 { "dd", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." },561 { "dq", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." },562 { "dw", 0, 1, &g_aArgDumpMem[0], RT_ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." },563 { "g", 0, 0, NULL, 0, NULL, 0, dbgcCmdGo, "", "Continue execution." },564 { "k", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack." },565 { "kg", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - guest." },566 { "kh", 0, 0, NULL, 0, NULL, 0, dbgcCmdStack, "", "Callstack - hypervisor." },567 { "ln", 0, ~0, &g_aArgListNear[0], RT_ELEMENTS(g_aArgListNear), &g_RetListNear, 0, dbgcCmdListNear, "[addr/sym [..]]", "List symbols near to the address. Default address is CS:EIP." },568 { "ls", 0, 1, &g_aArgListSource[0],RT_ELEMENTS(g_aArgListSource),NULL, 0, dbgcCmdListSource, "[addr]", "Source." },569 { "m", 1, 1, &g_aArgMemoryInfo[0],RT_ELEMENTS(g_aArgMemoryInfo),NULL, 0, dbgcCmdMemoryInfo, "<addr>", "Display information about that piece of memory." },570 { "r", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdReg, "[reg [newval]]", "Show or set register(s) - active reg set." },571 { "rg", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegGuest, "[reg [newval]]", "Show or set register(s) - guest reg set." },572 { "rh", 0, 2, &g_aArgReg[0], RT_ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegHyper, "[reg [newval]]", "Show or set register(s) - hypervisor reg set." },573 { "rt", 0, 0, NULL, 0, NULL, 0, dbgcCmdRegTerse, "", "Toggles terse / verbose register info." },574 //{ "s", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Continue last search." },575 { "sa", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for an ascii string." },576 { "sb", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more bytes." },577 { "sd", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more double words." },578 { "sq", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more quad words." },579 { "su", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for an unicode string." },580 { "sw", 2, ~0, &g_aArgSearchMem[0],RT_ELEMENTS(g_aArgSearchMem), NULL, 0, dbgcCmdSearchMem, "<range> <pattern>", "Search memory for one or more words." },581 { "t", 0, 0, NULL, 0, NULL, 0, dbgcCmdTrace, "", "Instruction trace (step into)." },582 { "u", 0, 1, &g_aArgUnassemble[0],RT_ELEMENTS(g_aArgUnassemble),NULL, 0, dbgcCmdUnassemble, "[addr]", "Unassemble." },583 311 }; 584 312 … … 1013 741 1014 742 /** 1015 * The ' go' command.743 * The 'stop' command. 1016 744 * 1017 745 * @returns VBox status. … … 1022 750 * @param cArgs Number of arguments in the array. 1023 751 */ 1024 static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1025 {1026 /*1027 * Check if the VM is halted or not before trying to resume it.1028 */1029 if (!DBGFR3IsHalted(pVM))1030 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already running...\n");1031 else1032 {1033 int rc = DBGFR3Resume(pVM);1034 if (VBOX_FAILURE(rc))1035 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Resume().");1036 }1037 1038 NOREF(pCmd);1039 NOREF(paArgs);1040 NOREF(cArgs);1041 NOREF(pResult);1042 return 0;1043 }1044 1045 /**1046 * The 'stop' command.1047 *1048 * @returns VBox status.1049 * @param pCmd Pointer to the command descriptor (as registered).1050 * @param pCmdHlp Pointer to command helper functions.1051 * @param pVM Pointer to the current VM (if any).1052 * @param paArgs Pointer to (readonly) array of arguments.1053 * @param cArgs Number of arguments in the array.1054 */1055 752 static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult) 1056 753 { … … 1072 769 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult); 1073 770 return rc; 1074 }1075 1076 1077 /**1078 * The 'ba' command.1079 *1080 * @returns VBox status.1081 * @param pCmd Pointer to the command descriptor (as registered).1082 * @param pCmdHlp Pointer to command helper functions.1083 * @param pVM Pointer to the current VM (if any).1084 * @param paArgs Pointer to (readonly) array of arguments.1085 * @param cArgs Number of arguments in the array.1086 */1087 static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1088 {1089 /*1090 * Interpret access type.1091 */1092 if ( !strchr("xrwi", paArgs[0].u.pszString[0])1093 || paArgs[0].u.pszString[1])1094 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n",1095 paArgs[0].u.pszString, pCmd->pszCmd);1096 uint8_t fType = 0;1097 switch (paArgs[0].u.pszString[0])1098 {1099 case 'x': fType = X86_DR7_RW_EO; break;1100 case 'r': fType = X86_DR7_RW_RW; break;1101 case 'w': fType = X86_DR7_RW_WO; break;1102 case 'i': fType = X86_DR7_RW_IO; break;1103 }1104 1105 /*1106 * Validate size.1107 */1108 if (fType == X86_DR7_RW_EO && paArgs[1].u.u64Number != 1)1109 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n",1110 paArgs[1].u.u64Number, pCmd->pszCmd);1111 switch (paArgs[1].u.u64Number)1112 {1113 case 1:1114 case 2:1115 case 4:1116 break;1117 /*case 8: - later*/1118 default:1119 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 1, 2 or 4!\n",1120 paArgs[1].u.u64Number, pCmd->pszCmd);1121 }1122 uint8_t cb = (uint8_t)paArgs[1].u.u64Number;1123 1124 /*1125 * Convert the pointer to a DBGF address.1126 */1127 DBGFADDRESS Address;1128 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[2], &Address);1129 if (VBOX_FAILURE(rc))1130 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[2], rc);1131 1132 /*1133 * Pick out the optional arguments.1134 */1135 uint64_t iHitTrigger = 0;1136 uint64_t iHitDisable = ~0;1137 const char *pszCmds = NULL;1138 unsigned iArg = 3;1139 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1140 {1141 iHitTrigger = paArgs[iArg].u.u64Number;1142 iArg++;1143 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1144 {1145 iHitDisable = paArgs[iArg].u.u64Number;1146 iArg++;1147 }1148 }1149 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)1150 {1151 pszCmds = paArgs[iArg].u.pszString;1152 iArg++;1153 }1154 1155 /*1156 * Try set the breakpoint.1157 */1158 RTUINT iBp;1159 rc = DBGFR3BpSetReg(pVM, &Address, iHitTrigger, iHitDisable, fType, cb, &iBp);1160 if (VBOX_SUCCESS(rc))1161 {1162 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1163 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);1164 if (VBOX_SUCCESS(rc))1165 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1166 if (rc == VERR_DBGC_BP_EXISTS)1167 {1168 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);1169 if (VBOX_SUCCESS(rc))1170 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1171 }1172 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);1173 AssertRC(rc2);1174 }1175 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);1176 }1177 1178 1179 /**1180 * The 'bc' command.1181 *1182 * @returns VBox status.1183 * @param pCmd Pointer to the command descriptor (as registered).1184 * @param pCmdHlp Pointer to command helper functions.1185 * @param pVM Pointer to the current VM (if any).1186 * @param paArgs Pointer to (readonly) array of arguments.1187 * @param cArgs Number of arguments in the array.1188 */1189 static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1190 {1191 /*1192 * Enumerate the arguments.1193 */1194 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1195 int rc = VINF_SUCCESS;1196 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)1197 {1198 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)1199 {1200 /* one */1201 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;1202 if (iBp != paArgs[iArg].u.u64Number)1203 {1204 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);1205 break;1206 }1207 int rc2 = DBGFR3BpClear(pVM, iBp);1208 if (VBOX_FAILURE(rc2))1209 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);1210 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)1211 dbgcBpDelete(pDbgc, iBp);1212 }1213 else if (!strcmp(paArgs[iArg].u.pszString, "all"))1214 {1215 /* all */1216 PDBGCBP pBp = pDbgc->pFirstBp;1217 while (pBp)1218 {1219 RTUINT iBp = pBp->iBp;1220 pBp = pBp->pNext;1221 1222 int rc2 = DBGFR3BpClear(pVM, iBp);1223 if (VBOX_FAILURE(rc2))1224 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc2, "DBGFR3BpClear failed for breakpoint %u!\n", iBp);1225 if (VBOX_SUCCESS(rc2) || rc2 == VERR_DBGF_BP_NOT_FOUND)1226 dbgcBpDelete(pDbgc, iBp);1227 }1228 }1229 else1230 {1231 /* invalid parameter */1232 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);1233 break;1234 }1235 }1236 return rc;1237 }1238 1239 1240 /**1241 * The 'bd' command.1242 *1243 * @returns VBox status.1244 * @param pCmd Pointer to the command descriptor (as registered).1245 * @param pCmdHlp Pointer to command helper functions.1246 * @param pVM Pointer to the current VM (if any).1247 * @param paArgs Pointer to (readonly) array of arguments.1248 * @param cArgs Number of arguments in the array.1249 */1250 static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1251 {1252 /*1253 * Enumerate the arguments.1254 */1255 int rc = VINF_SUCCESS;1256 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)1257 {1258 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)1259 {1260 /* one */1261 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;1262 if (iBp != paArgs[iArg].u.u64Number)1263 {1264 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);1265 break;1266 }1267 rc = DBGFR3BpDisable(pVM, iBp);1268 if (VBOX_FAILURE(rc))1269 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", iBp);1270 }1271 else if (!strcmp(paArgs[iArg].u.pszString, "all"))1272 {1273 /* all */1274 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1275 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)1276 {1277 rc = DBGFR3BpDisable(pVM, pBp->iBp);1278 if (VBOX_FAILURE(rc))1279 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpDisable failed for breakpoint %u!\n", pBp->iBp);1280 }1281 }1282 else1283 {1284 /* invalid parameter */1285 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);1286 break;1287 }1288 }1289 return rc;1290 }1291 1292 1293 /**1294 * The 'be' command.1295 *1296 * @returns VBox status.1297 * @param pCmd Pointer to the command descriptor (as registered).1298 * @param pCmdHlp Pointer to command helper functions.1299 * @param pVM Pointer to the current VM (if any).1300 * @param paArgs Pointer to (readonly) array of arguments.1301 * @param cArgs Number of arguments in the array.1302 */1303 static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1304 {1305 /*1306 * Enumerate the arguments.1307 */1308 int rc = VINF_SUCCESS;1309 for (unsigned iArg = 0; iArg < cArgs && VBOX_SUCCESS(rc); iArg++)1310 {1311 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)1312 {1313 /* one */1314 RTUINT iBp = (RTUINT)paArgs[iArg].u.u64Number;1315 if (iBp != paArgs[iArg].u.u64Number)1316 {1317 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);1318 break;1319 }1320 rc = DBGFR3BpEnable(pVM, iBp);1321 if (VBOX_FAILURE(rc))1322 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", iBp);1323 }1324 else if (!strcmp(paArgs[iArg].u.pszString, "all"))1325 {1326 /* all */1327 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1328 for (PDBGCBP pBp = pDbgc->pFirstBp; pBp; pBp = pBp->pNext)1329 {1330 rc = DBGFR3BpEnable(pVM, pBp->iBp);1331 if (VBOX_FAILURE(rc))1332 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnable failed for breakpoint %u!\n", pBp->iBp);1333 }1334 }1335 else1336 {1337 /* invalid parameter */1338 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);1339 break;1340 }1341 }1342 return rc;1343 }1344 1345 1346 /**1347 * Breakpoint enumeration callback function.1348 *1349 * @returns VBox status code. Any failure will stop the enumeration.1350 * @param pVM The VM handle.1351 * @param pvUser The user argument.1352 * @param pBp Pointer to the breakpoint information. (readonly)1353 */1354 static DECLCALLBACK(int) dbgcEnumBreakpointsCallback(PVM pVM, void *pvUser, PCDBGFBP pBp)1355 {1356 PDBGC pDbgc = (PDBGC)pvUser;1357 PDBGCBP pDbgcBp = dbgcBpGet(pDbgc, pBp->iBp);1358 1359 /*1360 * BP type and size.1361 */1362 char chType;1363 char cb = 1;1364 switch (pBp->enmType)1365 {1366 case DBGFBPTYPE_INT3:1367 chType = 'p';1368 break;1369 case DBGFBPTYPE_REG:1370 switch (pBp->u.Reg.fType)1371 {1372 case X86_DR7_RW_EO: chType = 'x'; break;1373 case X86_DR7_RW_WO: chType = 'w'; break;1374 case X86_DR7_RW_IO: chType = 'i'; break;1375 case X86_DR7_RW_RW: chType = 'r'; break;1376 default: chType = '?'; break;1377 1378 }1379 cb = pBp->u.Reg.cb;1380 break;1381 case DBGFBPTYPE_REM:1382 chType = 'r';1383 break;1384 default:1385 chType = '?';1386 break;1387 }1388 1389 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%2u %c %d %c %VGv %04RX64 (%04RX64 to ",1390 pBp->iBp, pBp->fEnabled ? 'e' : 'd', cb, chType,1391 pBp->GCPtr, pBp->cHits, pBp->iHitTrigger);1392 if (pBp->iHitDisable == ~(uint64_t)0)1393 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "~0) ");1394 else1395 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%04RX64)");1396 1397 /*1398 * Try resolve the address.1399 */1400 DBGFSYMBOL Sym;1401 RTGCINTPTR off;1402 int rc = DBGFR3SymbolByAddr(pVM, pBp->GCPtr, &off, &Sym);1403 if (VBOX_SUCCESS(rc))1404 {1405 if (!off)1406 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s", Sym.szName);1407 else if (off > 0)1408 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, off);1409 else1410 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "%s+%VGv", Sym.szName, -off);1411 }1412 1413 /*1414 * The commands.1415 */1416 if (pDbgcBp)1417 {1418 if (pDbgcBp->cchCmd)1419 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n cmds: '%s'\n",1420 pDbgcBp->szCmd);1421 else1422 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\n");1423 }1424 else1425 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, " [unknown bp]\n");1426 1427 return VINF_SUCCESS;1428 }1429 1430 1431 /**1432 * The 'bl' command.1433 *1434 * @returns VBox status.1435 * @param pCmd Pointer to the command descriptor (as registered).1436 * @param pCmdHlp Pointer to command helper functions.1437 * @param pVM Pointer to the current VM (if any).1438 * @param paArgs Pointer to (readonly) array of arguments.1439 * @param cArgs Number of arguments in the array.1440 */1441 static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)1442 {1443 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1444 1445 /*1446 * Enumerate the breakpoints.1447 */1448 int rc = DBGFR3BpEnum(pVM, dbgcEnumBreakpointsCallback, pDbgc);1449 if (VBOX_FAILURE(rc))1450 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3BpEnum failed.\n");1451 return rc;1452 }1453 1454 1455 /**1456 * The 'bp' command.1457 *1458 * @returns VBox status.1459 * @param pCmd Pointer to the command descriptor (as registered).1460 * @param pCmdHlp Pointer to command helper functions.1461 * @param pVM Pointer to the current VM (if any).1462 * @param paArgs Pointer to (readonly) array of arguments.1463 * @param cArgs Number of arguments in the array.1464 */1465 static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1466 {1467 /*1468 * Convert the pointer to a DBGF address.1469 */1470 DBGFADDRESS Address;1471 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);1472 if (VBOX_FAILURE(rc))1473 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);1474 1475 /*1476 * Pick out the optional arguments.1477 */1478 uint64_t iHitTrigger = 0;1479 uint64_t iHitDisable = ~0;1480 const char *pszCmds = NULL;1481 unsigned iArg = 1;1482 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1483 {1484 iHitTrigger = paArgs[iArg].u.u64Number;1485 iArg++;1486 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1487 {1488 iHitDisable = paArgs[iArg].u.u64Number;1489 iArg++;1490 }1491 }1492 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)1493 {1494 pszCmds = paArgs[iArg].u.pszString;1495 iArg++;1496 }1497 1498 /*1499 * Try set the breakpoint.1500 */1501 RTUINT iBp;1502 rc = DBGFR3BpSet(pVM, &Address, iHitTrigger, iHitDisable, &iBp);1503 if (VBOX_SUCCESS(rc))1504 {1505 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1506 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);1507 if (VBOX_SUCCESS(rc))1508 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1509 if (rc == VERR_DBGC_BP_EXISTS)1510 {1511 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);1512 if (VBOX_SUCCESS(rc))1513 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1514 }1515 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);1516 AssertRC(rc2);1517 }1518 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);1519 }1520 1521 1522 /**1523 * The 'br' command.1524 *1525 * @returns VBox status.1526 * @param pCmd Pointer to the command descriptor (as registered).1527 * @param pCmdHlp Pointer to command helper functions.1528 * @param pVM Pointer to the current VM (if any).1529 * @param paArgs Pointer to (readonly) array of arguments.1530 * @param cArgs Number of arguments in the array.1531 */1532 static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)1533 {1534 /*1535 * Convert the pointer to a DBGF address.1536 */1537 DBGFADDRESS Address;1538 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &Address);1539 if (VBOX_FAILURE(rc))1540 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);1541 1542 /*1543 * Pick out the optional arguments.1544 */1545 uint64_t iHitTrigger = 0;1546 uint64_t iHitDisable = ~0;1547 const char *pszCmds = NULL;1548 unsigned iArg = 1;1549 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1550 {1551 iHitTrigger = paArgs[iArg].u.u64Number;1552 iArg++;1553 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)1554 {1555 iHitDisable = paArgs[iArg].u.u64Number;1556 iArg++;1557 }1558 }1559 if (iArg < cArgs && paArgs[iArg].enmType == DBGCVAR_TYPE_STRING)1560 {1561 pszCmds = paArgs[iArg].u.pszString;1562 iArg++;1563 }1564 1565 /*1566 * Try set the breakpoint.1567 */1568 RTUINT iBp;1569 rc = DBGFR3BpSetREM(pVM, &Address, iHitTrigger, iHitDisable, &iBp);1570 if (VBOX_SUCCESS(rc))1571 {1572 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1573 rc = dbgcBpAdd(pDbgc, iBp, pszCmds);1574 if (VBOX_SUCCESS(rc))1575 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1576 if (rc == VERR_DBGC_BP_EXISTS)1577 {1578 rc = dbgcBpUpdate(pDbgc, iBp, pszCmds);1579 if (VBOX_SUCCESS(rc))1580 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);1581 }1582 int rc2 = DBGFR3BpClear(pDbgc->pVM, iBp);1583 AssertRC(rc2);1584 }1585 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);1586 }1587 1588 1589 /**1590 * The 'u' command.1591 *1592 * @returns VBox status.1593 * @param pCmd Pointer to the command descriptor (as registered).1594 * @param pCmdHlp Pointer to command helper functions.1595 * @param pVM Pointer to the current VM (if any).1596 * @param paArgs Pointer to (readonly) array of arguments.1597 * @param cArgs Number of arguments in the array.1598 */1599 static DECLCALLBACK(int) dbgcCmdUnassemble(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1600 {1601 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1602 1603 /*1604 * Validate input.1605 */1606 if ( cArgs > 11607 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))1608 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");1609 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))1610 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");1611 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))1612 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");1613 1614 /*1615 * Find address.1616 */1617 unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS;1618 if (!cArgs)1619 {1620 if (!DBGCVAR_ISPOINTER(pDbgc->DisasmPos.enmType))1621 {1622 pDbgc->DisasmPos.enmType = DBGCVAR_TYPE_GC_FAR;1623 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);1624 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM);1625 if (pDbgc->fRegCtxGuest)1626 fFlags |= DBGF_DISAS_FLAGS_CURRENT_GUEST;1627 else1628 fFlags |= DBGF_DISAS_FLAGS_CURRENT_HYPER;1629 }1630 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_NONE;1631 }1632 else1633 pDbgc->DisasmPos = paArgs[0];1634 1635 /*1636 * Range.1637 */1638 switch (pDbgc->DisasmPos.enmRangeType)1639 {1640 case DBGCVAR_RANGE_NONE:1641 pDbgc->DisasmPos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;1642 pDbgc->DisasmPos.u64Range = 10;1643 break;1644 1645 case DBGCVAR_RANGE_ELEMENTS:1646 if (pDbgc->DisasmPos.u64Range > 2048)1647 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");1648 break;1649 1650 case DBGCVAR_RANGE_BYTES:1651 if (pDbgc->DisasmPos.u64Range > 65536)1652 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");1653 break;1654 1655 default:1656 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType);1657 }1658 1659 /*1660 * Convert physical and host addresses to guest addresses.1661 */1662 int rc;1663 switch (pDbgc->DisasmPos.enmType)1664 {1665 case DBGCVAR_TYPE_GC_FLAT:1666 case DBGCVAR_TYPE_GC_FAR:1667 break;1668 case DBGCVAR_TYPE_GC_PHYS:1669 case DBGCVAR_TYPE_HC_FLAT:1670 case DBGCVAR_TYPE_HC_PHYS:1671 case DBGCVAR_TYPE_HC_FAR:1672 {1673 DBGCVAR VarTmp;1674 rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &pDbgc->DisasmPos);1675 if (VBOX_FAILURE(rc))1676 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Vrc .\n", pDbgc->DisasmPos, rc);1677 pDbgc->DisasmPos = VarTmp;1678 break;1679 }1680 default: AssertFailed(); break;1681 }1682 1683 /*1684 * Print address.1685 * todo: Change to list near.1686 */1687 #if 01688 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DisasmPos);1689 if (VBOX_FAILURE(rc))1690 return rc;1691 #endif1692 1693 /*1694 * Do the disassembling.1695 */1696 unsigned cTries = 32;1697 int iRangeLeft = (int)pDbgc->DisasmPos.u64Range;1698 if (iRangeLeft == 0) /* klugde for 'r'. */1699 iRangeLeft = -1;1700 for (;;)1701 {1702 /*1703 * Disassemble the instruction.1704 */1705 char szDis[256];1706 uint32_t cbInstr = 1;1707 if (pDbgc->DisasmPos.enmType == DBGCVAR_TYPE_GC_FLAT)1708 rc = DBGFR3DisasInstrEx(pVM, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, &szDis[0], sizeof(szDis), &cbInstr);1709 else1710 rc = DBGFR3DisasInstrEx(pVM, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, &szDis[0], sizeof(szDis), &cbInstr);1711 if (VBOX_SUCCESS(rc))1712 {1713 /* print it */1714 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-16DV %s\n", &pDbgc->DisasmPos, &szDis[0]);1715 if (VBOX_FAILURE(rc))1716 return rc;1717 }1718 else1719 {1720 /* bitch. */1721 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");1722 if (VBOX_FAILURE(rc))1723 return rc;1724 if (cTries-- > 0)1725 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Too many disassembly failures. Giving up.\n");1726 cbInstr = 1;1727 }1728 1729 /* advance */1730 if (iRangeLeft < 0) /* 'r' */1731 break;1732 if (pDbgc->DisasmPos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)1733 iRangeLeft--;1734 else1735 iRangeLeft -= cbInstr;1736 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DisasmPos, "(%Dv) + %x", &pDbgc->DisasmPos, cbInstr);1737 if (VBOX_FAILURE(rc))1738 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DisasmPos, cbInstr);1739 if (iRangeLeft <= 0)1740 break;1741 fFlags &= ~(DBGF_DISAS_FLAGS_CURRENT_GUEST | DBGF_DISAS_FLAGS_CURRENT_HYPER);1742 }1743 1744 NOREF(pCmd); NOREF(pResult);1745 return 0;1746 }1747 1748 1749 /**1750 * The 'ls' command.1751 *1752 * @returns VBox status.1753 * @param pCmd Pointer to the command descriptor (as registered).1754 * @param pCmdHlp Pointer to command helper functions.1755 * @param pVM Pointer to the current VM (if any).1756 * @param paArgs Pointer to (readonly) array of arguments.1757 * @param cArgs Number of arguments in the array.1758 */1759 static DECLCALLBACK(int) dbgcCmdListSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1760 {1761 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1762 1763 /*1764 * Validate input.1765 */1766 if ( cArgs > 11767 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))1768 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");1769 if (!pVM && !cArgs && !DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))1770 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Don't know where to start disassembling...\n");1771 if (!pVM && cArgs && DBGCVAR_ISGCPOINTER(paArgs[0].enmType))1772 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: GC address but no VM.\n");1773 1774 /*1775 * Find address.1776 */1777 if (!cArgs)1778 {1779 if (!DBGCVAR_ISPOINTER(pDbgc->SourcePos.enmType))1780 {1781 pDbgc->SourcePos.enmType = DBGCVAR_TYPE_GC_FAR;1782 pDbgc->SourcePos.u.GCFar.off = pDbgc->fRegCtxGuest ? CPUMGetGuestEIP(pVM) : CPUMGetHyperEIP(pVM);1783 pDbgc->SourcePos.u.GCFar.sel = pDbgc->fRegCtxGuest ? CPUMGetGuestCS(pVM) : CPUMGetHyperCS(pVM);1784 }1785 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_NONE;1786 }1787 else1788 pDbgc->SourcePos = paArgs[0];1789 1790 /*1791 * Ensure the the source address is flat GC.1792 */1793 switch (pDbgc->SourcePos.enmType)1794 {1795 case DBGCVAR_TYPE_GC_FLAT:1796 break;1797 case DBGCVAR_TYPE_GC_PHYS:1798 case DBGCVAR_TYPE_GC_FAR:1799 case DBGCVAR_TYPE_HC_FLAT:1800 case DBGCVAR_TYPE_HC_PHYS:1801 case DBGCVAR_TYPE_HC_FAR:1802 {1803 int rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "%%(%Dv)", &pDbgc->SourcePos);1804 if (VBOX_FAILURE(rc))1805 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid address or address type. (rc=%d)\n", rc);1806 break;1807 }1808 default: AssertFailed(); break;1809 }1810 1811 /*1812 * Range.1813 */1814 switch (pDbgc->SourcePos.enmRangeType)1815 {1816 case DBGCVAR_RANGE_NONE:1817 pDbgc->SourcePos.enmRangeType = DBGCVAR_RANGE_ELEMENTS;1818 pDbgc->SourcePos.u64Range = 10;1819 break;1820 1821 case DBGCVAR_RANGE_ELEMENTS:1822 if (pDbgc->SourcePos.u64Range > 2048)1823 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many lines requested. Max is 2048 lines.\n");1824 break;1825 1826 case DBGCVAR_RANGE_BYTES:1827 if (pDbgc->SourcePos.u64Range > 65536)1828 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");1829 break;1830 1831 default:1832 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);1833 }1834 1835 /*1836 * Do the disassembling.1837 */1838 bool fFirst = 1;1839 DBGFLINE LinePrev = { 0, 0, "" };1840 int iRangeLeft = (int)pDbgc->SourcePos.u64Range;1841 if (iRangeLeft == 0) /* klugde for 'r'. */1842 iRangeLeft = -1;1843 for (;;)1844 {1845 /*1846 * Get line info.1847 */1848 DBGFLINE Line;1849 RTGCINTPTR off;1850 int rc = DBGFR3LineByAddr(pVM, pDbgc->SourcePos.u.GCFlat, &off, &Line);1851 if (VBOX_FAILURE(rc))1852 return VINF_SUCCESS;1853 1854 unsigned cLines = 0;1855 if (memcmp(&Line, &LinePrev, sizeof(Line)))1856 {1857 /*1858 * Print filenamename1859 */1860 if (!fFirst && strcmp(Line.szFilename, LinePrev.szFilename))1861 fFirst = true;1862 if (fFirst)1863 {1864 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "[%s @ %d]\n", Line.szFilename, Line.uLineNo);1865 if (VBOX_FAILURE(rc))1866 return rc;1867 }1868 1869 /*1870 * Try open the file and read the line.1871 */1872 FILE *phFile = fopen(Line.szFilename, "r");1873 if (phFile)1874 {1875 /* Skip ahead to the desired line. */1876 char szLine[4096];1877 unsigned cBefore = fFirst ? RT_MIN(2, Line.uLineNo - 1) : Line.uLineNo - LinePrev.uLineNo - 1;1878 if (cBefore > 7)1879 cBefore = 0;1880 unsigned cLeft = Line.uLineNo - cBefore;1881 while (cLeft > 0)1882 {1883 szLine[0] = '\0';1884 if (!fgets(szLine, sizeof(szLine), phFile))1885 break;1886 cLeft--;1887 }1888 if (!cLeft)1889 {1890 /* print the before lines */1891 for (;;)1892 {1893 size_t cch = strlen(szLine);1894 while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || isspace(szLine[cch - 1])) )1895 szLine[--cch] = '\0';1896 if (cBefore-- <= 0)1897 break;1898 1899 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %4d: %s\n", Line.uLineNo - cBefore - 1, szLine);1900 szLine[0] = '\0';1901 fgets(szLine, sizeof(szLine), phFile);1902 cLines++;1903 }1904 /* print the actual line */1905 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08llx %4d: %s\n", Line.Address, Line.uLineNo, szLine);1906 }1907 fclose(phFile);1908 if (VBOX_FAILURE(rc))1909 return rc;1910 fFirst = false;1911 }1912 else1913 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);1914 1915 LinePrev = Line;1916 }1917 1918 1919 /*1920 * Advance1921 */1922 if (iRangeLeft < 0) /* 'r' */1923 break;1924 if (pDbgc->SourcePos.enmRangeType == DBGCVAR_RANGE_ELEMENTS)1925 iRangeLeft -= cLines;1926 else1927 iRangeLeft -= 1;1928 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->SourcePos, "(%Dv) + %x", &pDbgc->SourcePos, 1);1929 if (VBOX_FAILURE(rc))1930 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->SourcePos, 1);1931 if (iRangeLeft <= 0)1932 break;1933 }1934 1935 NOREF(pCmd); NOREF(pResult);1936 return 0;1937 }1938 1939 1940 /**1941 * The 'r' command.1942 *1943 * @returns VBox status.1944 * @param pCmd Pointer to the command descriptor (as registered).1945 * @param pCmdHlp Pointer to command helper functions.1946 * @param pVM Pointer to the current VM (if any).1947 * @param paArgs Pointer to (readonly) array of arguments.1948 * @param cArgs Number of arguments in the array.1949 */1950 static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)1951 {1952 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1953 1954 if (pDbgc->fRegCtxGuest)1955 return dbgcCmdRegGuest(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);1956 else1957 return dbgcCmdRegHyper(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult);1958 }1959 1960 1961 /**1962 * Common worker for the dbgcCmdReg*() commands.1963 *1964 * @returns VBox status.1965 * @param pCmd Pointer to the command descriptor (as registered).1966 * @param pCmdHlp Pointer to command helper functions.1967 * @param pVM Pointer to the current VM (if any).1968 * @param paArgs Pointer to (readonly) array of arguments.1969 * @param cArgs Number of arguments in the array.1970 * @param pszPrefix The symbol prefix.1971 */1972 static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult, const char *pszPrefix)1973 {1974 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);1975 1976 /*1977 * cArgs == 0: Show all1978 */1979 if (cArgs == 0)1980 {1981 /*1982 * Get register context.1983 */1984 int rc;1985 PCPUMCTX pCtx;1986 PCCPUMCTXCORE pCtxCore;1987 if (!*pszPrefix)1988 {1989 rc = CPUMQueryGuestCtxPtr(pVM, &pCtx);1990 pCtxCore = CPUMGetGuestCtxCore(pVM);1991 }1992 else1993 {1994 rc = CPUMQueryHyperCtxPtr(pVM, &pCtx);1995 pCtxCore = CPUMGetHyperCtxCore(pVM);1996 }1997 if (VBOX_FAILURE(rc))1998 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Getting register context\n");1999 2000 /*2001 * Format the flags.2002 */2003 static struct2004 {2005 const char *pszSet; const char *pszClear; uint32_t fFlag;2006 } aFlags[] =2007 {2008 { "vip",NULL, X86_EFL_VIP },2009 { "vif",NULL, X86_EFL_VIF },2010 { "ac", NULL, X86_EFL_AC },2011 { "vm", NULL, X86_EFL_VM },2012 { "rf", NULL, X86_EFL_RF },2013 { "nt", NULL, X86_EFL_NT },2014 { "ov", "nv", X86_EFL_OF },2015 { "dn", "up", X86_EFL_DF },2016 { "ei", "di", X86_EFL_IF },2017 { "tf", NULL, X86_EFL_TF },2018 { "nt", "pl", X86_EFL_SF },2019 { "nz", "zr", X86_EFL_ZF },2020 { "ac", "na", X86_EFL_AF },2021 { "po", "pe", X86_EFL_PF },2022 { "cy", "nc", X86_EFL_CF },2023 };2024 char szEFlags[80];2025 char *psz = szEFlags;2026 uint32_t efl = pCtxCore->eflags.u32;2027 for (unsigned i = 0; i < ELEMENTS(aFlags); i++)2028 {2029 const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;2030 if (pszAdd)2031 {2032 strcpy(psz, pszAdd);2033 psz += strlen(pszAdd);2034 *psz++ = ' ';2035 }2036 }2037 psz[-1] = '\0';2038 2039 2040 /*2041 * Format the registers.2042 */2043 if (pDbgc->fRegTerse)2044 {2045 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,2046 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"2047 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"2048 "%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",2049 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,2050 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,2051 pszPrefix, (RTSEL)pCtxCore->cs, pszPrefix, (RTSEL)pCtxCore->ds, pszPrefix, (RTSEL)pCtxCore->es,2052 pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);2053 }2054 else2055 {2056 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,2057 "%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"2058 "%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"2059 "%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"2060 "%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"2061 "%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"2062 "%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"2063 "%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"2064 "%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"2065 "%sgdtr=%08x:%04x %sidtr=%08x:%04x %seflags=%08x\n"2066 "%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"2067 "%str ={%04x base=%08x limit=%08x flags=%08x}\n"2068 "%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"2069 "%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"2070 ,2071 pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->esi, pszPrefix, pCtxCore->edi,2072 pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,2073 pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0, pszPrefix, pCtx->dr1,2074 pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2, pszPrefix, pCtx->dr3,2075 pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4, pszPrefix, pCtx->dr5,2076 pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6, pszPrefix, pCtx->dr7,2077 pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,2078 pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,2079 pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,2080 pszPrefix, (RTSEL)pCtx->ldtr, pCtx->ldtrHid.u32Base, pCtx->ldtrHid.u32Limit, pCtx->ldtrHid.Attr.u,2081 pszPrefix, (RTSEL)pCtx->tr, pCtx->trHid.u32Base, pCtx->trHid.u32Limit, pCtx->trHid.Attr.u,2082 pszPrefix, pCtx->SysEnter.cs, pCtx->SysEnter.eip, pCtx->SysEnter.esp,2083 pszPrefix, pCtx->fpu.FCW, pszPrefix, pCtx->fpu.FSW, pszPrefix, pCtx->fpu.FTW);2084 }2085 2086 /*2087 * Disassemble one instruction at cs:eip.2088 */2089 return pCmdHlp->pfnExec(pCmdHlp, "u %04x:%08x L 0", pCtx->cs, pCtx->eip);2090 }2091 2092 /*2093 * cArgs == 1: Show the register.2094 * cArgs == 2: Modify the register.2095 */2096 if ( cArgs == 12097 || cArgs == 2)2098 {2099 /* locate the register symbol. */2100 const char *pszReg = paArgs[0].u.pszString;2101 if ( *pszPrefix2102 && pszReg[0] != *pszPrefix)2103 {2104 /* prepend the prefix. */2105 char *psz = (char *)alloca(strlen(pszReg) + 2);2106 psz[0] = *pszPrefix;2107 strcpy(psz + 1, paArgs[0].u.pszString);2108 pszReg = psz;2109 }2110 PCDBGCSYM pSym = dbgcLookupRegisterSymbol(pDbgc, pszReg);2111 if (!pSym)2112 return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);2113 2114 /* show the register */2115 if (cArgs == 1)2116 {2117 DBGCVAR Var;2118 memset(&Var, 0, sizeof(Var));2119 int rc = pSym->pfnGet(pSym, pCmdHlp, DBGCVAR_TYPE_NUMBER, &Var);2120 if (VBOX_FAILURE(rc))2121 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed getting value for register '%s'.\n", pszReg);2122 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s=%Dv\n", pszReg, &Var);2123 }2124 2125 /* change the register */2126 int rc = pSym->pfnSet(pSym, pCmdHlp, &paArgs[1]);2127 if (VBOX_FAILURE(rc))2128 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Failed setting value for register '%s'.\n", pszReg);2129 return VINF_SUCCESS;2130 }2131 2132 2133 NOREF(pCmd); NOREF(paArgs); NOREF(pResult);2134 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Huh? cArgs=%d Expected 0, 1 or 2!\n", cArgs);2135 }2136 2137 2138 /**2139 * The 'rg' command.2140 *2141 * @returns VBox status.2142 * @param pCmd Pointer to the command descriptor (as registered).2143 * @param pCmdHlp Pointer to command helper functions.2144 * @param pVM Pointer to the current VM (if any).2145 * @param paArgs Pointer to (readonly) array of arguments.2146 * @param cArgs Number of arguments in the array.2147 */2148 static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2149 {2150 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, "");2151 }2152 2153 2154 /**2155 * The 'rh' command.2156 *2157 * @returns VBox status.2158 * @param pCmd Pointer to the command descriptor (as registered).2159 * @param pCmdHlp Pointer to command helper functions.2160 * @param pVM Pointer to the current VM (if any).2161 * @param paArgs Pointer to (readonly) array of arguments.2162 * @param cArgs Number of arguments in the array.2163 */2164 static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2165 {2166 return dbgcCmdRegCommon(pCmd, pCmdHlp, pVM, paArgs, cArgs, pResult, ".");2167 }2168 2169 2170 /**2171 * The 'rt' command.2172 *2173 * @returns VBox status.2174 * @param pCmd Pointer to the command descriptor (as registered).2175 * @param pCmdHlp Pointer to command helper functions.2176 * @param pVM Pointer to the current VM (if any).2177 * @param paArgs Pointer to (readonly) array of arguments.2178 * @param cArgs Number of arguments in the array.2179 */2180 static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2181 {2182 NOREF(pCmd); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2183 2184 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2185 pDbgc->fRegTerse = !pDbgc->fRegTerse;2186 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");2187 }2188 2189 2190 /**2191 * The 't' command.2192 *2193 * @returns VBox status.2194 * @param pCmd Pointer to the command descriptor (as registered).2195 * @param pCmdHlp Pointer to command helper functions.2196 * @param pVM Pointer to the current VM (if any).2197 * @param paArgs Pointer to (readonly) array of arguments.2198 * @param cArgs Number of arguments in the array.2199 */2200 static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2201 {2202 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2203 2204 int rc = DBGFR3Step(pVM);2205 if (VBOX_SUCCESS(rc))2206 pDbgc->fReady = false;2207 else2208 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);2209 2210 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2211 return rc;2212 }2213 2214 2215 /**2216 * The 'k', 'kg' and 'kh' commands.2217 *2218 * @returns VBox status.2219 * @param pCmd Pointer to the command descriptor (as registered).2220 * @param pCmdHlp Pointer to command helper functions.2221 * @param pVM Pointer to the current VM (if any).2222 * @param paArgs Pointer to (readonly) array of arguments.2223 * @param cArgs Number of arguments in the array.2224 */2225 static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2226 {2227 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2228 2229 /*2230 * Figure which context we're called for.2231 */2232 bool fGuest = pCmd->pszCmd[1] == 'g'2233 || (!pCmd->pszCmd[1] && pDbgc->fRegCtxGuest);2234 2235 2236 DBGFSTACKFRAME Frame;2237 memset(&Frame, 0, sizeof(Frame));2238 int rc;2239 if (fGuest)2240 rc = DBGFR3StackWalkBeginGuest(pVM, &Frame);2241 else2242 rc = DBGFR3StackWalkBeginHyper(pVM, &Frame);2243 if (VBOX_FAILURE(rc))2244 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to begin stack walk, rc=%Vrc\n", rc);2245 2246 /*2247 * Print header.2248 * 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol2249 */2250 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");2251 if (VBOX_FAILURE(rc))2252 return rc;2253 do2254 {2255 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",2256 (uint32_t)Frame.AddrFrame.off,2257 (uint32_t)Frame.AddrReturnFrame.off,2258 (uint32_t)Frame.AddrReturnPC.Sel,2259 (uint32_t)Frame.AddrReturnPC.off,2260 Frame.Args.au32[0],2261 Frame.Args.au32[1],2262 Frame.Args.au32[2],2263 Frame.Args.au32[3]);2264 if (VBOX_FAILURE(rc))2265 return rc;2266 if (!Frame.pSymPC)2267 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %RTsel:%08RGv", Frame.AddrPC.Sel, Frame.AddrPC.off);2268 else2269 {2270 RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */2271 if (offDisp > 0)2272 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s+%llx", Frame.pSymPC->szName, (int64_t)offDisp);2273 else if (offDisp < 0)2274 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s-%llx", Frame.pSymPC->szName, -(int64_t)offDisp);2275 else2276 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " %s", Frame.pSymPC->szName);2277 }2278 if (VBOX_SUCCESS(rc) && Frame.pLinePC)2279 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);2280 if (VBOX_SUCCESS(rc))2281 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");2282 if (VBOX_FAILURE(rc))2283 return rc;2284 2285 /* next */2286 rc = DBGFR3StackWalkNext(pVM, &Frame);2287 } while (VBOX_SUCCESS(rc));2288 2289 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);2290 return VINF_SUCCESS;2291 }2292 2293 2294 static int dbgcCmdDumpDTWorker64(PDBGCCMDHLP /*pCmdHlp*/, PCX86DESC64 /*pDesc*/, unsigned /*iEntry*/, bool /* fHyper */, bool * /*fDblEntry*/)2295 {2296 /* GUEST64 */2297 return VINF_SUCCESS;2298 }2299 2300 2301 /**2302 * Wroker function that displays one descriptor entry (GDT, LDT, IDT).2303 *2304 * @returns pfnPrintf status code.2305 * @param pCmdHlp The DBGC command helpers.2306 * @param pDesc The descriptor to display.2307 * @param iEntry The descriptor entry number.2308 * @param fHyper Whether the selector belongs to the hypervisor or not.2309 */2310 static int dbgcCmdDumpDTWorker32(PDBGCCMDHLP pCmdHlp, PCX86DESC pDesc, unsigned iEntry, bool fHyper)2311 {2312 int rc;2313 2314 const char *pszHyper = fHyper ? " HYPER" : "";2315 const char *pszPresent = pDesc->Gen.u1Present ? "P " : "NP";2316 if (pDesc->Gen.u1DescType)2317 {2318 static const char * const s_apszTypes[] =2319 {2320 "DataRO", /* 0 Read-Only */2321 "DataRO", /* 1 Read-Only - Accessed */2322 "DataRW", /* 2 Read/Write */2323 "DataRW", /* 3 Read/Write - Accessed */2324 "DownRO", /* 4 Expand-down, Read-Only */2325 "DownRO", /* 5 Expand-down, Read-Only - Accessed */2326 "DownRW", /* 6 Expand-down, Read/Write */2327 "DownRO", /* 7 Expand-down, Read/Write - Accessed */2328 "CodeEO", /* 8 Execute-Only */2329 "CodeEO", /* 9 Execute-Only - Accessed */2330 "CodeER", /* A Execute/Readable */2331 "CodeER", /* B Execute/Readable - Accessed */2332 "ConfE0", /* C Conforming, Execute-Only */2333 "ConfE0", /* D Conforming, Execute-Only - Accessed */2334 "ConfER", /* E Conforming, Execute/Readable */2335 "ConfER" /* F Conforming, Execute/Readable - Accessed */2336 };2337 const char *pszAccessed = pDesc->Gen.u4Type & RT_BIT(0) ? "A " : "NA";2338 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";2339 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";2340 uint32_t u32Base = pDesc->Gen.u16BaseLow2341 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)2342 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);2343 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);2344 if (pDesc->Gen.u1Granularity)2345 cbLimit <<= PAGE_SHIFT;2346 2347 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",2348 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,2349 pDesc->Gen.u2Dpl, pszPresent, pszAccessed, pszGranularity, pszBig,2350 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved, pszHyper);2351 }2352 else2353 {2354 static const char * const s_apszTypes[] =2355 {2356 "Ill-0 ", /* 0 0000 Reserved (Illegal) */2357 "Tss16A", /* 1 0001 Available 16-bit TSS */2358 "LDT ", /* 2 0010 LDT */2359 "Tss16B", /* 3 0011 Busy 16-bit TSS */2360 "Call16", /* 4 0100 16-bit Call Gate */2361 "TaskG ", /* 5 0101 Task Gate */2362 "Int16 ", /* 6 0110 16-bit Interrupt Gate */2363 "Trap16", /* 7 0111 16-bit Trap Gate */2364 "Ill-8 ", /* 8 1000 Reserved (Illegal) */2365 "Tss32A", /* 9 1001 Available 32-bit TSS */2366 "Ill-A ", /* A 1010 Reserved (Illegal) */2367 "Tss32B", /* B 1011 Busy 32-bit TSS */2368 "Call32", /* C 1100 32-bit Call Gate */2369 "Ill-D ", /* D 1101 Reserved (Illegal) */2370 "Int32 ", /* E 1110 32-bit Interrupt Gate */2371 "Trap32" /* F 1111 32-bit Trap Gate */2372 };2373 switch (pDesc->Gen.u4Type)2374 {2375 /* raw */2376 case X86_SEL_TYPE_SYS_UNDEFINED:2377 case X86_SEL_TYPE_SYS_UNDEFINED2:2378 case X86_SEL_TYPE_SYS_UNDEFINED4:2379 case X86_SEL_TYPE_SYS_UNDEFINED3:2380 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s %.8Rhxs DPL=%d %s%s\n",2381 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc,2382 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2383 break;2384 2385 case X86_SEL_TYPE_SYS_286_TSS_AVAIL:2386 case X86_SEL_TYPE_SYS_386_TSS_AVAIL:2387 case X86_SEL_TYPE_SYS_286_TSS_BUSY:2388 case X86_SEL_TYPE_SYS_386_TSS_BUSY:2389 case X86_SEL_TYPE_SYS_LDT:2390 {2391 const char *pszGranularity = pDesc->Gen.u1Granularity ? "G" : " ";2392 const char *pszBusy = pDesc->Gen.u4Type & RT_BIT(1) ? "B " : "NB";2393 const char *pszBig = pDesc->Gen.u1DefBig ? "BIG" : " ";2394 uint32_t u32Base = pDesc->Gen.u16BaseLow2395 | ((uint32_t)pDesc->Gen.u8BaseHigh1 << 16)2396 | ((uint32_t)pDesc->Gen.u8BaseHigh2 << 24);2397 uint32_t cbLimit = pDesc->Gen.u16LimitLow | (pDesc->Gen.u4LimitHigh << 16);2398 if (pDesc->Gen.u1Granularity)2399 cbLimit <<= PAGE_SHIFT;2400 2401 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Bas=%08x Lim=%08x DPL=%d %s %s %s %s AVL=%d R=%d%s\n",2402 iEntry, s_apszTypes[pDesc->Gen.u4Type], u32Base, cbLimit,2403 pDesc->Gen.u2Dpl, pszPresent, pszBusy, pszGranularity, pszBig,2404 pDesc->Gen.u1Available, pDesc->Gen.u1Reserved | (pDesc->Gen.u1DefBig << 1),2405 pszHyper);2406 break;2407 }2408 2409 case X86_SEL_TYPE_SYS_TASK_GATE:2410 {2411 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s TSS=%04x DPL=%d %s%s\n",2412 iEntry, s_apszTypes[pDesc->Gen.u4Type], pDesc->au16[1],2413 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2414 break;2415 }2416 2417 case X86_SEL_TYPE_SYS_286_CALL_GATE:2418 case X86_SEL_TYPE_SYS_386_CALL_GATE:2419 {2420 unsigned cParams = pDesc->au8[0] & 0x1f;2421 const char *pszCountOf = pDesc->Gen.u4Type & RT_BIT(3) ? "DC" : "WC";2422 RTSEL sel = pDesc->au16[1];2423 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);2424 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s %s=%d%s\n",2425 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,2426 pDesc->Gen.u2Dpl, pszPresent, pszCountOf, cParams, pszHyper);2427 break;2428 }2429 2430 case X86_SEL_TYPE_SYS_286_INT_GATE:2431 case X86_SEL_TYPE_SYS_386_INT_GATE:2432 case X86_SEL_TYPE_SYS_286_TRAP_GATE:2433 case X86_SEL_TYPE_SYS_386_TRAP_GATE:2434 {2435 RTSEL sel = pDesc->au16[1];2436 uint32_t off = pDesc->au16[0] | ((uint32_t)pDesc->au16[3] << 16);2437 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %s Sel:Off=%04x:%08x DPL=%d %s%s\n",2438 iEntry, s_apszTypes[pDesc->Gen.u4Type], sel, off,2439 pDesc->Gen.u2Dpl, pszPresent, pszHyper);2440 break;2441 }2442 2443 /* impossible, just it's necessary to keep gcc happy. */2444 default:2445 return VINF_SUCCESS;2446 }2447 }2448 return rc;2449 }2450 2451 2452 /**2453 * The 'dg', 'dga', 'dl' and 'dla' commands.2454 *2455 * @returns VBox status.2456 * @param pCmd Pointer to the command descriptor (as registered).2457 * @param pCmdHlp Pointer to command helper functions.2458 * @param pVM Pointer to the current VM (if any).2459 * @param paArgs Pointer to (readonly) array of arguments.2460 * @param cArgs Number of arguments in the array.2461 */2462 static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2463 {2464 /*2465 * Validate input.2466 */2467 if (!pVM)2468 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2469 2470 /*2471 * Get the CPU mode, check which command variation this is2472 * and fix a default parameter if needed.2473 */2474 CPUMMODE enmMode = CPUMGetGuestMode(pVM);2475 bool fGdt = pCmd->pszCmd[1] == 'g';2476 bool fAll = pCmd->pszCmd[2] == 'a';2477 2478 DBGCVAR Var;2479 if (!cArgs)2480 {2481 cArgs = 1;2482 paArgs = &Var;2483 Var.enmType = DBGCVAR_TYPE_NUMBER;2484 Var.u.u64Number = fGdt ? 0 : 4;2485 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;2486 Var.u64Range = 1024;2487 }2488 2489 /*2490 * Process the arguments.2491 */2492 for (unsigned i = 0; i < cArgs; i++)2493 {2494 /*2495 * Retrive the selector value from the argument.2496 * The parser may confuse pointers and numbers if more than one2497 * argument is given, that that into account.2498 */2499 /* check that what've got makes sense as we don't trust the parser yet. */2500 if ( paArgs[i].enmType != DBGCVAR_TYPE_NUMBER2501 && !DBGCVAR_ISPOINTER(paArgs[i].enmType))2502 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number or pointer type but %d.\n", i, paArgs[i].enmType);2503 uint64_t u64;2504 unsigned cSels = 1;2505 switch (paArgs[i].enmType)2506 {2507 case DBGCVAR_TYPE_NUMBER:2508 u64 = paArgs[i].u.u64Number;2509 if (paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE)2510 cSels = RT_MIN(paArgs[i].u64Range, 1024);2511 break;2512 case DBGCVAR_TYPE_GC_FAR: u64 = paArgs[i].u.GCFar.sel; break;2513 case DBGCVAR_TYPE_GC_FLAT: u64 = paArgs[i].u.GCFlat; break;2514 case DBGCVAR_TYPE_GC_PHYS: u64 = paArgs[i].u.GCPhys; break;2515 case DBGCVAR_TYPE_HC_FAR: u64 = paArgs[i].u.HCFar.sel; break;2516 case DBGCVAR_TYPE_HC_FLAT: u64 = (uintptr_t)paArgs[i].u.pvHCFlat; break;2517 case DBGCVAR_TYPE_HC_PHYS: u64 = paArgs[i].u.HCPhys; break;2518 default: u64 = _64K; break;2519 }2520 if (u64 < _64K)2521 {2522 unsigned Sel = (RTSEL)u64;2523 2524 /*2525 * Dump the specified range.2526 */2527 bool fSingle = cSels == 1;2528 while ( cSels-- > 02529 && Sel < _64K)2530 {2531 SELMSELINFO SelInfo;2532 int rc = SELMR3GetSelectorInfo(pVM, Sel, &SelInfo);2533 if (RT_SUCCESS(rc))2534 {2535 if (SelInfo.fRealMode)2536 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x RealM Bas=%04x Lim=%04x\n",2537 Sel, (unsigned)SelInfo.GCPtrBase, (unsigned)SelInfo.cbLimit);2538 else if (fAll || fSingle || SelInfo.Raw.Gen.u1Present)2539 {2540 if (enmMode == CPUMMODE_PROTECTED)2541 rc = dbgcCmdDumpDTWorker32(pCmdHlp, (PX86DESC)&SelInfo.Raw, Sel, SelInfo.fHyper);2542 else2543 {2544 bool fDblSkip = false;2545 rc = dbgcCmdDumpDTWorker64(pCmdHlp, (PX86DESC64)&SelInfo.Raw, Sel, SelInfo.fHyper, &fDblSkip);2546 if (fDblSkip)2547 Sel += 4;2548 }2549 }2550 }2551 else2552 {2553 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %Vrc\n", Sel, rc);2554 if (!fAll)2555 return rc;2556 }2557 if (RT_FAILURE(rc))2558 return rc;2559 2560 /* next */2561 Sel += 4;2562 }2563 }2564 else2565 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds\n", u64);2566 }2567 2568 NOREF(pResult);2569 return VINF_SUCCESS;2570 }2571 2572 2573 /**2574 * The 'di' and 'dia' commands.2575 *2576 * @returns VBox status.2577 * @param pCmd Pointer to the command descriptor (as registered).2578 * @param pCmdHlp Pointer to command helper functions.2579 * @param pVM Pointer to the current VM (if any).2580 * @param paArgs Pointer to (readonly) array of arguments.2581 * @param cArgs Number of arguments in the array.2582 */2583 static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2584 {2585 /*2586 * Validate input.2587 */2588 if (!pVM)2589 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2590 2591 /*2592 * Establish some stuff like the current IDTR and CPU mode,2593 * and fix a default parameter.2594 */2595 uint16_t cbLimit;2596 RTGCUINTPTR GCPtrBase = CPUMGetGuestIDTR(pVM, &cbLimit);2597 CPUMMODE enmMode = CPUMGetGuestMode(pVM);2598 unsigned cbEntry;2599 switch (enmMode)2600 {2601 case CPUMMODE_REAL: cbEntry = sizeof(RTFAR16); break;2602 case CPUMMODE_PROTECTED: cbEntry = sizeof(X86DESC); break;2603 case CPUMMODE_LONG: cbEntry = sizeof(X86DESC64); break;2604 default:2605 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid CPU mode %d.\n", enmMode);2606 }2607 2608 bool fAll = pCmd->pszCmd[2] == 'a';2609 DBGCVAR Var;2610 if (!cArgs)2611 {2612 cArgs = 1;2613 paArgs = &Var;2614 Var.enmType = DBGCVAR_TYPE_NUMBER;2615 Var.u.u64Number = 0;2616 Var.enmRangeType = DBGCVAR_RANGE_ELEMENTS;2617 Var.u64Range = 256;2618 }2619 2620 /*2621 * Process the arguments.2622 */2623 for (unsigned i = 0; i < cArgs; i++)2624 {2625 /* check that what've got makes sense as we don't trust the parser yet. */2626 if (paArgs[i].enmType != DBGCVAR_TYPE_NUMBER)2627 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: arg #%u isn't of number type but %d.\n", i, paArgs[i].enmType);2628 if (paArgs[i].u.u64Number < 256)2629 {2630 RTGCUINTPTR iInt = (RTGCUINTPTR)paArgs[i].u.u64Number;2631 unsigned cInts = paArgs[i].enmRangeType != DBGCVAR_RANGE_NONE2632 ? paArgs[i].u64Range2633 : 1;2634 bool fSingle = cInts == 1;2635 while ( cInts-- > 02636 && iInt < 256)2637 {2638 /*2639 * Try read it.2640 */2641 union2642 {2643 RTFAR16 Real;2644 X86DESC Prot;2645 X86DESC64 Long;2646 } u;2647 if (iInt * cbEntry + (cbEntry - 1) > cbLimit)2648 {2649 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x not within the IDT\n", (unsigned)iInt);2650 if (!fAll && !fSingle)2651 return VINF_SUCCESS;2652 }2653 DBGCVAR AddrVar;2654 AddrVar.enmType = DBGCVAR_TYPE_GC_FLAT;2655 AddrVar.u.GCFlat = GCPtrBase + iInt * cbEntry;2656 AddrVar.enmRangeType = DBGCVAR_RANGE_NONE;2657 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &u, cbEntry, &AddrVar, NULL);2658 if (VBOX_FAILURE(rc))2659 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading IDT entry %#04x.\n", (unsigned)iInt);2660 2661 /*2662 * Display it.2663 */2664 switch (enmMode)2665 {2666 case CPUMMODE_REAL:2667 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%04x %RTfp16\n", (unsigned)iInt, u.Real);2668 /** @todo resolve 16:16 IDTE to a symbol */2669 break;2670 case CPUMMODE_PROTECTED:2671 if (fAll || fSingle || u.Prot.Gen.u1Present)2672 rc = dbgcCmdDumpDTWorker32(pCmdHlp, &u.Prot, iInt, false);2673 break;2674 case CPUMMODE_LONG:2675 if (fAll || fSingle || u.Long.Gen.u1Present)2676 rc = dbgcCmdDumpDTWorker64(pCmdHlp, &u.Long, iInt, false, NULL);2677 break;2678 default: break; /* to shut up gcc */2679 }2680 if (RT_FAILURE(rc))2681 return rc;2682 2683 /* next */2684 iInt++;2685 }2686 }2687 else2688 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %llx is out of bounds (max 256)\n", paArgs[i].u.u64Number);2689 }2690 2691 NOREF(pResult);2692 return VINF_SUCCESS;2693 }2694 2695 2696 /**2697 * The 'da', 'dq', 'dd', 'dw' and 'db' commands.2698 *2699 * @returns VBox status.2700 * @param pCmd Pointer to the command descriptor (as registered).2701 * @param pCmdHlp Pointer to command helper functions.2702 * @param pVM Pointer to the current VM (if any).2703 * @param paArgs Pointer to (readonly) array of arguments.2704 * @param cArgs Number of arguments in the array.2705 */2706 static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2707 {2708 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2709 2710 /*2711 * Validate input.2712 */2713 if ( cArgs > 12714 || (cArgs == 1 && !DBGCVAR_ISPOINTER(paArgs[0].enmType)))2715 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");2716 if (!pVM)2717 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2718 2719 /*2720 * Figure out the element size.2721 */2722 unsigned cbElement;2723 bool fAscii = false;2724 switch (pCmd->pszCmd[1])2725 {2726 default:2727 case 'b': cbElement = 1; break;2728 case 'w': cbElement = 2; break;2729 case 'd': cbElement = 4; break;2730 case 'q': cbElement = 8; break;2731 case 'a':2732 cbElement = 1;2733 fAscii = true;2734 break;2735 case '\0':2736 fAscii = !!(pDbgc->cbDumpElement & 0x80000000);2737 cbElement = pDbgc->cbDumpElement & 0x7fffffff;2738 if (!cbElement)2739 cbElement = 1;2740 break;2741 }2742 2743 /*2744 * Find address.2745 */2746 if (!cArgs)2747 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_NONE;2748 else2749 pDbgc->DumpPos = paArgs[0];2750 2751 /*2752 * Range.2753 */2754 switch (pDbgc->DumpPos.enmRangeType)2755 {2756 case DBGCVAR_RANGE_NONE:2757 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;2758 pDbgc->DumpPos.u64Range = 0x60;2759 break;2760 2761 case DBGCVAR_RANGE_ELEMENTS:2762 if (pDbgc->DumpPos.u64Range > 2048)2763 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");2764 pDbgc->DumpPos.enmRangeType = DBGCVAR_RANGE_BYTES;2765 pDbgc->DumpPos.u64Range = (cbElement ? cbElement : 1) * pDbgc->DumpPos.u64Range;2766 break;2767 2768 case DBGCVAR_RANGE_BYTES:2769 if (pDbgc->DumpPos.u64Range > 65536)2770 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: The requested range is too big. Max is 64KB.\n");2771 break;2772 2773 default:2774 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);2775 }2776 2777 /*2778 * Do the dumping.2779 */2780 pDbgc->cbDumpElement = cbElement | (fAscii << 31);2781 int cbLeft = (int)pDbgc->DumpPos.u64Range;2782 uint8_t u8Prev = '\0';2783 for (;;)2784 {2785 /*2786 * Read memory.2787 */2788 char achBuffer[16];2789 size_t cbReq = RT_MIN((int)sizeof(achBuffer), cbLeft);2790 size_t cb = RT_MIN((int)sizeof(achBuffer), cbLeft);2791 int rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &achBuffer, cbReq, &pDbgc->DumpPos, &cb);2792 if (VBOX_FAILURE(rc))2793 {2794 if (u8Prev && u8Prev != '\n')2795 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");2796 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &pDbgc->DumpPos);2797 }2798 2799 /*2800 * Display it.2801 */2802 memset(&achBuffer[cb], 0, sizeof(achBuffer) - cb);2803 if (!fAscii)2804 {2805 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:", &pDbgc->DumpPos);2806 unsigned i;2807 for (i = 0; i < cb; i += cbElement)2808 {2809 const char *pszSpace = " ";2810 if (cbElement <= 2 && i == 8 && !fAscii)2811 pszSpace = "-";2812 switch (cbElement)2813 {2814 case 1: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%02x", pszSpace, *(uint8_t *)&achBuffer[i]); break;2815 case 2: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%04x", pszSpace, *(uint16_t *)&achBuffer[i]); break;2816 case 4: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%08x", pszSpace, *(uint32_t *)&achBuffer[i]); break;2817 case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;2818 }2819 }2820 2821 /* chars column */2822 if (pDbgc->cbDumpElement == 1)2823 {2824 while (i++ < sizeof(achBuffer))2825 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");2826 pCmdHlp->pfnPrintf(pCmdHlp, NULL, " ");2827 for (i = 0; i < cb; i += cbElement)2828 {2829 uint8_t u8 = *(uint8_t *)&achBuffer[i];2830 if (isprint(u8) && u8 < 127)2831 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);2832 else2833 pCmdHlp->pfnPrintf(pCmdHlp, NULL, ".");2834 }2835 }2836 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");2837 }2838 else2839 {2840 /*2841 * We print up to the first zero and stop there.2842 * Only printables + '\t' and '\n' are printed.2843 */2844 if (!u8Prev)2845 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV:\n", &pDbgc->DumpPos);2846 uint8_t u8 = '\0';2847 unsigned i;2848 for (i = 0; i < cb; i++)2849 {2850 u8Prev = u8;2851 u8 = *(uint8_t *)&achBuffer[i];2852 if ( u8 < 1272853 && ( isprint(u8)2854 || u8 == '\t'2855 || u8 == '\n'))2856 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%c", u8);2857 else if (!u8)2858 break;2859 else2860 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\\x%x", u8);2861 }2862 if (u8 == '\0')2863 cb = cbLeft = i + 1;2864 if (cbLeft - cb <= 0 && u8Prev != '\n')2865 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");2866 }2867 2868 /*2869 * Advance2870 */2871 cbLeft -= (int)cb;2872 rc = pCmdHlp->pfnEval(pCmdHlp, &pDbgc->DumpPos, "(%Dv) + %x", &pDbgc->DumpPos, cb);2873 if (VBOX_FAILURE(rc))2874 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Expression: (%Dv) + %x\n", &pDbgc->DumpPos, cb);2875 if (cbLeft <= 0)2876 break;2877 }2878 2879 NOREF(pCmd); NOREF(pResult);2880 return VINF_SUCCESS;2881 }2882 2883 2884 /**2885 * Best guess at which paging mode currently applies to the guest2886 * paging structures.2887 *2888 * This have to come up with a decent answer even when the guest2889 * is in non-paged protected mode or real mode.2890 *2891 * @returns cr3.2892 * @param pDbgc The DBGC instance.2893 * @param pfPAE Where to store the page address extension indicator.2894 * @param pfLME Where to store the long mode enabled indicator.2895 * @param pfPSE Where to store the page size extension indicator.2896 * @param pfPGE Where to store the page global enabled indicator.2897 * @param pfNXE Where to store the no-execution enabled inidicator.2898 */2899 static RTGCPHYS dbgcGetGuestPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)2900 {2901 RTGCUINTREG cr4 = CPUMGetGuestCR4(pDbgc->pVM);2902 *pfPSE = !!(cr4 & X86_CR4_PSE);2903 *pfPGE = !!(cr4 & X86_CR4_PGE);2904 *pfPAE = !!(cr4 & X86_CR4_PAE);2905 *pfLME = CPUMGetGuestMode(pDbgc->pVM) == CPUMMODE_LONG;2906 *pfNXE = false; /* GUEST64 GUESTNX */2907 return CPUMGetGuestCR3(pDbgc->pVM);2908 }2909 2910 2911 /**2912 * Determin the shadow paging mode.2913 *2914 * @returns cr3.2915 * @param pDbgc The DBGC instance.2916 * @param pfPAE Where to store the page address extension indicator.2917 * @param pfLME Where to store the long mode enabled indicator.2918 * @param pfPSE Where to store the page size extension indicator.2919 * @param pfPGE Where to store the page global enabled indicator.2920 * @param pfNXE Where to store the no-execution enabled inidicator.2921 */2922 static RTHCPHYS dbgcGetShadowPageMode(PDBGC pDbgc, bool *pfPAE, bool *pfLME, bool *pfPSE, bool *pfPGE, bool *pfNXE)2923 {2924 *pfPSE = true;2925 *pfPGE = false;2926 switch (PGMGetShadowMode(pDbgc->pVM))2927 {2928 default:2929 case PGMMODE_32_BIT:2930 *pfPAE = *pfLME = *pfNXE = false;2931 break;2932 case PGMMODE_PAE:2933 *pfLME = *pfNXE = false;2934 *pfPAE = true;2935 break;2936 case PGMMODE_PAE_NX:2937 *pfLME = false;2938 *pfPAE = *pfNXE = true;2939 break;2940 case PGMMODE_AMD64:2941 *pfNXE = false;2942 *pfPAE = *pfLME = true;2943 break;2944 case PGMMODE_AMD64_NX:2945 *pfPAE = *pfLME = *pfNXE = true;2946 break;2947 }2948 return PGMGetHyperCR3(pDbgc->pVM);2949 }2950 2951 2952 /**2953 * The 'dpd', 'dpda', 'dpdb', 'dpdg' and 'dpdh' commands.2954 *2955 * @returns VBox status.2956 * @param pCmd Pointer to the command descriptor (as registered).2957 * @param pCmdHlp Pointer to command helper functions.2958 * @param pVM Pointer to the current VM (if any).2959 * @param paArgs Pointer to (readonly) array of arguments.2960 * @param cArgs Number of arguments in the array.2961 */2962 static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)2963 {2964 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);2965 2966 /*2967 * Validate input.2968 */2969 if ( cArgs > 12970 || (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))2971 || (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))2972 )2973 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");2974 if (!pVM)2975 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");2976 2977 /*2978 * Guest or shadow page directories? Get the paging parameters.2979 */2980 bool fGuest = pCmd->pszCmd[3] != 'h';2981 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')2982 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER2983 ? pDbgc->fRegCtxGuest2984 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);2985 2986 bool fPAE, fLME, fPSE, fPGE, fNXE;2987 uint64_t cr3 = fGuest2988 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)2989 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);2990 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);2991 2992 /*2993 * Setup default arugment if none was specified.2994 * Fix address / index confusion.2995 */2996 DBGCVAR VarDefault;2997 if (!cArgs)2998 {2999 if (pCmd->pszCmd[3] == 'a')3000 {3001 if (fLME || fPAE)3002 return DBGCCmdHlpPrintf(pCmdHlp, "Default argument for 'dpda' hasn't been fully implemented yet. Try with an address or use one of the other commands.\n");3003 if (fGuest)3004 DBGCVAR_INIT_GC_PHYS(&VarDefault, cr3);3005 else3006 DBGCVAR_INIT_HC_PHYS(&VarDefault, cr3);3007 }3008 else3009 DBGCVAR_INIT_GC_FLAT(&VarDefault, 0);3010 paArgs = &VarDefault;3011 cArgs = 1;3012 }3013 else if (paArgs[0].enmType == DBGCVAR_TYPE_NUMBER)3014 {3015 Assert(pCmd->pszCmd[3] != 'a');3016 VarDefault = paArgs[0];3017 if (VarDefault.u.u64Number <= 1024)3018 {3019 if (fPAE)3020 return DBGCCmdHlpPrintf(pCmdHlp, "PDE indexing is only implemented for 32-bit paging.\n");3021 if (VarDefault.u.u64Number >= PAGE_SIZE / cbEntry)3022 return DBGCCmdHlpPrintf(pCmdHlp, "PDE index is out of range [0..%d].\n", PAGE_SIZE / cbEntry - 1);3023 VarDefault.u.u64Number <<= X86_PD_SHIFT;3024 }3025 VarDefault.enmType = DBGCVAR_TYPE_GC_FLAT;3026 paArgs = &VarDefault;3027 }3028 3029 /*3030 * Locate the PDE to start displaying at.3031 *3032 * The 'dpda' command takes the address of a PDE, while the others are guest3033 * virtual address which PDEs should be displayed. So, 'dpda' is rather simple3034 * while the others require us to do all the tedious walking thru the paging3035 * hierarchy to find the intended PDE.3036 */3037 unsigned iEntry = ~0U; /* The page directory index. ~0U for 'dpta'. */3038 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PDE (iEntry != ~0U). */3039 DBGCVAR VarPDEAddr; /* The address of the current PDE. */3040 unsigned cEntries; /* The number of entries to display. */3041 unsigned cEntriesMax; /* The max number of entries to display. */3042 int rc;3043 if (pCmd->pszCmd[3] == 'a')3044 {3045 VarPDEAddr = paArgs[0];3046 switch (VarPDEAddr.enmRangeType)3047 {3048 case DBGCVAR_RANGE_BYTES: cEntries = VarPDEAddr.u64Range / cbEntry; break;3049 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPDEAddr.u64Range; break;3050 default: cEntries = 10; break;3051 }3052 cEntriesMax = PAGE_SIZE / cbEntry;3053 }3054 else3055 {3056 /*3057 * Determin the range.3058 */3059 switch (paArgs[0].enmRangeType)3060 {3061 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;3062 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;3063 default: cEntries = 10; break;3064 }3065 3066 /*3067 * Normalize the input address, it must be a flat GC address.3068 */3069 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);3070 if (VBOX_FAILURE(rc))3071 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);3072 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)3073 {3074 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;3075 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;3076 }3077 if (fPAE)3078 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_PAE_SHIFT) - 1);3079 else3080 VarGCPtr.u.GCFlat &= ~(((RTGCPTR)1 << X86_PD_SHIFT) - 1);3081 3082 /*3083 * Do the paging walk until we get to the page directory.3084 */3085 DBGCVAR VarCur;3086 if (fGuest)3087 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);3088 else3089 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);3090 if (fLME)3091 {3092 /* Page Map Level 4 Lookup. */3093 /* Check if it's a valid address first? */3094 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;3095 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);3096 X86PML4E Pml4e;3097 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);3098 if (VBOX_FAILURE(rc))3099 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);3100 if (!Pml4e.n.u1Present)3101 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);3102 3103 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;3104 Assert(fPAE);3105 }3106 if (fPAE)3107 {3108 /* Page directory pointer table. */3109 X86PDPE Pdpe;3110 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);3111 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);3112 if (VBOX_FAILURE(rc))3113 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);3114 if (!Pdpe.n.u1Present)3115 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);3116 3117 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK;3118 VarPDEAddr = VarCur;3119 VarPDEAddr.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;3120 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDEPAE);3121 }3122 else3123 {3124 /* 32-bit legacy - CR3 == page directory. */3125 iEntry = (VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK;3126 VarPDEAddr = VarCur;3127 VarPDEAddr.u.u64Number += iEntry * sizeof(X86PDE);3128 }3129 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;3130 iEntry /= cbEntry;3131 }3132 3133 /* adjust cEntries */3134 cEntries = RT_MAX(1, cEntries);3135 cEntries = RT_MIN(cEntries, cEntriesMax);3136 3137 /*3138 * The display loop.3139 */3140 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (index %#x):\n" : "%DV:\n",3141 &VarPDEAddr, iEntry);3142 do3143 {3144 /*3145 * Read.3146 */3147 X86PDEPAE Pde;3148 Pde.u = 0;3149 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, cbEntry, &VarPDEAddr, NULL);3150 if (VBOX_FAILURE(rc))3151 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarPDEAddr);3152 3153 /*3154 * Display.3155 */3156 if (iEntry != ~0U)3157 {3158 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);3159 iEntry++;3160 }3161 if (fPSE && Pde.b.u1Size)3162 DBGCCmdHlpPrintf(pCmdHlp,3163 fPAE3164 ? "%016llx big phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"3165 : "%08llx big phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",3166 Pde.u,3167 Pde.u & X86_PDE_PAE_PG_MASK,3168 Pde.b.u1Present ? "p " : "np",3169 Pde.b.u1Write ? "w" : "r",3170 Pde.b.u1User ? "u" : "s",3171 Pde.b.u1Accessed ? "a " : "na",3172 Pde.b.u1Dirty ? "d " : "nd",3173 Pde.b.u3Available,3174 Pde.b.u1Global ? (fPGE ? "g" : "G") : " ",3175 Pde.b.u1WriteThru ? "pwt" : " ",3176 Pde.b.u1CacheDisable ? "pcd" : " ",3177 Pde.b.u1PAT ? "pat" : "",3178 Pde.b.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");3179 else3180 DBGCCmdHlpPrintf(pCmdHlp,3181 fPAE3182 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s"3183 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s",3184 Pde.u,3185 Pde.u & X86_PDE_PAE_PG_MASK,3186 Pde.n.u1Present ? "p " : "np",3187 Pde.n.u1Write ? "w" : "r",3188 Pde.n.u1User ? "u" : "s",3189 Pde.n.u1Accessed ? "a " : "na",3190 Pde.u & RT_BIT(6) ? "6 " : " ",3191 Pde.n.u3Available,3192 Pde.u & RT_BIT(8) ? "8" : " ",3193 Pde.n.u1WriteThru ? "pwt" : " ",3194 Pde.n.u1CacheDisable ? "pcd" : " ",3195 Pde.u & RT_BIT(7) ? "7" : "",3196 Pde.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " ");3197 if (Pde.u & UINT64_C(0x7fff000000000000))3198 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pde.u & UINT64_C(0x7fff000000000000)));3199 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");3200 if (VBOX_FAILURE(rc))3201 return rc;3202 3203 /*3204 * Advance.3205 */3206 VarPDEAddr.u.u64Number += cbEntry;3207 if (iEntry != ~0U)3208 VarGCPtr.u.GCFlat += 1 << (fPAE ? X86_PD_PAE_SHIFT : X86_PD_SHIFT);3209 } while (cEntries-- > 0);3210 3211 NOREF(pResult);3212 return VINF_SUCCESS;3213 }3214 3215 3216 /**3217 * The 'dpdb' command.3218 *3219 * @returns VBox status.3220 * @param pCmd Pointer to the command descriptor (as registered).3221 * @param pCmdHlp Pointer to command helper functions.3222 * @param pVM Pointer to the current VM (if any).3223 * @param paArgs Pointer to (readonly) array of arguments.3224 * @param cArgs Number of arguments in the array.3225 */3226 static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3227 {3228 if (!pVM)3229 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3230 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);3231 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);3232 if (VBOX_FAILURE(rc1))3233 return rc1;3234 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);3235 return rc2;3236 }3237 3238 3239 /**3240 * The 'dpg*' commands.3241 *3242 * @returns VBox status.3243 * @param pCmd Pointer to the command descriptor (as registered).3244 * @param pCmdHlp Pointer to command helper functions.3245 * @param pVM Pointer to the current VM (if any).3246 * @param paArgs Pointer to (readonly) array of arguments.3247 * @param cArgs Number of arguments in the array.3248 */3249 static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3250 {3251 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);3252 3253 /*3254 * Validate input.3255 */3256 if ( cArgs != 13257 || (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))3258 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))3259 )3260 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");3261 if (!pVM)3262 return DBGCCmdHlpPrintf(pCmdHlp, "error: No VM.\n");3263 3264 /*3265 * Guest or shadow page tables? Get the paging parameters.3266 */3267 bool fGuest = pCmd->pszCmd[3] != 'h';3268 if (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')3269 fGuest = paArgs[0].enmType == DBGCVAR_TYPE_NUMBER3270 ? pDbgc->fRegCtxGuest3271 : DBGCVAR_ISGCPOINTER(paArgs[0].enmType);3272 3273 bool fPAE, fLME, fPSE, fPGE, fNXE;3274 uint64_t cr3 = fGuest3275 ? dbgcGetGuestPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE)3276 : dbgcGetShadowPageMode(pDbgc, &fPAE, &fLME, &fPSE, &fPGE, &fNXE);3277 const unsigned cbEntry = fPAE ? sizeof(X86PTEPAE) : sizeof(X86PTE);3278 3279 /*3280 * Locate the PTE to start displaying at.3281 *3282 * The 'dpta' command takes the address of a PTE, while the others are guest3283 * virtual address which PTEs should be displayed. So, 'pdta' is rather simple3284 * while the others require us to do all the tedious walking thru the paging3285 * hierarchy to find the intended PTE.3286 */3287 unsigned iEntry = ~0U; /* The page table index. ~0U for 'dpta'. */3288 DBGCVAR VarGCPtr; /* The GC address corresponding to the current PTE (iEntry != ~0U). */3289 DBGCVAR VarPTEAddr; /* The address of the current PTE. */3290 unsigned cEntries; /* The number of entries to display. */3291 unsigned cEntriesMax; /* The max number of entries to display. */3292 int rc;3293 if (pCmd->pszCmd[3] == 'a')3294 {3295 VarPTEAddr = paArgs[0];3296 switch (VarPTEAddr.enmRangeType)3297 {3298 case DBGCVAR_RANGE_BYTES: cEntries = VarPTEAddr.u64Range / cbEntry; break;3299 case DBGCVAR_RANGE_ELEMENTS: cEntries = VarPTEAddr.u64Range; break;3300 default: cEntries = 10; break;3301 }3302 cEntriesMax = PAGE_SIZE / cbEntry;3303 }3304 else3305 {3306 /*3307 * Determin the range.3308 */3309 switch (paArgs[0].enmRangeType)3310 {3311 case DBGCVAR_RANGE_BYTES: cEntries = paArgs[0].u64Range / PAGE_SIZE; break;3312 case DBGCVAR_RANGE_ELEMENTS: cEntries = paArgs[0].u64Range; break;3313 default: cEntries = 10; break;3314 }3315 3316 /*3317 * Normalize the input address, it must be a flat GC address.3318 */3319 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);3320 if (VBOX_FAILURE(rc))3321 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);3322 if (VarGCPtr.enmType == DBGCVAR_TYPE_HC_FLAT)3323 {3324 VarGCPtr.u.GCFlat = (uintptr_t)VarGCPtr.u.pvHCFlat;3325 VarGCPtr.enmType = DBGCVAR_TYPE_GC_FLAT;3326 }3327 VarGCPtr.u.GCFlat &= ~(RTGCPTR)PAGE_OFFSET_MASK;3328 3329 /*3330 * Do the paging walk until we get to the page table.3331 */3332 DBGCVAR VarCur;3333 if (fGuest)3334 DBGCVAR_INIT_GC_PHYS(&VarCur, cr3);3335 else3336 DBGCVAR_INIT_HC_PHYS(&VarCur, cr3);3337 if (fLME)3338 {3339 /* Page Map Level 4 Lookup. */3340 /* Check if it's a valid address first? */3341 VarCur.u.u64Number &= X86_PTE_PAE_PG_MASK;3342 VarCur.u.u64Number += (((uint64_t)VarGCPtr.u.GCFlat >> X86_PML4_SHIFT) & X86_PML4_MASK) * sizeof(X86PML4E);3343 X86PML4E Pml4e;3344 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pml4e, sizeof(Pml4e), &VarCur, NULL);3345 if (VBOX_FAILURE(rc))3346 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PML4E memory at %DV.\n", &VarCur);3347 if (!Pml4e.n.u1Present)3348 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory pointer table is not present for %Dv.\n", &VarGCPtr);3349 3350 VarCur.u.u64Number = Pml4e.u & X86_PML4E_PG_MASK;3351 Assert(fPAE);3352 }3353 if (fPAE)3354 {3355 /* Page directory pointer table. */3356 X86PDPE Pdpe;3357 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PDPTR_SHIFT) & X86_PDPTR_MASK) * sizeof(Pdpe);3358 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pdpe, sizeof(Pdpe), &VarCur, NULL);3359 if (VBOX_FAILURE(rc))3360 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDPE memory at %DV.\n", &VarCur);3361 if (!Pdpe.n.u1Present)3362 return DBGCCmdHlpPrintf(pCmdHlp, "Page directory is not present for %Dv.\n", &VarGCPtr);3363 3364 VarCur.u.u64Number = Pdpe.u & X86_PDPE_PG_MASK;3365 3366 /* Page directory (PAE). */3367 X86PDEPAE Pde;3368 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_PAE_SHIFT) & X86_PD_PAE_MASK) * sizeof(Pde);3369 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);3370 if (VBOX_FAILURE(rc))3371 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);3372 if (!Pde.n.u1Present)3373 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);3374 if (fPSE && Pde.n.u1Size)3375 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);3376 3377 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_PAE_SHIFT) & X86_PT_PAE_MASK;3378 VarPTEAddr = VarCur;3379 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PAE_PG_MASK;3380 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTEPAE);3381 }3382 else3383 {3384 /* Page directory (legacy). */3385 X86PDE Pde;3386 VarCur.u.u64Number += ((VarGCPtr.u.GCFlat >> X86_PD_SHIFT) & X86_PD_MASK) * sizeof(Pde);3387 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarCur, NULL);3388 if (VBOX_FAILURE(rc))3389 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PDE memory at %DV.\n", &VarCur);3390 if (!Pde.n.u1Present)3391 return DBGCCmdHlpPrintf(pCmdHlp, "Page table is not present for %Dv.\n", &VarGCPtr);3392 if (fPSE && Pde.n.u1Size)3393 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);3394 3395 iEntry = (VarGCPtr.u.GCFlat >> X86_PT_SHIFT) & X86_PT_MASK;3396 VarPTEAddr = VarCur;3397 VarPTEAddr.u.u64Number = Pde.u & X86_PDE_PG_MASK;3398 VarPTEAddr.u.u64Number += iEntry * sizeof(X86PTE);3399 }3400 cEntriesMax = (PAGE_SIZE - iEntry) / cbEntry;3401 iEntry /= cbEntry;3402 }3403 3404 /* adjust cEntries */3405 cEntries = RT_MAX(1, cEntries);3406 cEntries = RT_MIN(cEntries, cEntriesMax);3407 3408 /*3409 * The display loop.3410 */3411 DBGCCmdHlpPrintf(pCmdHlp, iEntry != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n",3412 &VarPTEAddr, &VarGCPtr, iEntry);3413 do3414 {3415 /*3416 * Read.3417 */3418 X86PTEPAE Pte;3419 Pte.u = 0;3420 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, cbEntry, &VarPTEAddr, NULL);3421 if (VBOX_FAILURE(rc))3422 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Reading PTE memory at %DV.\n", &VarPTEAddr);3423 3424 /*3425 * Display.3426 */3427 if (iEntry != ~0U)3428 {3429 DBGCCmdHlpPrintf(pCmdHlp, "%03x %DV: ", iEntry, &VarGCPtr);3430 iEntry++;3431 }3432 DBGCCmdHlpPrintf(pCmdHlp,3433 fPAE3434 ? "%016llx 4kb phys=%016llx %s %s %s %s %s avl=%02x %s %s %s %s %s"3435 : "%08llx 4kb phys=%08llx %s %s %s %s %s avl=%02x %s %s %s %s %s",3436 Pte.u,3437 Pte.u & X86_PTE_PAE_PG_MASK,3438 Pte.n.u1Present ? "p " : "np",3439 Pte.n.u1Write ? "w" : "r",3440 Pte.n.u1User ? "u" : "s",3441 Pte.n.u1Accessed ? "a " : "na",3442 Pte.n.u1Dirty ? "d " : "nd",3443 Pte.n.u3Available,3444 Pte.n.u1Global ? (fPGE ? "g" : "G") : " ",3445 Pte.n.u1WriteThru ? "pwt" : " ",3446 Pte.n.u1CacheDisable ? "pcd" : " ",3447 Pte.n.u1PAT ? "pat" : " ",3448 Pte.n.u1NoExecute ? (fNXE ? "nx" : "NX") : " "3449 );3450 if (Pte.u & UINT64_C(0x7fff000000000000))3451 DBGCCmdHlpPrintf(pCmdHlp, " weird=%RX64", (Pte.u & UINT64_C(0x7fff000000000000)));3452 rc = DBGCCmdHlpPrintf(pCmdHlp, "\n");3453 if (VBOX_FAILURE(rc))3454 return rc;3455 3456 /*3457 * Advance.3458 */3459 VarPTEAddr.u.u64Number += cbEntry;3460 if (iEntry != ~0U)3461 VarGCPtr.u.GCFlat += PAGE_SIZE;3462 } while (cEntries-- > 0);3463 3464 NOREF(pResult);3465 return VINF_SUCCESS;3466 }3467 3468 3469 /**3470 * The 'dptb' command.3471 *3472 * @returns VBox status.3473 * @param pCmd Pointer to the command descriptor (as registered).3474 * @param pCmdHlp Pointer to command helper functions.3475 * @param pVM Pointer to the current VM (if any).3476 * @param paArgs Pointer to (readonly) array of arguments.3477 * @param cArgs Number of arguments in the array.3478 */3479 static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3480 {3481 if (!pVM)3482 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3483 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);3484 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);3485 if (VBOX_FAILURE(rc1))3486 return rc1;3487 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3488 return rc2;3489 }3490 3491 3492 /**3493 * The 'dt' command.3494 *3495 * @returns VBox status.3496 * @param pCmd Pointer to the command descriptor (as registered).3497 * @param pCmdHlp Pointer to command helper functions.3498 * @param pVM Pointer to the current VM (if any).3499 * @param paArgs Pointer to (readonly) array of arguments.3500 * @param cArgs Number of arguments in the array.3501 */3502 static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM /*pVM*/, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)3503 {3504 /*3505 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.3506 */3507 3508 /** @todo */3509 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dt is not implemented yet, feel free to do it. \n");3510 }3511 3512 3513 /**3514 * The 'm' command.3515 *3516 * @returns VBox status.3517 * @param pCmd Pointer to the command descriptor (as registered).3518 * @param pCmdHlp Pointer to command helper functions.3519 * @param pVM Pointer to the current VM (if any).3520 * @param paArgs Pointer to (readonly) array of arguments.3521 * @param cArgs Number of arguments in the array.3522 */3523 static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3524 {3525 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Address: %DV\n", &paArgs[0]);3526 if (!pVM)3527 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");3528 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);3529 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);3530 int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);3531 int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);3532 if (VBOX_FAILURE(rc1))3533 return rc1;3534 if (VBOX_FAILURE(rc2))3535 return rc2;3536 if (VBOX_FAILURE(rc3))3537 return rc3;3538 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);3539 return rc4;3540 771 } 3541 772 … … 3654 885 return rc; 3655 886 } 3656 3657 3658 /**3659 * The 's' command.3660 *3661 * @returns VBox status.3662 * @param pCmd Pointer to the command descriptor (as registered).3663 * @param pCmdHlp Pointer to command helper functions.3664 * @param pVM Pointer to the current VM (if any).3665 * @param paArgs Pointer to (readonly) array of arguments.3666 * @param cArgs Number of arguments in the array.3667 */3668 static DECLCALLBACK(int) dbgcCmdSearchMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)3669 {3670 /* check that the parser did what it's supposed to do. */3671 if ( cArgs != 13672 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)3673 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");3674 return -1;3675 }3676 3677 887 3678 888 … … 3950 1160 3951 1161 /** 3952 * List near symbol.3953 *3954 * @returns VBox status code.3955 * @param pCmdHlp Pointer to command helper functions.3956 * @param pVM Pointer to the current VM (if any).3957 * @param pArg Pointer to the address or symbol to lookup.3958 */3959 static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)3960 {3961 dbgcVarSetGCFlat(pResult, 0);3962 3963 DBGFSYMBOL Symbol;3964 int rc;3965 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)3966 {3967 /*3968 * Lookup the symbol address.3969 */3970 rc = DBGFR3SymbolByName(pVM, pArg->u.pszString, &Symbol);3971 if (VBOX_FAILURE(rc))3972 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByName(, %s,)\n", pArg->u.pszString);3973 3974 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */3975 dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);3976 }3977 else3978 {3979 /*3980 * Convert it to a flat GC address and lookup that address.3981 */3982 DBGCVAR AddrVar;3983 rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);3984 if (VBOX_FAILURE(rc))3985 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);3986 3987 dbgcVarSetVar(pResult, &AddrVar);3988 3989 RTGCINTPTR offDisp = 0;3990 rc = DBGFR3SymbolByAddr(pVM, AddrVar.u.GCFlat, &offDisp, &Symbol);3991 if (VBOX_FAILURE(rc))3992 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByAddr(, %VGv,,)\n", AddrVar.u.GCFlat);3993 3994 if (!offDisp)3995 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);3996 else if (offDisp > 0)3997 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);3998 else3999 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);4000 if ((RTGCINTPTR)Symbol.cb > -offDisp)4001 {4002 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);4003 dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);4004 }4005 else4006 {4007 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");4008 dbgcVarSetNoRange(pResult);4009 }4010 }4011 4012 return rc;4013 }4014 4015 4016 /**4017 * The 'ln' (listnear) command.4018 *4019 * @returns VBox status.4020 * @param pCmd Pointer to the command descriptor (as registered).4021 * @param pCmdHlp Pointer to command helper functions.4022 * @param pVM Pointer to the current VM (if any).4023 * @param paArgs Pointer to (readonly) array of arguments.4024 * @param cArgs Number of arguments in the array.4025 */4026 static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)4027 {4028 dbgcVarSetGCFlat(pResult, 0);4029 if (!cArgs)4030 {4031 /*4032 * Current cs:eip symbol.4033 */4034 DBGCVAR AddrVar;4035 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(cs:eip)");4036 if (VBOX_FAILURE(rc))4037 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");4038 return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);4039 }4040 4041 /*4042 * Iterate arguments.4043 */4044 for (unsigned iArg = 0; iArg < cArgs; iArg++)4045 {4046 int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);4047 if (VBOX_FAILURE(rc))4048 return rc;4049 }4050 4051 NOREF(pCmd); NOREF(pResult);4052 return VINF_SUCCESS;4053 }4054 4055 4056 /**4057 1162 * The 'loadsyms' command. 4058 1163 * … … 6734 3839 6735 3840 /** @todo move me!*/ 6736 staticvoid dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)3841 void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat) 6737 3842 { 6738 3843 if (pVar) … … 6747 3852 6748 3853 /** @todo move me!*/ 6749 staticvoid dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)3854 void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb) 6750 3855 { 6751 3856 if (pVar) … … 6760 3865 6761 3866 /** @todo move me!*/ 6762 staticvoid dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)3867 void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2) 6763 3868 { 6764 3869 if (pVar) … … 6778 3883 6779 3884 /** @todo move me!*/ 6780 staticvoid dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)3885 void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb) 6781 3886 { 6782 3887 if (pVar) … … 6789 3894 6790 3895 /** @todo move me!*/ 6791 staticvoid dbgcVarSetNoRange(PDBGCVAR pVar)3896 void dbgcVarSetNoRange(PDBGCVAR pVar) 6792 3897 { 6793 3898 if (pVar) … … 6856 3961 * Adds a breakpoint to the DBGC breakpoint list. 6857 3962 */ 6858 staticint dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)3963 int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd) 6859 3964 { 6860 3965 /* … … 6894 3999 * @param pszCmd The new command. 6895 4000 */ 6896 staticint dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)4001 int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd) 6897 4002 { 6898 4003 /* … … 6939 4044 * @param iBp The breakpoint to delete. 6940 4045 */ 6941 staticint dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)4046 int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp) 6942 4047 { 6943 4048 /* … … 6972 4077 * @param iBp The breakpoint to get. 6973 4078 */ 6974 staticPDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)4079 PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp) 6975 4080 { 6976 4081 /* … … 6995 4100 * @param iBp The breakpoint to execute. 6996 4101 */ 6997 staticint dbgcBpExec(PDBGC pDbgc, RTUINT iBp)4102 int dbgcBpExec(PDBGC pDbgc, RTUINT iBp) 6998 4103 { 6999 4104 /* … … 7222 4327 * @param pszSymbol The symbol name. 7223 4328 */ 7224 staticPCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)4329 PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol) 7225 4330 { 7226 4331 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++) … … 8875 5980 pDbgc->pszEmulation = "CodeView/WinDbg"; 8876 5981 pDbgc->paEmulationCmds = &g_aCmdsCodeView[0]; 8877 pDbgc->cEmulationCmds = RT_ELEMENTS(g_aCmdsCodeView);5982 pDbgc->cEmulationCmds = g_cCmdsCodeView; 8878 5983 //pDbgc->fLog = false; 8879 5984 pDbgc->fRegCtxGuest = true; -
trunk/src/VBox/Debugger/Makefile.kmk
r4071 r5669 6 6 # 7 7 # Copyright (C) 2006-2007 innotek GmbH 8 # 8 # 9 9 # This file is part of VirtualBox Open Source Edition (OSE), as 10 10 # available from http://www.virtualbox.org. This file is free software; … … 36 36 Debugger_SOURCES = \ 37 37 DBGConsole.cpp \ 38 DBGCEmulateCodeView.cpp \ 38 39 DBGCTcp.cpp 39 40 … … 61 62 VBoxDbg_DEFS = IN_DBG_R3 62 63 VBoxDbg_CXXFLAGS.linux = $(TEMPLATE_VBOXQTGUI_CXXFLAGS.linux) -O2 64 VBoxDbg_CXXFLAGS.win = -wd4244 63 65 VBoxDbg_INCS = \ 64 66 . \ … … 95 97 VBoxDbgConsole.cpp \ 96 98 VBoxDbgStats.cpp \ 97 DBGConsole.cpp 99 DBGConsole.cpp \ 100 DBGCEmulateCodeView.cpp 98 101 99 102 VBoxDbg_LIBS = $(LIB_VMM)
Note:
See TracChangeset
for help on using the changeset viewer.