VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGConsole.cpp@ 5671

Last change on this file since 5671 was 5669, checked in by vboxsync, 17 years ago

Split out the codeview/windbg commands.

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

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