VirtualBox

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

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

Don't use SELMToFlatEx.

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