VirtualBox

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

Last change on this file since 4122 was 4071, checked in by vboxsync, 18 years ago

Biggest check-in ever. New source code headers for all (C) innotek files.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 302.6 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 0 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 0;
4324
4325 case DBGCVAR_TYPE_GC_FAR:
4326 {
4327 PCPUMCTX pCtx;
4328 CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4329
4330 Assert(pDbgc->pVM);
4331
4332 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
4333 rc = SELMToFlatEx(pDbgc->pVM, pCtx->eflags, pResult->u.GCFar.sel, pResult->u.GCFar.off, NULL,
4334 SELMTOFLAT_FLAGS_NO_PL | SELMTOFLAT_FLAGS_HYPER, &pResult->u.GCFlat, NULL);
4335 if (VBOX_SUCCESS(rc))
4336 return 0;
4337 return VERR_PARSE_CONVERSION_FAILED;
4338 }
4339
4340 case DBGCVAR_TYPE_GC_PHYS:
4341 //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
4342 return VERR_PARSE_INCORRECT_ARG_TYPE;
4343
4344 case DBGCVAR_TYPE_HC_FLAT:
4345 return 0;
4346
4347 case DBGCVAR_TYPE_HC_FAR:
4348 return VERR_PARSE_INCORRECT_ARG_TYPE;
4349
4350 case DBGCVAR_TYPE_HC_PHYS:
4351 Assert(pDbgc->pVM);
4352 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4353 rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);
4354 if (VBOX_SUCCESS(rc))
4355 return 0;
4356 return VERR_PARSE_CONVERSION_FAILED;
4357
4358 case DBGCVAR_TYPE_NUMBER:
4359 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
4360 pResult->u.GCFlat = (RTGCPTR)pResult->u.u64Number;
4361 return 0;
4362
4363 case DBGCVAR_TYPE_STRING:
4364 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);
4365
4366 case DBGCVAR_TYPE_UNKNOWN:
4367 default:
4368 return VERR_PARSE_INCORRECT_ARG_TYPE;
4369 }
4370}
4371
4372
4373/**
4374 * Physical address (unary).
4375 *
4376 * @returns 0 on success.
4377 * @returns VBox evaluation / parsing error code on failure.
4378 * The caller does the bitching.
4379 * @param pDbgc Debugger console instance data.
4380 * @param pArg The argument.
4381 * @param pResult Where to store the result.
4382 */
4383static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4384{
4385// LogFlow(("dbgcOpAddrPhys\n"));
4386 int rc;
4387
4388 *pResult = *pArg;
4389 switch (pArg->enmType)
4390 {
4391 case DBGCVAR_TYPE_GC_FLAT:
4392 Assert(pDbgc->pVM);
4393 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4394 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);
4395 if (VBOX_SUCCESS(rc))
4396 return 0;
4397 /** @todo more memory types! */
4398 return VERR_PARSE_CONVERSION_FAILED;
4399
4400 case DBGCVAR_TYPE_GC_FAR:
4401 {
4402 PCPUMCTX pCtx;
4403 CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4404 Assert(pDbgc->pVM);
4405 rc = SELMToFlatEx(pDbgc->pVM, pCtx->eflags, pResult->u.GCFar.sel, pResult->u.GCFar.off, NULL,
4406 SELMTOFLAT_FLAGS_NO_PL | SELMTOFLAT_FLAGS_HYPER, &pResult->u.GCFlat, NULL);
4407 if (VBOX_SUCCESS(rc))
4408 {
4409 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4410 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pResult->u.GCFlat, &pResult->u.GCPhys);
4411 if (VBOX_SUCCESS(rc))
4412 return 0;
4413 /** @todo more memory types! */
4414 }
4415 return VERR_PARSE_CONVERSION_FAILED;
4416 }
4417
4418 case DBGCVAR_TYPE_GC_PHYS:
4419 return 0;
4420
4421 case DBGCVAR_TYPE_HC_FLAT:
4422 Assert(pDbgc->pVM);
4423 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4424 rc = PGMPhysHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);
4425 if (VBOX_SUCCESS(rc))
4426 return 0;
4427 /** @todo more memory types! */
4428 return VERR_PARSE_CONVERSION_FAILED;
4429
4430 case DBGCVAR_TYPE_HC_FAR:
4431 return VERR_PARSE_INCORRECT_ARG_TYPE;
4432
4433 case DBGCVAR_TYPE_HC_PHYS:
4434 return 0;
4435
4436 case DBGCVAR_TYPE_NUMBER:
4437 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4438 pResult->u.GCPhys = (RTGCPHYS)pResult->u.u64Number;
4439 return 0;
4440
4441 case DBGCVAR_TYPE_STRING:
4442 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);
4443
4444 case DBGCVAR_TYPE_UNKNOWN:
4445 default:
4446 return VERR_PARSE_INCORRECT_ARG_TYPE;
4447 }
4448 return 0;
4449}
4450
4451
4452/**
4453 * Physical host address (unary).
4454 *
4455 * @returns 0 on success.
4456 * @returns VBox evaluation / parsing error code on failure.
4457 * The caller does the bitching.
4458 * @param pDbgc Debugger console instance data.
4459 * @param pArg The argument.
4460 * @param pResult Where to store the result.
4461 */
4462static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4463{
4464// LogFlow(("dbgcOpAddrPhys\n"));
4465 int rc;
4466
4467 *pResult = *pArg;
4468 switch (pArg->enmType)
4469 {
4470 case DBGCVAR_TYPE_GC_FLAT:
4471 Assert(pDbgc->pVM);
4472 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
4473 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
4474 if (VBOX_SUCCESS(rc))
4475 return 0;
4476 /** @todo more memory types. */
4477 return VERR_PARSE_CONVERSION_FAILED;
4478
4479 case DBGCVAR_TYPE_GC_FAR:
4480 {
4481 PCPUMCTX pCtx;
4482 CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4483
4484 Assert(pDbgc->pVM);
4485 rc = SELMToFlatEx(pDbgc->pVM, pCtx->eflags, pResult->u.GCFar.sel, pResult->u.GCFar.off, NULL,
4486 SELMTOFLAT_FLAGS_NO_PL | SELMTOFLAT_FLAGS_HYPER, &pResult->u.GCFlat, NULL);
4487 if (VBOX_SUCCESS(rc))
4488 {
4489 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
4490 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pResult->u.GCFlat, &pResult->u.HCPhys);
4491 if (VBOX_SUCCESS(rc))
4492 return 0;
4493 /** @todo more memory types. */
4494 }
4495 return VERR_PARSE_CONVERSION_FAILED;
4496 }
4497
4498 case DBGCVAR_TYPE_GC_PHYS:
4499 Assert(pDbgc->pVM);
4500 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
4501 rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
4502 if (VBOX_SUCCESS(rc))
4503 return 0;
4504 return VERR_PARSE_CONVERSION_FAILED;
4505
4506 case DBGCVAR_TYPE_HC_FLAT:
4507 Assert(pDbgc->pVM);
4508 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
4509 rc = PGMPhysHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);
4510 if (VBOX_SUCCESS(rc))
4511 return 0;
4512 /** @todo more memory types! */
4513 return VERR_PARSE_CONVERSION_FAILED;
4514
4515 case DBGCVAR_TYPE_HC_FAR:
4516 return VERR_PARSE_INCORRECT_ARG_TYPE;
4517
4518 case DBGCVAR_TYPE_HC_PHYS:
4519 return 0;
4520
4521 case DBGCVAR_TYPE_NUMBER:
4522 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
4523 pResult->u.HCPhys = (RTGCPHYS)pResult->u.u64Number;
4524 return 0;
4525
4526 case DBGCVAR_TYPE_STRING:
4527 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);
4528
4529 case DBGCVAR_TYPE_UNKNOWN:
4530 default:
4531 return VERR_PARSE_INCORRECT_ARG_TYPE;
4532 }
4533 return 0;
4534}
4535
4536
4537/**
4538 * Host address (unary).
4539 *
4540 * @returns 0 on success.
4541 * @returns VBox evaluation / parsing error code on failure.
4542 * The caller does the bitching.
4543 * @param pDbgc Debugger console instance data.
4544 * @param pArg The argument.
4545 * @param pResult Where to store the result.
4546 */
4547static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4548{
4549// LogFlow(("dbgcOpAddrHost\n"));
4550 int rc;
4551
4552 *pResult = *pArg;
4553 switch (pArg->enmType)
4554 {
4555 case DBGCVAR_TYPE_GC_FLAT:
4556 Assert(pDbgc->pVM);
4557 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4558 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);
4559 if (VBOX_SUCCESS(rc))
4560 return 0;
4561 /** @todo more memory types. */
4562 return VERR_PARSE_CONVERSION_FAILED;
4563
4564 case DBGCVAR_TYPE_GC_FAR:
4565 {
4566 PCPUMCTX pCtx;
4567 CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4568
4569 Assert(pDbgc->pVM);
4570 rc = SELMToFlatEx(pDbgc->pVM, pCtx->eflags, pResult->u.GCFar.sel, pResult->u.GCFar.off, NULL,
4571 SELMTOFLAT_FLAGS_NO_PL | SELMTOFLAT_FLAGS_HYPER, &pResult->u.GCFlat, NULL);
4572 if (VBOX_SUCCESS(rc))
4573 {
4574 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4575 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pResult->u.GCFlat, &pResult->u.pvHCFlat);
4576 if (VBOX_SUCCESS(rc))
4577 return 0;
4578 /** @todo more memory types. */
4579 }
4580 return VERR_PARSE_CONVERSION_FAILED;
4581 }
4582
4583 case DBGCVAR_TYPE_GC_PHYS:
4584 Assert(pDbgc->pVM);
4585 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4586 rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);
4587 if (VBOX_SUCCESS(rc))
4588 return 0;
4589 return VERR_PARSE_CONVERSION_FAILED;
4590
4591 case DBGCVAR_TYPE_HC_FLAT:
4592 return 0;
4593
4594 case DBGCVAR_TYPE_HC_FAR:
4595 case DBGCVAR_TYPE_HC_PHYS:
4596 /** @todo !*/
4597 return VERR_PARSE_CONVERSION_FAILED;
4598
4599 case DBGCVAR_TYPE_NUMBER:
4600 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4601 pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;
4602 return 0;
4603
4604 case DBGCVAR_TYPE_STRING:
4605 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);
4606
4607 case DBGCVAR_TYPE_UNKNOWN:
4608 default:
4609 return VERR_PARSE_INCORRECT_ARG_TYPE;
4610 }
4611}
4612
4613/**
4614 * Bitwise not (unary).
4615 *
4616 * @returns 0 on success.
4617 * @returns VBox evaluation / parsing error code on failure.
4618 * The caller does the bitching.
4619 * @param pDbgc Debugger console instance data.
4620 * @param pArg The argument.
4621 * @param pResult Where to store the result.
4622 */
4623static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4624{
4625// LogFlow(("dbgcOpAddrFar\n"));
4626 int rc;
4627
4628 switch (pArg1->enmType)
4629 {
4630 case DBGCVAR_TYPE_STRING:
4631 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
4632 if (VBOX_FAILURE(rc))
4633 return rc;
4634 break;
4635 case DBGCVAR_TYPE_NUMBER:
4636 *pResult = *pArg1;
4637 break;
4638
4639 case DBGCVAR_TYPE_GC_FLAT:
4640 case DBGCVAR_TYPE_GC_FAR:
4641 case DBGCVAR_TYPE_GC_PHYS:
4642 case DBGCVAR_TYPE_HC_FLAT:
4643 case DBGCVAR_TYPE_HC_FAR:
4644 case DBGCVAR_TYPE_HC_PHYS:
4645 case DBGCVAR_TYPE_UNKNOWN:
4646 default:
4647 return VERR_PARSE_INCORRECT_ARG_TYPE;
4648 }
4649 pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;
4650
4651 /* common code for the two types we support. */
4652 switch (pArg2->enmType)
4653 {
4654 case DBGCVAR_TYPE_GC_FLAT:
4655 pResult->u.GCFar.off = pArg2->u.GCFlat;
4656 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
4657 break;
4658
4659 case DBGCVAR_TYPE_HC_FLAT:
4660 pResult->u.HCFar.off = pArg2->u.GCFlat;
4661 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
4662 break;
4663
4664 case DBGCVAR_TYPE_NUMBER:
4665 pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;
4666 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
4667 break;
4668
4669 case DBGCVAR_TYPE_STRING:
4670 {
4671 DBGCVAR Var;
4672 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
4673 if (VBOX_FAILURE(rc))
4674 return rc;
4675 pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;
4676 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
4677 break;
4678 }
4679
4680 case DBGCVAR_TYPE_GC_FAR:
4681 case DBGCVAR_TYPE_GC_PHYS:
4682 case DBGCVAR_TYPE_HC_FAR:
4683 case DBGCVAR_TYPE_HC_PHYS:
4684 case DBGCVAR_TYPE_UNKNOWN:
4685 default:
4686 return VERR_PARSE_INCORRECT_ARG_TYPE;
4687 }
4688 return 0;
4689
4690}
4691
4692
4693
4694/**
4695 * Multiplication operator (binary).
4696 *
4697 * @returns 0 on success.
4698 * @returns VBox evaluation / parsing error code on failure.
4699 * The caller does the bitching.
4700 * @param pDbgc Debugger console instance data.
4701 * @param pArg1 The first argument.
4702 * @param pArg2 The 2nd argument.
4703 * @param pResult Where to store the result.
4704 */
4705static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4706{
4707 LogFlow(("dbgcOpMult\n"));
4708 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
4709 return -1;
4710}
4711
4712
4713/**
4714 * Division operator (binary).
4715 *
4716 * @returns 0 on success.
4717 * @returns VBox evaluation / parsing error code on failure.
4718 * The caller does the bitching.
4719 * @param pDbgc Debugger console instance data.
4720 * @param pArg1 The first argument.
4721 * @param pArg2 The 2nd argument.
4722 * @param pResult Where to store the result.
4723 */
4724static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4725{
4726 LogFlow(("dbgcOpDiv\n"));
4727 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
4728 return -1;
4729}
4730
4731
4732/**
4733 * Modulus operator (binary).
4734 *
4735 * @returns 0 on success.
4736 * @returns VBox evaluation / parsing error code on failure.
4737 * The caller does the bitching.
4738 * @param pDbgc Debugger console instance data.
4739 * @param pArg1 The first argument.
4740 * @param pArg2 The 2nd argument.
4741 * @param pResult Where to store the result.
4742 */
4743static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4744{
4745 LogFlow(("dbgcOpMod\n"));
4746 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
4747 return -1;
4748}
4749
4750
4751/**
4752 * Addition operator (binary).
4753 *
4754 * @returns 0 on success.
4755 * @returns VBox evaluation / parsing error code on failure.
4756 * The caller does the bitching.
4757 * @param pDbgc Debugger console instance data.
4758 * @param pArg1 The first argument.
4759 * @param pArg2 The 2nd argument.
4760 * @param pResult Where to store the result.
4761 */
4762static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4763{
4764// LogFlow(("dbgcOpAdd\n"));
4765
4766 /*
4767 * An addition operation will return (when possible) the left side type in the
4768 * expression. We make an omission for numbers, where we'll take the right side
4769 * type instead. An expression where only the left hand side is a string we'll
4770 * use the right hand type assuming that the string is a symbol.
4771 */
4772 if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)
4773 || (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))
4774 {
4775 PCDBGCVAR pTmp = pArg2;
4776 pArg2 = pArg1;
4777 pArg1 = pTmp;
4778 }
4779 DBGCVAR Sym1, Sym2;
4780 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
4781 {
4782 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
4783 if (VBOX_FAILURE(rc))
4784 return rc;
4785 pArg1 = &Sym1;
4786
4787 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
4788 if (VBOX_FAILURE(rc))
4789 return rc;
4790 pArg2 = &Sym2;
4791 }
4792
4793 int rc;
4794 DBGCVAR Var;
4795 DBGCVAR Var2;
4796 switch (pArg1->enmType)
4797 {
4798 /*
4799 * GC Flat
4800 */
4801 case DBGCVAR_TYPE_GC_FLAT:
4802 switch (pArg2->enmType)
4803 {
4804 case DBGCVAR_TYPE_HC_FLAT:
4805 case DBGCVAR_TYPE_HC_FAR:
4806 case DBGCVAR_TYPE_HC_PHYS:
4807 return VERR_PARSE_INVALID_OPERATION;
4808 default:
4809 *pResult = *pArg1;
4810 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
4811 if (VBOX_FAILURE(rc))
4812 return rc;
4813 pResult->u.GCFlat += pArg2->u.GCFlat;
4814 break;
4815 }
4816 break;
4817
4818 /*
4819 * GC Far
4820 */
4821 case DBGCVAR_TYPE_GC_FAR:
4822 switch (pArg2->enmType)
4823 {
4824 case DBGCVAR_TYPE_HC_FLAT:
4825 case DBGCVAR_TYPE_HC_FAR:
4826 case DBGCVAR_TYPE_HC_PHYS:
4827 return VERR_PARSE_INVALID_OPERATION;
4828 case DBGCVAR_TYPE_NUMBER:
4829 *pResult = *pArg1;
4830 pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;
4831 break;
4832 default:
4833 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
4834 if (VBOX_FAILURE(rc))
4835 return rc;
4836 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
4837 if (VBOX_FAILURE(rc))
4838 return rc;
4839 pResult->u.GCFlat += pArg2->u.GCFlat;
4840 break;
4841 }
4842 break;
4843
4844 /*
4845 * GC Phys
4846 */
4847 case DBGCVAR_TYPE_GC_PHYS:
4848 switch (pArg2->enmType)
4849 {
4850 case DBGCVAR_TYPE_HC_FLAT:
4851 case DBGCVAR_TYPE_HC_FAR:
4852 case DBGCVAR_TYPE_HC_PHYS:
4853 return VERR_PARSE_INVALID_OPERATION;
4854 default:
4855 *pResult = *pArg1;
4856 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
4857 if (VBOX_FAILURE(rc))
4858 return rc;
4859 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
4860 return VERR_PARSE_INVALID_OPERATION;
4861 pResult->u.GCPhys += Var.u.GCPhys;
4862 break;
4863 }
4864 break;
4865
4866 /*
4867 * HC Flat
4868 */
4869 case DBGCVAR_TYPE_HC_FLAT:
4870 *pResult = *pArg1;
4871 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
4872 if (VBOX_FAILURE(rc))
4873 return rc;
4874 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
4875 if (VBOX_FAILURE(rc))
4876 return rc;
4877 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
4878 break;
4879
4880 /*
4881 * HC Far
4882 */
4883 case DBGCVAR_TYPE_HC_FAR:
4884 switch (pArg2->enmType)
4885 {
4886 case DBGCVAR_TYPE_NUMBER:
4887 *pResult = *pArg1;
4888 pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;
4889 break;
4890
4891 default:
4892 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
4893 if (VBOX_FAILURE(rc))
4894 return rc;
4895 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
4896 if (VBOX_FAILURE(rc))
4897 return rc;
4898 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
4899 if (VBOX_FAILURE(rc))
4900 return rc;
4901 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
4902 break;
4903 }
4904 break;
4905
4906 /*
4907 * HC Phys
4908 */
4909 case DBGCVAR_TYPE_HC_PHYS:
4910 *pResult = *pArg1;
4911 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
4912 if (VBOX_FAILURE(rc))
4913 return rc;
4914 pResult->u.HCPhys += Var.u.HCPhys;
4915 break;
4916
4917 /*
4918 * Numbers (see start of function)
4919 */
4920 case DBGCVAR_TYPE_NUMBER:
4921 switch (pArg2->enmType)
4922 {
4923 case DBGCVAR_TYPE_STRING:
4924 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
4925 if (VBOX_FAILURE(rc))
4926 return rc;
4927 case DBGCVAR_TYPE_NUMBER:
4928 pResult->u.u64Number += pArg2->u.u64Number;
4929 break;
4930 default:
4931 return VERR_PARSE_INVALID_OPERATION;
4932 }
4933 break;
4934
4935 default:
4936 return VERR_PARSE_INVALID_OPERATION;
4937
4938 }
4939 return 0;
4940}
4941
4942
4943/**
4944 * Subtration operator (binary).
4945 *
4946 * @returns 0 on success.
4947 * @returns VBox evaluation / parsing error code on failure.
4948 * The caller does the bitching.
4949 * @param pDbgc Debugger console instance data.
4950 * @param pArg1 The first argument.
4951 * @param pArg2 The 2nd argument.
4952 * @param pResult Where to store the result.
4953 */
4954static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
4955{
4956// LogFlow(("dbgcOpSub\n"));
4957
4958 /*
4959 * An subtraction operation will return the left side type in the expression.
4960 * However, if the left hand side is a number and the right hand a pointer of
4961 * some kind we'll convert the left hand side to the same type as the right hand.
4962 * Any strings will be attempted resolved as symbols.
4963 */
4964 DBGCVAR Sym1, Sym2;
4965 if ( pArg2->enmType == DBGCVAR_TYPE_STRING
4966 && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER
4967 || pArg1->enmType == DBGCVAR_TYPE_STRING))
4968 {
4969 int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
4970 if (VBOX_FAILURE(rc))
4971 return rc;
4972 pArg2 = &Sym2;
4973 }
4974
4975 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
4976 {
4977 DBGCVARTYPE enmType;
4978 switch (pArg2->enmType)
4979 {
4980 case DBGCVAR_TYPE_NUMBER:
4981 enmType = DBGCVAR_TYPE_ANY;
4982 break;
4983 case DBGCVAR_TYPE_GC_FLAT:
4984 case DBGCVAR_TYPE_GC_PHYS:
4985 case DBGCVAR_TYPE_HC_FLAT:
4986 case DBGCVAR_TYPE_HC_PHYS:
4987 enmType = pArg2->enmType;
4988 break;
4989 case DBGCVAR_TYPE_GC_FAR:
4990 enmType = DBGCVAR_TYPE_GC_FLAT;
4991 break;
4992 case DBGCVAR_TYPE_HC_FAR:
4993 enmType = DBGCVAR_TYPE_HC_FLAT;
4994 break;
4995
4996 default:
4997 case DBGCVAR_TYPE_STRING:
4998 AssertMsgFailed(("Can't happen\n"));
4999 enmType = DBGCVAR_TYPE_STRING;
5000 break;
5001 }
5002 if (enmType != DBGCVAR_TYPE_STRING)
5003 {
5004 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
5005 if (VBOX_FAILURE(rc))
5006 return rc;
5007 pArg1 = &Sym1;
5008 }
5009 }
5010 else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)
5011 {
5012 PFNDBGCOPUNARY pOp = NULL;
5013 switch (pArg2->enmType)
5014 {
5015 case DBGCVAR_TYPE_GC_FAR:
5016 case DBGCVAR_TYPE_GC_FLAT:
5017 pOp = dbgcOpAddrFlat;
5018 break;
5019 case DBGCVAR_TYPE_GC_PHYS:
5020 pOp = dbgcOpAddrPhys;
5021 break;
5022 case DBGCVAR_TYPE_HC_FAR:
5023 case DBGCVAR_TYPE_HC_FLAT:
5024 pOp = dbgcOpAddrHost;
5025 break;
5026 case DBGCVAR_TYPE_HC_PHYS:
5027 pOp = dbgcOpAddrHostPhys;
5028 break;
5029 case DBGCVAR_TYPE_NUMBER:
5030 break;
5031 default:
5032 case DBGCVAR_TYPE_STRING:
5033 AssertMsgFailed(("Can't happen\n"));
5034 break;
5035 }
5036 if (pOp)
5037 {
5038 int rc = pOp(pDbgc, pArg1, &Sym1);
5039 if (VBOX_FAILURE(rc))
5040 return rc;
5041 pArg1 = &Sym1;
5042 }
5043 }
5044
5045
5046 /*
5047 * Normal processing.
5048 */
5049 int rc;
5050 DBGCVAR Var;
5051 DBGCVAR Var2;
5052 switch (pArg1->enmType)
5053 {
5054 /*
5055 * GC Flat
5056 */
5057 case DBGCVAR_TYPE_GC_FLAT:
5058 switch (pArg2->enmType)
5059 {
5060 case DBGCVAR_TYPE_HC_FLAT:
5061 case DBGCVAR_TYPE_HC_FAR:
5062 case DBGCVAR_TYPE_HC_PHYS:
5063 return VERR_PARSE_INVALID_OPERATION;
5064 default:
5065 *pResult = *pArg1;
5066 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5067 if (VBOX_FAILURE(rc))
5068 return rc;
5069 pResult->u.GCFlat -= pArg2->u.GCFlat;
5070 break;
5071 }
5072 break;
5073
5074 /*
5075 * GC Far
5076 */
5077 case DBGCVAR_TYPE_GC_FAR:
5078 switch (pArg2->enmType)
5079 {
5080 case DBGCVAR_TYPE_HC_FLAT:
5081 case DBGCVAR_TYPE_HC_FAR:
5082 case DBGCVAR_TYPE_HC_PHYS:
5083 return VERR_PARSE_INVALID_OPERATION;
5084 case DBGCVAR_TYPE_NUMBER:
5085 *pResult = *pArg1;
5086 pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;
5087 break;
5088 default:
5089 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5090 if (VBOX_FAILURE(rc))
5091 return rc;
5092 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5093 if (VBOX_FAILURE(rc))
5094 return rc;
5095 pResult->u.GCFlat -= pArg2->u.GCFlat;
5096 break;
5097 }
5098 break;
5099
5100 /*
5101 * GC Phys
5102 */
5103 case DBGCVAR_TYPE_GC_PHYS:
5104 switch (pArg2->enmType)
5105 {
5106 case DBGCVAR_TYPE_HC_FLAT:
5107 case DBGCVAR_TYPE_HC_FAR:
5108 case DBGCVAR_TYPE_HC_PHYS:
5109 return VERR_PARSE_INVALID_OPERATION;
5110 default:
5111 *pResult = *pArg1;
5112 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
5113 if (VBOX_FAILURE(rc))
5114 return rc;
5115 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
5116 return VERR_PARSE_INVALID_OPERATION;
5117 pResult->u.GCPhys -= Var.u.GCPhys;
5118 break;
5119 }
5120 break;
5121
5122 /*
5123 * HC Flat
5124 */
5125 case DBGCVAR_TYPE_HC_FLAT:
5126 *pResult = *pArg1;
5127 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5128 if (VBOX_FAILURE(rc))
5129 return rc;
5130 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5131 if (VBOX_FAILURE(rc))
5132 return rc;
5133 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
5134 break;
5135
5136 /*
5137 * HC Far
5138 */
5139 case DBGCVAR_TYPE_HC_FAR:
5140 switch (pArg2->enmType)
5141 {
5142 case DBGCVAR_TYPE_NUMBER:
5143 *pResult = *pArg1;
5144 pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;
5145 break;
5146
5147 default:
5148 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5149 if (VBOX_FAILURE(rc))
5150 return rc;
5151 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5152 if (VBOX_FAILURE(rc))
5153 return rc;
5154 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5155 if (VBOX_FAILURE(rc))
5156 return rc;
5157 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
5158 break;
5159 }
5160 break;
5161
5162 /*
5163 * HC Phys
5164 */
5165 case DBGCVAR_TYPE_HC_PHYS:
5166 *pResult = *pArg1;
5167 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
5168 if (VBOX_FAILURE(rc))
5169 return rc;
5170 pResult->u.HCPhys -= Var.u.HCPhys;
5171 break;
5172
5173 /*
5174 * Numbers (see start of function)
5175 */
5176 case DBGCVAR_TYPE_NUMBER:
5177 switch (pArg2->enmType)
5178 {
5179 case DBGCVAR_TYPE_STRING:
5180 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
5181 if (VBOX_FAILURE(rc))
5182 return rc;
5183 case DBGCVAR_TYPE_NUMBER:
5184 pResult->u.u64Number -= pArg2->u.u64Number;
5185 break;
5186 default:
5187 return VERR_PARSE_INVALID_OPERATION;
5188 }
5189 break;
5190
5191 default:
5192 return VERR_PARSE_INVALID_OPERATION;
5193
5194 }
5195 return 0;
5196}
5197
5198
5199/**
5200 * Bitwise shift left operator (binary).
5201 *
5202 * @returns 0 on success.
5203 * @returns VBox evaluation / parsing error code on failure.
5204 * The caller does the bitching.
5205 * @param pDbgc Debugger console instance data.
5206 * @param pArg1 The first argument.
5207 * @param pArg2 The 2nd argument.
5208 * @param pResult Where to store the result.
5209 */
5210static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5211{
5212 LogFlow(("dbgcOpBitwiseShiftLeft\n"));
5213 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5214 return -1;
5215}
5216
5217
5218/**
5219 * Bitwise shift right operator (binary).
5220 *
5221 * @returns 0 on success.
5222 * @returns VBox evaluation / parsing error code on failure.
5223 * The caller does the bitching.
5224 * @param pDbgc Debugger console instance data.
5225 * @param pArg1 The first argument.
5226 * @param pArg2 The 2nd argument.
5227 * @param pResult Where to store the result.
5228 */
5229static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5230{
5231 LogFlow(("dbgcOpBitwiseShiftRight\n"));
5232 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5233 return -1;
5234}
5235
5236
5237/**
5238 * Bitwise and operator (binary).
5239 *
5240 * @returns 0 on success.
5241 * @returns VBox evaluation / parsing error code on failure.
5242 * The caller does the bitching.
5243 * @param pDbgc Debugger console instance data.
5244 * @param pArg1 The first argument.
5245 * @param pArg2 The 2nd argument.
5246 * @param pResult Where to store the result.
5247 */
5248static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5249{
5250 LogFlow(("dbgcOpBitwiseAnd\n"));
5251 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5252 return -1;
5253}
5254
5255
5256/**
5257 * Bitwise exclusive or operator (binary).
5258 *
5259 * @returns 0 on success.
5260 * @returns VBox evaluation / parsing error code on failure.
5261 * The caller does the bitching.
5262 * @param pDbgc Debugger console instance data.
5263 * @param pArg1 The first argument.
5264 * @param pArg2 The 2nd argument.
5265 * @param pResult Where to store the result.
5266 */
5267static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5268{
5269 LogFlow(("dbgcOpBitwiseXor\n"));
5270 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5271 return -1;
5272}
5273
5274
5275/**
5276 * Bitwise inclusive or operator (binary).
5277 *
5278 * @returns 0 on success.
5279 * @returns VBox evaluation / parsing error code on failure.
5280 * The caller does the bitching.
5281 * @param pDbgc Debugger console instance data.
5282 * @param pArg1 The first argument.
5283 * @param pArg2 The 2nd argument.
5284 * @param pResult Where to store the result.
5285 */
5286static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5287{
5288 LogFlow(("dbgcOpBitwiseOr\n"));
5289 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5290 return -1;
5291}
5292
5293
5294/**
5295 * Boolean and operator (binary).
5296 *
5297 * @returns 0 on success.
5298 * @returns VBox evaluation / parsing error code on failure.
5299 * The caller does the bitching.
5300 * @param pDbgc Debugger console instance data.
5301 * @param pArg1 The first argument.
5302 * @param pArg2 The 2nd argument.
5303 * @param pResult Where to store the result.
5304 */
5305static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5306{
5307 LogFlow(("dbgcOpBooleanAnd\n"));
5308 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5309 return -1;
5310}
5311
5312
5313/**
5314 * Boolean or operator (binary).
5315 *
5316 * @returns 0 on success.
5317 * @returns VBox evaluation / parsing error code on failure.
5318 * The caller does the bitching.
5319 * @param pDbgc Debugger console instance data.
5320 * @param pArg1 The first argument.
5321 * @param pArg2 The 2nd argument.
5322 * @param pResult Where to store the result.
5323 */
5324static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5325{
5326 LogFlow(("dbgcOpBooleanOr\n"));
5327 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5328 return -1;
5329}
5330
5331
5332/**
5333 * Range to operator (binary).
5334 *
5335 * @returns 0 on success.
5336 * @returns VBox evaluation / parsing error code on failure.
5337 * The caller does the bitching.
5338 * @param pDbgc Debugger console instance data.
5339 * @param pArg1 The first argument.
5340 * @param pArg2 The 2nd argument.
5341 * @param pResult Where to store the result.
5342 */
5343static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5344{
5345// LogFlow(("dbgcOpRangeLength\n"));
5346 /*
5347 * Make result. Strings needs to be resolved into symbols.
5348 */
5349 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
5350 {
5351 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
5352 if (VBOX_FAILURE(rc))
5353 return rc;
5354 }
5355 else
5356 *pResult = *pArg1;
5357
5358 /*
5359 * Convert 2nd argument to element count.
5360 */
5361 pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;
5362 switch (pArg2->enmType)
5363 {
5364 case DBGCVAR_TYPE_NUMBER:
5365 pResult->u64Range = pArg2->u.u64Number;
5366 break;
5367
5368 case DBGCVAR_TYPE_STRING:
5369 {
5370 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
5371 if (VBOX_FAILURE(rc))
5372 return rc;
5373 pResult->u64Range = pArg2->u.u64Number;
5374 break;
5375 }
5376
5377 default:
5378 return VERR_PARSE_INVALID_OPERATION;
5379 }
5380
5381 return VINF_SUCCESS;
5382}
5383
5384
5385/**
5386 * Range to operator (binary).
5387 *
5388 * @returns 0 on success.
5389 * @returns VBox evaluation / parsing error code on failure.
5390 * The caller does the bitching.
5391 * @param pDbgc Debugger console instance data.
5392 * @param pArg1 The first argument.
5393 * @param pArg2 The 2nd argument.
5394 * @param pResult Where to store the result.
5395 */
5396static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5397{
5398// LogFlow(("dbgcOpRangeLengthBytes\n"));
5399 int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);
5400 if (VBOX_SUCCESS(rc))
5401 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
5402 return rc;
5403}
5404
5405
5406/**
5407 * Range to operator (binary).
5408 *
5409 * @returns 0 on success.
5410 * @returns VBox evaluation / parsing error code on failure.
5411 * The caller does the bitching.
5412 * @param pDbgc Debugger console instance data.
5413 * @param pArg1 The first argument.
5414 * @param pArg2 The 2nd argument.
5415 * @param pResult Where to store the result.
5416 */
5417static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5418{
5419// LogFlow(("dbgcOpRangeTo\n"));
5420 /*
5421 * Calc number of bytes between the two args.
5422 */
5423 DBGCVAR Diff;
5424 int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);
5425 if (VBOX_FAILURE(rc))
5426 return rc;
5427
5428 /*
5429 * Use the diff as the range of Arg1.
5430 */
5431 *pResult = *pArg1;
5432 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
5433 switch (Diff.enmType)
5434 {
5435 case DBGCVAR_TYPE_GC_FLAT:
5436 pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;
5437 break;
5438 case DBGCVAR_TYPE_GC_PHYS:
5439 pResult->u64Range = Diff.u.GCPhys;
5440 break;
5441 case DBGCVAR_TYPE_HC_FLAT:
5442 pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;
5443 break;
5444 case DBGCVAR_TYPE_HC_PHYS:
5445 pResult->u64Range = Diff.u.HCPhys;
5446 break;
5447 case DBGCVAR_TYPE_NUMBER:
5448 pResult->u64Range = Diff.u.u64Number;
5449 break;
5450
5451 case DBGCVAR_TYPE_GC_FAR:
5452 case DBGCVAR_TYPE_STRING:
5453 case DBGCVAR_TYPE_HC_FAR:
5454 default:
5455 AssertMsgFailed(("Impossible!\n"));
5456 return VERR_PARSE_INVALID_OPERATION;
5457 }
5458
5459 return 0;
5460}
5461
5462
5463
5464
5465
5466/**
5467 * Output callback.
5468 *
5469 * @returns number of bytes written.
5470 * @param pvArg User argument.
5471 * @param pachChars Pointer to an array of utf-8 characters.
5472 * @param cbChars Number of bytes in the character array pointed to by pachChars.
5473 */
5474static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
5475{
5476 PDBGC pDbgc = (PDBGC)pvArg;
5477 if (cbChars)
5478 {
5479 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
5480 if (VBOX_FAILURE(rc))
5481 {
5482 pDbgc->rcOutput = rc;
5483 cbChars = 0;
5484 }
5485 }
5486
5487 return cbChars;
5488}
5489
5490
5491
5492
5493
5494
5495
5496
5497
5498//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
5499//
5500//
5501// C a l l b a c k H e l p e r s
5502//
5503//
5504//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
5505
5506
5507
5508/**
5509 * Command helper for writing text to the debug console.
5510 *
5511 * @returns VBox status.
5512 * @param pCmdHlp Pointer to the command callback structure.
5513 * @param pvBuf What to write.
5514 * @param cbBuf Number of bytes to write.
5515 * @param pcbWritten Where to store the number of bytes actually written.
5516 * If NULL the entire buffer must be successfully written.
5517 */
5518static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
5519{
5520 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5521 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
5522}
5523
5524
5525/**
5526 * Command helper for writing formatted text to the debug console.
5527 *
5528 * @returns VBox status.
5529 * @param pCmdHlp Pointer to the command callback structure.
5530 * @param pcb Where to store the number of bytes written.
5531 * @param pszFormat The format string.
5532 * This is using the log formatter, so it's format extensions can be used.
5533 * @param ... Arguments specified in the format string.
5534 */
5535static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
5536{
5537 /*
5538 * Do the formatting and output.
5539 */
5540 va_list args;
5541 va_start(args, pszFormat);
5542 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
5543 va_end(args);
5544
5545 return rc;
5546}
5547
5548/**
5549 * Callback to format non-standard format specifiers.
5550 *
5551 * @returns The number of bytes formatted.
5552 * @param pvArg Formatter argument.
5553 * @param pfnOutput Pointer to output function.
5554 * @param pvArgOutput Argument for the output function.
5555 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
5556 * after the format specifier.
5557 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
5558 * @param cchWidth Format Width. -1 if not specified.
5559 * @param cchPrecision Format Precision. -1 if not specified.
5560 * @param fFlags Flags (RTSTR_NTFS_*).
5561 * @param chArgSize The argument size specifier, 'l' or 'L'.
5562 */
5563static DECLCALLBACK(int) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
5564 const char **ppszFormat, va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
5565{
5566 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
5567 if (**ppszFormat != 'D')
5568 {
5569 (*ppszFormat)++;
5570 return 0;
5571 }
5572
5573 (*ppszFormat)++;
5574 switch (**ppszFormat)
5575 {
5576 /*
5577 * Print variable without range.
5578 * The argument is a const pointer to the variable.
5579 */
5580 case 'V':
5581 {
5582 (*ppszFormat)++;
5583 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
5584 switch (pVar->enmType)
5585 {
5586 case DBGCVAR_TYPE_GC_FLAT:
5587 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
5588 case DBGCVAR_TYPE_GC_FAR:
5589 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
5590 case DBGCVAR_TYPE_GC_PHYS:
5591 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
5592 case DBGCVAR_TYPE_HC_FLAT:
5593 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
5594 case DBGCVAR_TYPE_HC_FAR:
5595 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
5596 case DBGCVAR_TYPE_HC_PHYS:
5597 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
5598 case DBGCVAR_TYPE_STRING:
5599 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
5600 case DBGCVAR_TYPE_NUMBER:
5601 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
5602
5603 case DBGCVAR_TYPE_UNKNOWN:
5604 default:
5605 return pfnOutput(pvArgOutput, "??", 2);
5606 }
5607 }
5608
5609 /*
5610 * Print variable with range.
5611 * The argument is a const pointer to the variable.
5612 */
5613 case 'v':
5614 {
5615 (*ppszFormat)++;
5616 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
5617
5618 char szRange[32];
5619 switch (pVar->enmRangeType)
5620 {
5621 case DBGCVAR_RANGE_NONE:
5622 szRange[0] = '\0';
5623 break;
5624 case DBGCVAR_RANGE_ELEMENTS:
5625 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
5626 break;
5627 case DBGCVAR_RANGE_BYTES:
5628 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
5629 break;
5630 }
5631
5632 switch (pVar->enmType)
5633 {
5634 case DBGCVAR_TYPE_GC_FLAT:
5635 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
5636 case DBGCVAR_TYPE_GC_FAR:
5637 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
5638 case DBGCVAR_TYPE_GC_PHYS:
5639 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
5640 case DBGCVAR_TYPE_HC_FLAT:
5641 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
5642 case DBGCVAR_TYPE_HC_FAR:
5643 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
5644 case DBGCVAR_TYPE_HC_PHYS:
5645 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
5646 case DBGCVAR_TYPE_STRING:
5647 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
5648 case DBGCVAR_TYPE_NUMBER:
5649 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
5650
5651 case DBGCVAR_TYPE_UNKNOWN:
5652 default:
5653 return pfnOutput(pvArgOutput, "??", 2);
5654 }
5655 }
5656
5657 default:
5658 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
5659 return 0;
5660 }
5661}
5662
5663
5664/**
5665 * Command helper for writing formatted text to the debug console.
5666 *
5667 * @returns VBox status.
5668 * @param pCmdHlp Pointer to the command callback structure.
5669 * @param pcb Where to store the number of bytes written.
5670 * @param pszFormat The format string.
5671 * This is using the log formatter, so it's format extensions can be used.
5672 * @param args Arguments specified in the format string.
5673 */
5674static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
5675{
5676 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5677
5678 /*
5679 * Do the formatting and output.
5680 */
5681 pDbgc->rcOutput = 0;
5682 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
5683
5684 if (pcbWritten)
5685 *pcbWritten = cb;
5686
5687 return pDbgc->rcOutput;
5688}
5689
5690
5691/**
5692 * Reports an error from a DBGF call.
5693 *
5694 * @returns VBox status code appropriate to return from a command.
5695 * @param pCmdHlp Pointer to command helpers.
5696 * @param rc The VBox status code returned by a DBGF call.
5697 * @param pszFormat Format string for additional messages. Can be NULL.
5698 * @param ... Format arguments, optional.
5699 */
5700static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
5701{
5702 switch (rc)
5703 {
5704 case VINF_SUCCESS:
5705 break;
5706
5707 default:
5708 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
5709 if (VBOX_SUCCESS(rc) && pszFormat)
5710 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
5711 break;
5712 }
5713 return rc;
5714}
5715
5716
5717/**
5718 * Reports an error from a DBGF call.
5719 *
5720 * @returns VBox status code appropriate to return from a command.
5721 * @param pCmdHlp Pointer to command helpers.
5722 * @param rc The VBox status code returned by a DBGF call.
5723 * @param pszFormat Format string for additional messages. Can be NULL.
5724 * @param ... Format arguments, optional.
5725 */
5726static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
5727{
5728 va_list args;
5729 va_start(args, pszFormat);
5730 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
5731 va_end(args);
5732 return rcRet;
5733}
5734
5735
5736/**
5737 * Command helper for reading memory specified by a DBGC variable.
5738 *
5739 * @returns VBox status code appropriate to return from a command.
5740 * @param pCmdHlp Pointer to the command callback structure.
5741 * @param pVM VM handle if GC or physical HC address.
5742 * @param pvBuffer Where to store the read data.
5743 * @param cbRead Number of bytes to read.
5744 * @param pVarPointer DBGC variable specifying where to start reading.
5745 * @param pcbRead Where to store the number of bytes actually read.
5746 * This optional, but it's useful when read GC virtual memory where a
5747 * page in the requested range might not be present.
5748 * If not specified not-present failure or end of a HC physical page
5749 * will cause failure.
5750 */
5751static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
5752{
5753 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5754
5755 /*
5756 * Dummy check.
5757 */
5758 if (cbRead == 0)
5759 {
5760 if (*pcbRead)
5761 *pcbRead = 0;
5762 return VINF_SUCCESS;
5763 }
5764
5765 /*
5766 * Convert Far addresses getting size and the correct base address.
5767 */
5768 DBGCVAR Var = *pVarPointer;
5769 switch (pVarPointer->enmType)
5770 {
5771 case DBGCVAR_TYPE_GC_FAR:
5772 {
5773 uint32_t cb;
5774 PCPUMCTX pCtx;
5775 CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
5776
5777 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
5778 int rc = SELMToFlatEx(pDbgc->pVM, pCtx->eflags, Var.u.GCFar.sel, Var.u.GCFar.off, NULL,
5779 SELMTOFLAT_FLAGS_NO_PL | SELMTOFLAT_FLAGS_HYPER, &Var.u.GCFlat, &cb);
5780 if (VBOX_FAILURE(rc))
5781 return rc;
5782 if (cbRead > cb)
5783 {
5784 if (!pcbRead)
5785 return VERR_OUT_OF_SELECTOR_BOUNDS;
5786 cbRead = cb;
5787 }
5788 break;
5789 }
5790
5791 case DBGCVAR_TYPE_HC_FAR:
5792 /* not supported yet! */
5793 return VERR_NOT_IMPLEMENTED;
5794
5795 case DBGCVAR_TYPE_GC_FLAT:
5796 case DBGCVAR_TYPE_GC_PHYS:
5797 case DBGCVAR_TYPE_HC_FLAT:
5798 case DBGCVAR_TYPE_HC_PHYS:
5799 break;
5800
5801 default:
5802 return VERR_NOT_IMPLEMENTED;
5803 }
5804
5805
5806
5807 /*
5808 * Copy page by page.
5809 */
5810 size_t cbLeft = cbRead;
5811 for (;;)
5812 {
5813 /*
5814 * Calc read size.
5815 */
5816 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
5817 switch (pVarPointer->enmType)
5818 {
5819 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
5820 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
5821 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
5822 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! */
5823 default: break;
5824 }
5825
5826 /*
5827 * Perform read.
5828 */
5829 int rc;
5830 switch (Var.enmType)
5831 {
5832 case DBGCVAR_TYPE_GC_FLAT:
5833 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
5834 break;
5835 case DBGCVAR_TYPE_GC_PHYS:
5836 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
5837 break;
5838
5839 case DBGCVAR_TYPE_HC_PHYS:
5840 case DBGCVAR_TYPE_HC_FLAT:
5841 case DBGCVAR_TYPE_HC_FAR:
5842 {
5843 DBGCVAR Var2;
5844 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
5845 if (VBOX_SUCCESS(rc))
5846 {
5847 /** @todo protect this!!! */
5848 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
5849 rc = 0;
5850 }
5851 else
5852 rc = VERR_INVALID_POINTER;
5853 break;
5854 }
5855
5856 default:
5857 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
5858 }
5859
5860 /*
5861 * Check for failure.
5862 */
5863 if (VBOX_FAILURE(rc))
5864 {
5865 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
5866 return VINF_SUCCESS;
5867 return rc;
5868 }
5869
5870 /*
5871 * Next.
5872 */
5873 cbLeft -= cb;
5874 if (!cbLeft)
5875 break;
5876 pvBuffer = (char *)pvBuffer + cb;
5877 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
5878 if (VBOX_FAILURE(rc))
5879 {
5880 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
5881 return VINF_SUCCESS;
5882 return rc;
5883 }
5884 }
5885
5886 /*
5887 * Done
5888 */
5889 if (pcbRead)
5890 *pcbRead = cbRead;
5891 return 0;
5892}
5893
5894/**
5895 * Command helper for writing memory specified by a DBGC variable.
5896 *
5897 * @returns VBox status code appropriate to return from a command.
5898 * @param pCmdHlp Pointer to the command callback structure.
5899 * @param pVM VM handle if GC or physical HC address.
5900 * @param pvBuffer What to write.
5901 * @param cbWrite Number of bytes to write.
5902 * @param pVarPointer DBGC variable specifying where to start reading.
5903 * @param pcbWritten Where to store the number of bytes written.
5904 * This is optional. If NULL be aware that some of the buffer
5905 * might have been written to the specified address.
5906 */
5907static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
5908{
5909 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
5910 return VERR_NOT_IMPLEMENTED;
5911}
5912
5913
5914/**
5915 * Evaluates an expression.
5916 * (Hopefully the parser and functions are fully reentrant.)
5917 *
5918 * @returns VBox status code appropriate to return from a command.
5919 * @param pCmdHlp Pointer to the command callback structure.
5920 * @param pResult Where to store the result.
5921 * @param pszExpr The expression. Format string with the format DBGC extensions.
5922 * @param ... Format arguments.
5923 */
5924static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
5925{
5926 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5927
5928 /*
5929 * Format the expression.
5930 */
5931 char szExprFormatted[2048];
5932 va_list args;
5933 va_start(args, pszExpr);
5934 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
5935 va_end(args);
5936 /* ignore overflows. */
5937
5938 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
5939}
5940
5941
5942/**
5943 * Executes one command expression.
5944 * (Hopefully the parser and functions are fully reentrant.)
5945 *
5946 * @returns VBox status code appropriate to return from a command.
5947 * @param pCmdHlp Pointer to the command callback structure.
5948 * @param pszExpr The expression. Format string with the format DBGC extensions.
5949 * @param ... Format arguments.
5950 */
5951static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
5952{
5953 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5954 /* Save the scratch state. */
5955 char *pszScratch = pDbgc->pszScratch;
5956 unsigned iArg = pDbgc->iArg;
5957
5958 /*
5959 * Format the expression.
5960 */
5961 va_list args;
5962 va_start(args, pszExpr);
5963 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
5964 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
5965 va_end(args);
5966 if (cb >= cbScratch)
5967 return VERR_BUFFER_OVERFLOW;
5968
5969 /*
5970 * Execute the command.
5971 * We save and restore the arg index and scratch buffer pointer.
5972 */
5973 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
5974 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
5975
5976 /* Restore the scratch state. */
5977 pDbgc->iArg = iArg;
5978 pDbgc->pszScratch = pszScratch;
5979
5980 return rc;
5981}
5982
5983
5984/**
5985 * Converts a DBGC variable to a DBGF address structure.
5986 *
5987 * @returns VBox status code.
5988 * @param pCmdHlp Pointer to the command callback structure.
5989 * @param pVar The variable to convert.
5990 * @param pAddress The target address.
5991 */
5992static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
5993{
5994 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
5995 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
5996}
5997
5998
5999/**
6000 * Converts a DBGC variable to a boolean.
6001 *
6002 * @returns VBox status code.
6003 * @param pCmdHlp Pointer to the command callback structure.
6004 * @param pVar The variable to convert.
6005 * @param pf Where to store the boolean.
6006 */
6007static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
6008{
6009 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6010 NOREF(pDbgc);
6011
6012 switch (pVar->enmType)
6013 {
6014 case DBGCVAR_TYPE_STRING:
6015 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
6016 if ( !strcmp(pVar->u.pszString, "true")
6017 || !strcmp(pVar->u.pszString, "True")
6018 || !strcmp(pVar->u.pszString, "TRUE")
6019 || !strcmp(pVar->u.pszString, "on")
6020 || !strcmp(pVar->u.pszString, "On")
6021 || !strcmp(pVar->u.pszString, "oN")
6022 || !strcmp(pVar->u.pszString, "ON")
6023 || !strcmp(pVar->u.pszString, "enabled")
6024 || !strcmp(pVar->u.pszString, "Enabled")
6025 || !strcmp(pVar->u.pszString, "DISABLED"))
6026 {
6027 *pf = true;
6028 return VINF_SUCCESS;
6029 }
6030 if ( !strcmp(pVar->u.pszString, "false")
6031 || !strcmp(pVar->u.pszString, "False")
6032 || !strcmp(pVar->u.pszString, "FALSE")
6033 || !strcmp(pVar->u.pszString, "off")
6034 || !strcmp(pVar->u.pszString, "Off")
6035 || !strcmp(pVar->u.pszString, "OFF")
6036 || !strcmp(pVar->u.pszString, "disabled")
6037 || !strcmp(pVar->u.pszString, "Disabled")
6038 || !strcmp(pVar->u.pszString, "DISABLED"))
6039 {
6040 *pf = false;
6041 return VINF_SUCCESS;
6042 }
6043 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
6044
6045 case DBGCVAR_TYPE_GC_FLAT:
6046 case DBGCVAR_TYPE_GC_PHYS:
6047 case DBGCVAR_TYPE_HC_FLAT:
6048 case DBGCVAR_TYPE_HC_PHYS:
6049 case DBGCVAR_TYPE_NUMBER:
6050 *pf = pVar->u.u64Number != 0;
6051 return VINF_SUCCESS;
6052
6053 case DBGCVAR_TYPE_HC_FAR:
6054 case DBGCVAR_TYPE_GC_FAR:
6055 case DBGCVAR_TYPE_SYMBOL:
6056 default:
6057 return VERR_PARSE_INCORRECT_ARG_TYPE;
6058 }
6059}
6060
6061
6062
6063
6064
6065//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6066//
6067//
6068// V a r i a b l e M a n i p u l a t i o n
6069//
6070//
6071//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6072
6073
6074
6075/** @todo move me!*/
6076static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
6077{
6078 if (pVar)
6079 {
6080 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6081 pVar->u.GCFlat = GCFlat;
6082 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6083 pVar->u64Range = 0;
6084 }
6085}
6086
6087
6088/** @todo move me!*/
6089static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
6090{
6091 if (pVar)
6092 {
6093 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6094 pVar->u.GCFlat = GCFlat;
6095 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
6096 pVar->u64Range = cb;
6097 }
6098}
6099
6100
6101/** @todo move me!*/
6102static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
6103{
6104 if (pVar)
6105 {
6106 if (pVar2)
6107 *pVar = *pVar2;
6108 else
6109 {
6110 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
6111 memset(&pVar->u, 0, sizeof(pVar->u));
6112 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6113 pVar->u64Range = 0;
6114 }
6115 }
6116}
6117
6118
6119/** @todo move me!*/
6120static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
6121{
6122 if (pVar)
6123 {
6124 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
6125 pVar->u64Range = cb;
6126 }
6127}
6128
6129
6130/** @todo move me!*/
6131static void dbgcVarSetNoRange(PDBGCVAR pVar)
6132{
6133 if (pVar)
6134 {
6135 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6136 pVar->u64Range = 0;
6137 }
6138}
6139
6140
6141/**
6142 * Converts a DBGC variable to a DBGF address.
6143 *
6144 * @returns VBox status code.
6145 * @param pDbgc The DBGC instance.
6146 * @param pVar The variable.
6147 * @param pAddress Where to store the address.
6148 */
6149static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
6150{
6151 AssertReturn(pVar, VERR_INVALID_PARAMETER);
6152 switch (pVar->enmType)
6153 {
6154 case DBGCVAR_TYPE_GC_FLAT:
6155 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
6156 return VINF_SUCCESS;
6157
6158 case DBGCVAR_TYPE_NUMBER:
6159 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
6160 return VINF_SUCCESS;
6161
6162 case DBGCVAR_TYPE_GC_FAR:
6163 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
6164
6165 case DBGCVAR_TYPE_STRING:
6166 case DBGCVAR_TYPE_SYMBOL:
6167 {
6168 DBGCVAR Var;
6169 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
6170 if (VBOX_FAILURE(rc))
6171 return rc;
6172 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
6173 }
6174
6175 case DBGCVAR_TYPE_GC_PHYS:
6176 case DBGCVAR_TYPE_HC_FLAT:
6177 case DBGCVAR_TYPE_HC_FAR:
6178 case DBGCVAR_TYPE_HC_PHYS:
6179 default:
6180 return VERR_PARSE_CONVERSION_FAILED;
6181 }
6182}
6183
6184
6185
6186//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6187//
6188//
6189// B r e a k p o i n t M a n a g e m e n t
6190//
6191//
6192//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6193
6194
6195/**
6196 * Adds a breakpoint to the DBGC breakpoint list.
6197 */
6198static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
6199{
6200 /*
6201 * Check if it already exists.
6202 */
6203 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
6204 if (pBp)
6205 return VERR_DBGC_BP_EXISTS;
6206
6207 /*
6208 * Add the breakpoint.
6209 */
6210 if (pszCmd)
6211 pszCmd = RTStrStripL(pszCmd);
6212 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
6213 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
6214 if (!pBp)
6215 return VERR_NO_MEMORY;
6216 if (cchCmd)
6217 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
6218 else
6219 pBp->szCmd[0] = '\0';
6220 pBp->cchCmd = cchCmd;
6221 pBp->iBp = iBp;
6222 pBp->pNext = pDbgc->pFirstBp;
6223 pDbgc->pFirstBp = pBp;
6224
6225 return VINF_SUCCESS;
6226}
6227
6228/**
6229 * Updates the a breakpoint.
6230 *
6231 * @returns VBox status code.
6232 * @param pDbgc The DBGC instance.
6233 * @param iBp The breakpoint to update.
6234 * @param pszCmd The new command.
6235 */
6236static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
6237{
6238 /*
6239 * Find the breakpoint.
6240 */
6241 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
6242 if (!pBp)
6243 return VERR_DBGC_BP_NOT_FOUND;
6244
6245 /*
6246 * Do we need to reallocate?
6247 */
6248 if (pszCmd)
6249 pszCmd = RTStrStripL(pszCmd);
6250 if (!pszCmd || !*pszCmd)
6251 pBp->szCmd[0] = '\0';
6252 else
6253 {
6254 size_t cchCmd = strlen(pszCmd);
6255 if (strlen(pBp->szCmd) >= cchCmd)
6256 {
6257 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
6258 pBp->cchCmd = cchCmd;
6259 }
6260 else
6261 {
6262 /*
6263 * Yes, let's do it the simple way...
6264 */
6265 int rc = dbgcBpDelete(pDbgc, iBp);
6266 AssertRC(rc);
6267 return dbgcBpAdd(pDbgc, iBp, pszCmd);
6268 }
6269 }
6270 return VINF_SUCCESS;
6271}
6272
6273
6274/**
6275 * Deletes a breakpoint.
6276 *
6277 * @returns VBox status code.
6278 * @param pDbgc The DBGC instance.
6279 * @param iBp The breakpoint to delete.
6280 */
6281static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
6282{
6283 /*
6284 * Search thru the list, when found unlink and free it.
6285 */
6286 PDBGCBP pBpPrev = NULL;
6287 PDBGCBP pBp = pDbgc->pFirstBp;
6288 for (; pBp; pBp = pBp->pNext)
6289 {
6290 if (pBp->iBp == iBp)
6291 {
6292 if (pBpPrev)
6293 pBpPrev->pNext = pBp->pNext;
6294 else
6295 pDbgc->pFirstBp = pBp->pNext;
6296 RTMemFree(pBp);
6297 return VINF_SUCCESS;
6298 }
6299 pBpPrev = pBp;
6300 }
6301
6302 return VERR_DBGC_BP_NOT_FOUND;
6303}
6304
6305
6306/**
6307 * Get a breakpoint.
6308 *
6309 * @returns Pointer to the breakpoint.
6310 * @returns NULL if the breakpoint wasn't found.
6311 * @param pDbgc The DBGC instance.
6312 * @param iBp The breakpoint to get.
6313 */
6314static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
6315{
6316 /*
6317 * Enumerate the list.
6318 */
6319 PDBGCBP pBp = pDbgc->pFirstBp;
6320 for (; pBp; pBp = pBp->pNext)
6321 if (pBp->iBp == iBp)
6322 return pBp;
6323 return NULL;
6324}
6325
6326
6327/**
6328 * Executes the command of a breakpoint.
6329 *
6330 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
6331 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
6332 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
6333 * @returns VBox status code from dbgcProcessCommand() other wise.
6334 * @param pDbgc The DBGC instance.
6335 * @param iBp The breakpoint to execute.
6336 */
6337static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
6338{
6339 /*
6340 * Find the breakpoint.
6341 */
6342 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
6343 if (!pBp)
6344 return VERR_DBGC_BP_NOT_FOUND;
6345
6346 /*
6347 * Anything to do?
6348 */
6349 if (!pBp->cchCmd)
6350 return VINF_DBGC_BP_NO_COMMAND;
6351
6352 /*
6353 * Execute the command.
6354 * This means copying it to the scratch buffer and process it as if it
6355 * were user input. We must save and restore the state of the scratch buffer.
6356 */
6357 /* Save the scratch state. */
6358 char *pszScratch = pDbgc->pszScratch;
6359 unsigned iArg = pDbgc->iArg;
6360
6361 /* Copy the command to the scratch buffer. */
6362 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
6363 if (pBp->cchCmd >= cbScratch)
6364 return VERR_BUFFER_OVERFLOW;
6365 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
6366
6367 /* Execute the command. */
6368 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
6369 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
6370
6371 /* Restore the scratch state. */
6372 pDbgc->iArg = iArg;
6373 pDbgc->pszScratch = pszScratch;
6374
6375 return rc;
6376}
6377
6378
6379
6380
6381
6382//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6383//
6384//
6385// I n p u t , p a r s i n g a n d l o g g i n g
6386//
6387//
6388//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6389
6390
6391
6392/**
6393 * Prints any log lines from the log buffer.
6394 *
6395 * The caller must not call function this unless pDbgc->fLog is set.
6396 *
6397 * @returns VBox status. (output related)
6398 * @param pDbgc Debugger console instance data.
6399 */
6400static int dbgcProcessLog(PDBGC pDbgc)
6401{
6402 /** @todo */
6403 NOREF(pDbgc);
6404 return 0;
6405}
6406
6407
6408
6409/**
6410 * Handle input buffer overflow.
6411 *
6412 * Will read any available input looking for a '\n' to reset the buffer on.
6413 *
6414 * @returns VBox status.
6415 * @param pDbgc Debugger console instance data.
6416 */
6417static int dbgcInputOverflow(PDBGC pDbgc)
6418{
6419 /*
6420 * Assert overflow status and reset the input buffer.
6421 */
6422 if (!pDbgc->fInputOverflow)
6423 {
6424 pDbgc->fInputOverflow = true;
6425 pDbgc->iRead = pDbgc->iWrite = 0;
6426 pDbgc->cInputLines = 0;
6427 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
6428 }
6429
6430 /*
6431 * Eat input till no more or there is a '\n'.
6432 * When finding a '\n' we'll continue normal processing.
6433 */
6434 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
6435 {
6436 size_t cbRead;
6437 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
6438 if (VBOX_FAILURE(rc))
6439 return rc;
6440 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
6441 if (psz)
6442 {
6443 pDbgc->fInputOverflow = false;
6444 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
6445 pDbgc->iWrite = cbRead;
6446 pDbgc->cInputLines = 0;
6447 break;
6448 }
6449 }
6450
6451 return 0;
6452}
6453
6454
6455
6456/**
6457 * Read input and do some preprocessing.
6458 *
6459 * @returns VBox status.
6460 * In addition to the iWrite and achInput, cInputLines is maintained.
6461 * In case of an input overflow the fInputOverflow flag will be set.
6462 * @param pDbgc Debugger console instance data.
6463 */
6464static int dbgcInputRead(PDBGC pDbgc)
6465{
6466 /*
6467 * We have ready input.
6468 * Read it till we don't have any or we have a full input buffer.
6469 */
6470 int rc = 0;
6471 do
6472 {
6473 /*
6474 * More available buffer space?
6475 */
6476 size_t cbLeft;
6477 if (pDbgc->iWrite > pDbgc->iRead)
6478 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
6479 else
6480 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
6481 if (!cbLeft)
6482 {
6483 /* overflow? */
6484 if (!pDbgc->cInputLines)
6485 rc = dbgcInputOverflow(pDbgc);
6486 break;
6487 }
6488
6489 /*
6490 * Read one char and interpret it.
6491 */
6492 char achRead[128];
6493 size_t cbRead;
6494 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
6495 if (VBOX_FAILURE(rc))
6496 return rc;
6497 char *psz = &achRead[0];
6498 while (cbRead-- > 0)
6499 {
6500 char ch = *psz++;
6501 switch (ch)
6502 {
6503 /*
6504 * Ignore.
6505 */
6506 case '\0':
6507 case '\r':
6508 case '\a':
6509 break;
6510
6511 /*
6512 * Backspace.
6513 */
6514 case '\b':
6515 Log2(("DBGC: backspace\n"));
6516 if (pDbgc->iRead != pDbgc->iWrite)
6517 {
6518 unsigned iWriteUndo = pDbgc->iWrite;
6519 if (pDbgc->iWrite)
6520 pDbgc->iWrite--;
6521 else
6522 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
6523
6524 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
6525 pDbgc->iWrite = iWriteUndo;
6526 }
6527 break;
6528
6529 /*
6530 * Add char to buffer.
6531 */
6532 case '\t':
6533 case '\n':
6534 case ';':
6535 switch (ch)
6536 {
6537 case '\t': ch = ' '; break;
6538 case '\n': pDbgc->cInputLines++; break;
6539 }
6540 default:
6541 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
6542 pDbgc->achInput[pDbgc->iWrite] = ch;
6543 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
6544 pDbgc->iWrite = 0;
6545 break;
6546 }
6547 }
6548
6549 /* Terminate it to make it easier to read in the debugger. */
6550 pDbgc->achInput[pDbgc->iWrite] = '\0';
6551 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
6552
6553 return rc;
6554}
6555
6556
6557/**
6558 * Finds a builtin symbol.
6559 * @returns Pointer to symbol descriptor on success.
6560 * @returns NULL on failure.
6561 * @param pDbgc The debug console instance.
6562 * @param pszSymbol The symbol name.
6563 */
6564static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
6565{
6566 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)
6567 if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
6568 return &g_aSyms[iSym];
6569
6570 /** @todo externally registered symbols. */
6571 NOREF(pDbgc);
6572 return NULL;
6573}
6574
6575
6576/**
6577 * Resolves a symbol (or tries to do so at least).
6578 *
6579 * @returns 0 on success.
6580 * @returns VBox status on failure.
6581 * @param pDbgc The debug console instance.
6582 * @param pszSymbol The symbol name.
6583 * @param enmType The result type.
6584 * @param pResult Where to store the result.
6585 */
6586static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
6587{
6588 /*
6589 * Builtin?
6590 */
6591 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
6592 if (pSymDesc)
6593 {
6594 if (!pSymDesc->pfnGet)
6595 return VERR_PARSE_WRITEONLY_SYMBOL;
6596 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
6597 }
6598
6599
6600 /*
6601 * Ask PDM.
6602 */
6603 /** @todo resolve symbols using PDM. */
6604
6605
6606 /*
6607 * Ask the debug info manager.
6608 */
6609 DBGFSYMBOL Symbol;
6610 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
6611 if (VBOX_SUCCESS(rc))
6612 {
6613 /*
6614 * Default return is a flat gc address.
6615 */
6616 memset(pResult, 0, sizeof(*pResult));
6617 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
6618 pResult->u64Range = Symbol.cb;
6619 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
6620 pResult->u.GCFlat = Symbol.Value;
6621 DBGCVAR VarTmp;
6622 switch (enmType)
6623 {
6624 /* nothing to do. */
6625 case DBGCVAR_TYPE_GC_FLAT:
6626 case DBGCVAR_TYPE_GC_FAR:
6627 case DBGCVAR_TYPE_ANY:
6628 return VINF_SUCCESS;
6629
6630 /* simply make it numeric. */
6631 case DBGCVAR_TYPE_NUMBER:
6632 pResult->enmType = DBGCVAR_TYPE_NUMBER;
6633 pResult->u.u64Number = Symbol.Value;
6634 return VINF_SUCCESS;
6635
6636 /* cast it. */
6637
6638 case DBGCVAR_TYPE_GC_PHYS:
6639 VarTmp = *pResult;
6640 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
6641
6642 case DBGCVAR_TYPE_HC_FAR:
6643 case DBGCVAR_TYPE_HC_FLAT:
6644 VarTmp = *pResult;
6645 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
6646
6647 case DBGCVAR_TYPE_HC_PHYS:
6648 VarTmp = *pResult;
6649 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
6650
6651 default:
6652 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
6653 return VERR_INVALID_PARAMETER;
6654 }
6655 }
6656
6657 return VERR_PARSE_NOT_IMPLEMENTED;
6658}
6659
6660
6661
6662/**
6663 * Finds a routine.
6664 *
6665 * @returns Pointer to the command descriptor.
6666 * If the request was for an external command, the caller is responsible for
6667 * unlocking the external command list.
6668 * @returns NULL if not found.
6669 * @param pDbgc The debug console instance.
6670 * @param pachName Pointer to the routine string (not terminated).
6671 * @param cchName Length of the routine name.
6672 * @param fExternal Whether or not the routine is external.
6673 */
6674static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
6675{
6676 if (!fExternal)
6677 {
6678 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
6679 {
6680 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
6681 && !g_aCmds[iCmd].pszCmd[cchName])
6682 return &g_aCmds[iCmd];
6683 }
6684 }
6685 else
6686 {
6687 DBGCEXTCMDS_LOCK_RD();
6688 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
6689 {
6690 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
6691 {
6692 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
6693 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])
6694 return &pExtCmds->paCmds[iCmd];
6695 }
6696 }
6697 DBGCEXTCMDS_UNLOCK_RD();
6698 }
6699
6700 NOREF(pDbgc);
6701 return NULL;
6702}
6703
6704
6705/**
6706 * Searches for an operator descriptor which matches the start of
6707 * the expression given us.
6708 *
6709 * @returns Pointer to the operator on success.
6710 * @param pDbgc The debug console instance.
6711 * @param pszExpr Pointer to the expression string which might start with an operator.
6712 * @param fPreferBinary Whether to favour binary or unary operators.
6713 * Caller must assert that it's the disired type! Both types will still
6714 * be returned, this is only for resolving duplicates.
6715 * @param chPrev The previous char. Some operators requires a blank in front of it.
6716 */
6717static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
6718{
6719 PCDBGCOP pOp = NULL;
6720 for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)
6721 {
6722 if ( g_aOps[iOp].szName[0] == pszExpr[0]
6723 && (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])
6724 && (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))
6725 {
6726 /*
6727 * Check that we don't mistake it for some other operator which have more chars.
6728 */
6729 unsigned j;
6730 for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)
6731 if ( g_aOps[j].cchName > g_aOps[iOp].cchName
6732 && g_aOps[j].szName[0] == pszExpr[0]
6733 && (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])
6734 && (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )
6735 break;
6736 if (j < ELEMENTS(g_aOps))
6737 continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */
6738 pOp = &g_aOps[iOp];
6739
6740 /*
6741 * Prefered type?
6742 */
6743 if (g_aOps[iOp].fBinary == fPreferBinary)
6744 break;
6745 }
6746 }
6747
6748 if (pOp)
6749 Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));
6750 NOREF(pDbgc); NOREF(chPrev);
6751 return pOp;
6752}
6753
6754
6755
6756static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
6757{
6758 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
6759
6760 /*
6761 * Removing any quoting and escapings.
6762 */
6763 char ch = *pszExpr;
6764 if (ch == '"' || ch == '\'' || ch == '`')
6765 {
6766 if (pszExpr[--cchExpr] != ch)
6767 return VERR_PARSE_UNBALANCED_QUOTE;
6768 cchExpr--;
6769 pszExpr++;
6770
6771 /** @todo string unescaping. */
6772 }
6773 pszExpr[cchExpr] = '\0';
6774
6775 /*
6776 * Make the argument.
6777 */
6778 pArg->pDesc = NULL;
6779 pArg->pNext = NULL;
6780 pArg->enmType = DBGCVAR_TYPE_STRING;
6781 pArg->u.pszString = pszExpr;
6782 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
6783 pArg->u64Range = cchExpr;
6784
6785 NOREF(pDbgc);
6786 return 0;
6787}
6788
6789
6790static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
6791{
6792 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
6793 /*
6794 * Convert to number.
6795 */
6796 uint64_t u64 = 0;
6797 char ch;
6798 while ((ch = *pszExpr) != '\0')
6799 {
6800 uint64_t u64Prev = u64;
6801 unsigned u = ch - '0';
6802 if (u < 10 && u < uBase)
6803 u64 = u64 * uBase + u;
6804 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
6805 u64 = u64 * uBase + u;
6806 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
6807 u64 = u64 * uBase + u;
6808 else
6809 return VERR_PARSE_INVALID_NUMBER;
6810
6811 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
6812 if (u64Prev != u64 / uBase)
6813 return VERR_PARSE_NUMBER_TOO_BIG;
6814
6815 /* next */
6816 pszExpr++;
6817 }
6818
6819 /*
6820 * Initialize the argument.
6821 */
6822 pArg->pDesc = NULL;
6823 pArg->pNext = NULL;
6824 pArg->enmType = DBGCVAR_TYPE_NUMBER;
6825 pArg->u.u64Number = u64;
6826 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
6827 pArg->u64Range = 0;
6828
6829 return 0;
6830}
6831
6832
6833/**
6834 * Match variable and variable descriptor, promoting the variable if necessary.
6835 *
6836 * @returns VBox status code.
6837 * @param pDbgc Debug console instanace.
6838 * @param pVar Variable.
6839 * @param pVarDesc Variable descriptor.
6840 */
6841static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
6842{
6843 /*
6844 * (If match or promoted to match, return, else break.)
6845 */
6846 switch (pVarDesc->enmCategory)
6847 {
6848 /*
6849 * Anything goes
6850 */
6851 case DBGCVAR_CAT_ANY:
6852 return VINF_SUCCESS;
6853
6854 /*
6855 * Pointer with and without range.
6856 * We can try resolve strings and symbols as symbols and
6857 * promote numbers to flat GC pointers.
6858 */
6859 case DBGCVAR_CAT_POINTER_NO_RANGE:
6860 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
6861 return VERR_PARSE_NO_RANGE_ALLOWED;
6862 /* fallthru */
6863 case DBGCVAR_CAT_POINTER:
6864 switch (pVar->enmType)
6865 {
6866 case DBGCVAR_TYPE_GC_FLAT:
6867 case DBGCVAR_TYPE_GC_FAR:
6868 case DBGCVAR_TYPE_GC_PHYS:
6869 case DBGCVAR_TYPE_HC_FLAT:
6870 case DBGCVAR_TYPE_HC_FAR:
6871 case DBGCVAR_TYPE_HC_PHYS:
6872 return VINF_SUCCESS;
6873
6874 case DBGCVAR_TYPE_SYMBOL:
6875 case DBGCVAR_TYPE_STRING:
6876 {
6877 DBGCVAR Var;
6878 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
6879 if (VBOX_SUCCESS(rc))
6880 {
6881 /* deal with range */
6882 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
6883 {
6884 Var.enmRangeType = pVar->enmRangeType;
6885 Var.u64Range = pVar->u64Range;
6886 }
6887 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
6888 Var.enmRangeType = DBGCVAR_RANGE_NONE;
6889 *pVar = Var;
6890 return rc;
6891 }
6892 break;
6893 }
6894
6895 case DBGCVAR_TYPE_NUMBER:
6896 {
6897 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
6898 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6899 pVar->u.GCFlat = GCPtr;
6900 return VINF_SUCCESS;
6901 }
6902
6903 default:
6904 break;
6905 }
6906 break;
6907
6908 /*
6909 * GC pointer with and without range.
6910 * We can try resolve strings and symbols as symbols and
6911 * promote numbers to flat GC pointers.
6912 */
6913 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
6914 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
6915 return VERR_PARSE_NO_RANGE_ALLOWED;
6916 /* fallthru */
6917 case DBGCVAR_CAT_GC_POINTER:
6918 switch (pVar->enmType)
6919 {
6920 case DBGCVAR_TYPE_GC_FLAT:
6921 case DBGCVAR_TYPE_GC_FAR:
6922 case DBGCVAR_TYPE_GC_PHYS:
6923 return VINF_SUCCESS;
6924
6925 case DBGCVAR_TYPE_HC_FLAT:
6926 case DBGCVAR_TYPE_HC_FAR:
6927 case DBGCVAR_TYPE_HC_PHYS:
6928 return VERR_PARSE_CONVERSION_FAILED;
6929
6930 case DBGCVAR_TYPE_SYMBOL:
6931 case DBGCVAR_TYPE_STRING:
6932 {
6933 DBGCVAR Var;
6934 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
6935 if (VBOX_SUCCESS(rc))
6936 {
6937 /* deal with range */
6938 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
6939 {
6940 Var.enmRangeType = pVar->enmRangeType;
6941 Var.u64Range = pVar->u64Range;
6942 }
6943 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
6944 Var.enmRangeType = DBGCVAR_RANGE_NONE;
6945 *pVar = Var;
6946 return rc;
6947 }
6948 break;
6949 }
6950
6951 case DBGCVAR_TYPE_NUMBER:
6952 {
6953 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
6954 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6955 pVar->u.GCFlat = GCPtr;
6956 return VINF_SUCCESS;
6957 }
6958
6959 default:
6960 break;
6961 }
6962 break;
6963
6964 /*
6965 * Number with or without a range.
6966 * Numbers can be resolved from symbols, but we cannot demote a pointer
6967 * to a number.
6968 */
6969 case DBGCVAR_CAT_NUMBER_NO_RANGE:
6970 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
6971 return VERR_PARSE_NO_RANGE_ALLOWED;
6972 /* fallthru */
6973 case DBGCVAR_CAT_NUMBER:
6974 switch (pVar->enmType)
6975 {
6976 case DBGCVAR_TYPE_NUMBER:
6977 return VINF_SUCCESS;
6978
6979 case DBGCVAR_TYPE_SYMBOL:
6980 case DBGCVAR_TYPE_STRING:
6981 {
6982 DBGCVAR Var;
6983 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
6984 if (VBOX_SUCCESS(rc))
6985 {
6986 *pVar = Var;
6987 return rc;
6988 }
6989 break;
6990 }
6991 default:
6992 break;
6993 }
6994 break;
6995
6996 /*
6997 * Strings can easily be made from symbols (and of course strings).
6998 * We could consider reformatting the addresses and numbers into strings later...
6999 */
7000 case DBGCVAR_CAT_STRING:
7001 switch (pVar->enmType)
7002 {
7003 case DBGCVAR_TYPE_SYMBOL:
7004 pVar->enmType = DBGCVAR_TYPE_STRING;
7005 /* fallthru */
7006 case DBGCVAR_TYPE_STRING:
7007 return VINF_SUCCESS;
7008 default:
7009 break;
7010 }
7011 break;
7012
7013 /*
7014 * Symol is pretty much the same thing as a string (at least until we actually implement it).
7015 */
7016 case DBGCVAR_CAT_SYMBOL:
7017 switch (pVar->enmType)
7018 {
7019 case DBGCVAR_TYPE_STRING:
7020 pVar->enmType = DBGCVAR_TYPE_SYMBOL;
7021 /* fallthru */
7022 case DBGCVAR_TYPE_SYMBOL:
7023 return VINF_SUCCESS;
7024 default:
7025 break;
7026 }
7027 break;
7028
7029 /*
7030 * Anything else is illegal.
7031 */
7032 default:
7033 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
7034 break;
7035 }
7036
7037 return VERR_PARSE_NO_ARGUMENT_MATCH;
7038}
7039
7040
7041/**
7042 * Matches a set of variables with a description set.
7043 *
7044 * This is typically used for routine arguments before a call. The effects in
7045 * addition to the validation, is that some variables might be propagated to
7046 * other types in order to match the description. The following transformations
7047 * are supported:
7048 * - String reinterpreted as a symbol and resolved to a number or pointer.
7049 * - Number to a pointer.
7050 * - Pointer to a number.
7051 * @returns 0 on success with paVars.
7052 * @returns VBox error code for match errors.
7053 */
7054static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
7055 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
7056 PDBGCVAR paVars, unsigned cVars)
7057{
7058 /*
7059 * Just do basic min / max checks first.
7060 */
7061 if (cVars < cVarsMin)
7062 return VERR_PARSE_TOO_FEW_ARGUMENTS;
7063 if (cVars > cVarsMax)
7064 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7065
7066 /*
7067 * Match the descriptors and actual variables.
7068 */
7069 PCDBGCVARDESC pPrevDesc = NULL;
7070 unsigned cCurDesc = 0;
7071 unsigned iVar = 0;
7072 unsigned iVarDesc = 0;
7073 while (iVar < cVars)
7074 {
7075 /* walk the descriptors */
7076 if (iVarDesc >= cVarDescs)
7077 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7078 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
7079 && &paVarDescs[iVarDesc - 1] != pPrevDesc)
7080 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
7081 {
7082 iVarDesc++;
7083 if (iVarDesc >= cVarDescs)
7084 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7085 cCurDesc = 0;
7086 }
7087
7088 /*
7089 * Skip thru optional arguments until we find something which matches
7090 * or can easily be promoted to what the descriptor want.
7091 */
7092 for (;;)
7093 {
7094 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
7095 if (VBOX_SUCCESS(rc))
7096 {
7097 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
7098 cCurDesc++;
7099 break;
7100 }
7101
7102 /* can we advance? */
7103 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
7104 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
7105 if (++iVarDesc >= cVarDescs)
7106 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
7107 cCurDesc = 0;
7108 }
7109
7110 /* next var */
7111 iVar++;
7112 }
7113
7114 /*
7115 * Check that the rest of the descriptors are optional.
7116 */
7117 while (iVarDesc < cVarDescs)
7118 {
7119 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
7120 return VERR_PARSE_TOO_FEW_ARGUMENTS;
7121 cCurDesc = 0;
7122
7123 /* next */
7124 iVarDesc++;
7125 }
7126
7127 return 0;
7128}
7129
7130
7131/**
7132 * Evaluates one argument with though of unary operators.
7133 *
7134 * @returns 0 on success. pResult contains the result.
7135 * @returns VBox error code on parse or other evaluation error.
7136 *
7137 * @param pDbgc Debugger console instance data.
7138 * @param pszExpr The expression string.
7139 * @param pResult Where to store the result of the expression evaluation.
7140 */
7141static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
7142{
7143 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7144
7145 /*
7146 * The state of the expression is now such that it will start by zero or more
7147 * unary operators and being followed by an expression of some kind.
7148 * The expression is either plain or in parenthesis.
7149 *
7150 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
7151 * ASSUME: unary operators are all of equal precedence.
7152 */
7153 int rc = 0;
7154 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
7155 if (pOp)
7156 {
7157 /* binary operators means syntax error. */
7158 if (pOp->fBinary)
7159 return VERR_PARSE_UNEXPECTED_OPERATOR;
7160
7161 /*
7162 * If the next expression (the one following the unary operator) is in a
7163 * parenthesis a full eval is needed. If not the unary eval will suffice.
7164 */
7165 /* calc and strip next expr. */
7166 char *pszExpr2 = pszExpr + pOp->cchName;
7167 while (isblank(*pszExpr2))
7168 pszExpr2++;
7169
7170 if (!*pszExpr2)
7171 rc = VERR_PARSE_EMPTY_ARGUMENT;
7172 else
7173 {
7174 DBGCVAR Arg;
7175 if (*pszExpr2 == '(')
7176 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
7177 else
7178 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
7179 if (VBOX_SUCCESS(rc))
7180 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
7181 }
7182 }
7183 else
7184 {
7185 /*
7186 * Didn't find any operators, so it we have to check if this can be an
7187 * function call before assuming numeric or string expression.
7188 *
7189 * (ASSUMPTIONS:)
7190 * A function name only contains alphanumerical chars and it can not start
7191 * with a numerical character.
7192 * Immediately following the name is a parenthesis which must over
7193 * the remaining part of the expression.
7194 */
7195 bool fExternal = *pszExpr == '.';
7196 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
7197 char *pszFunEnd = NULL;
7198 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
7199 {
7200 pszFunEnd = pszExpr + 1;
7201 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
7202 pszFunEnd++;
7203 if (*pszFunEnd != '(')
7204 pszFunEnd = NULL;
7205 }
7206
7207 if (pszFunEnd)
7208 {
7209 /*
7210 * Ok, it's a function call.
7211 */
7212 if (fExternal)
7213 pszExpr++, cchExpr--;
7214 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
7215 if (!pFun)
7216 return VERR_PARSE_FUNCTION_NOT_FOUND;
7217 if (!pFun->pResultDesc)
7218 return VERR_PARSE_NOT_A_FUNCTION;
7219
7220 /*
7221 * Parse the expression in parenthesis.
7222 */
7223 cchExpr -= pszFunEnd - pszExpr;
7224 pszExpr = pszFunEnd;
7225 /** @todo implement multiple arguments. */
7226 DBGCVAR Arg;
7227 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
7228 if (!rc)
7229 {
7230 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
7231 if (!rc)
7232 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
7233 }
7234 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
7235 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
7236 }
7237 else
7238 {
7239 /*
7240 * Didn't find any operators, so it must be a plain expression.
7241 * This might be numeric or a string expression.
7242 */
7243 char ch = pszExpr[0];
7244 char ch2 = pszExpr[1];
7245 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
7246 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
7247 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
7248 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
7249 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
7250 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
7251 else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
7252 rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
7253 else
7254 {
7255 /*
7256 * Hexadecimal number or a string?
7257 */
7258 char *psz = pszExpr;
7259 while (isxdigit(*psz))
7260 psz++;
7261 if (!*psz)
7262 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7263 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
7264 {
7265 *psz = '\0';
7266 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7267 }
7268 else
7269 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7270 }
7271 }
7272 }
7273
7274 return rc;
7275}
7276
7277
7278/**
7279 * Evaluates one argument.
7280 *
7281 * @returns 0 on success. pResult contains the result.
7282 * @returns VBox error code on parse or other evaluation error.
7283 *
7284 * @param pDbgc Debugger console instance data.
7285 * @param pszExpr The expression string.
7286 * @param pResult Where to store the result of the expression evaluation.
7287 */
7288static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
7289{
7290 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7291 /*
7292 * First we need to remove blanks in both ends.
7293 * ASSUMES: There is no quoting unless the entire expression is a string.
7294 */
7295
7296 /* stripping. */
7297 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
7298 pszExpr[--cchExpr] = '\0';
7299 while (isblank(*pszExpr))
7300 pszExpr++, cchExpr--;
7301 if (!*pszExpr)
7302 return VERR_PARSE_EMPTY_ARGUMENT;
7303
7304 /* it there is any kind of quoting in the expression, it's string meat. */
7305 if (strpbrk(pszExpr, "\"'`"))
7306 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7307
7308 /*
7309 * Check if there are any parenthesis which needs removing.
7310 */
7311 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
7312 {
7313 do
7314 {
7315 unsigned cPar = 1;
7316 char *psz = pszExpr + 1;
7317 char ch;
7318 while ((ch = *psz) != '\0')
7319 {
7320 if (ch == '(')
7321 cPar++;
7322 else if (ch == ')')
7323 {
7324 if (cPar <= 0)
7325 return VERR_PARSE_UNBALANCED_PARENTHESIS;
7326 cPar--;
7327 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
7328 break;
7329 }
7330 /* next */
7331 psz++;
7332 }
7333 if (ch)
7334 break;
7335
7336 /* remove the parenthesis. */
7337 pszExpr++;
7338 cchExpr -= 2;
7339 pszExpr[cchExpr] = '\0';
7340
7341 /* strip blanks. */
7342 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
7343 pszExpr[--cchExpr] = '\0';
7344 while (isblank(*pszExpr))
7345 pszExpr++, cchExpr--;
7346 if (!*pszExpr)
7347 return VERR_PARSE_EMPTY_ARGUMENT;
7348 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
7349 }
7350
7351 /* tabs to spaces. */
7352 char *psz = pszExpr;
7353 while ((psz = strchr(psz, '\t')) != NULL)
7354 *psz = ' ';
7355
7356 /*
7357 * Now, we need to look for the binary operator with the lowest precedence.
7358 *
7359 * If there are no operators we're left with a simple expression which we
7360 * evaluate with respect to unary operators
7361 */
7362 char *pszOpSplit = NULL;
7363 PCDBGCOP pOpSplit = NULL;
7364 unsigned iOpSplit = 0;
7365 unsigned cBinaryOps = 0;
7366 unsigned cPar = 0;
7367 char ch;
7368 char chPrev = ' ';
7369 bool fBinary = false;
7370 psz = pszExpr;
7371
7372 while ((ch = *psz) != '\0')
7373 {
7374 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
7375 /*
7376 * Parenthesis.
7377 */
7378 if (ch == '(')
7379 {
7380 cPar++;
7381 fBinary = false;
7382 }
7383 else if (ch == ')')
7384 {
7385 if (cPar <= 0)
7386 return VERR_PARSE_UNBALANCED_PARENTHESIS;
7387 cPar++;
7388 fBinary = true;
7389 }
7390 /*
7391 * Potential operator.
7392 */
7393 else if (cPar == 0 && !isblank(ch))
7394 {
7395 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev);
7396 if (pOp)
7397 {
7398 /* If not the right kind of operator we've got a syntax error. */
7399 if (pOp->fBinary != fBinary)
7400 return VERR_PARSE_UNEXPECTED_OPERATOR;
7401
7402 /*
7403 * Update the parse state and skip the operator.
7404 */
7405 if (fBinary)
7406 {
7407 cBinaryOps++;
7408 if (iOpSplit < pOp->iPrecedence)
7409 {
7410 pOpSplit = pOp;
7411 pszOpSplit = psz;
7412 }
7413 }
7414 psz += pOp->cchName - 1;
7415 fBinary = false;
7416 }
7417 else
7418 fBinary = true;
7419 }
7420
7421 /* next */
7422 psz++;
7423 chPrev = ch;
7424 } /* parse loop. */
7425
7426
7427 /*
7428 * Either we found an operator to divide the expression by
7429 * or we didn't find any. In the first case it's divide and
7430 * conquer. In the latter it's a single expression which
7431 * needs dealing with its unary operators if any.
7432 */
7433 int rc;
7434 if (cBinaryOps)
7435 {
7436 /* process 1st sub expression. */
7437 *pszOpSplit = '\0';
7438 DBGCVAR Arg1;
7439 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
7440 if (VBOX_SUCCESS(rc))
7441 {
7442 /* process 2nd sub expression. */
7443 char *psz2 = pszOpSplit + pOpSplit->cchName;
7444 DBGCVAR Arg2;
7445 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
7446 if (VBOX_SUCCESS(rc))
7447 /* apply the operator. */
7448 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
7449 }
7450 }
7451 else
7452 /* plain expression or using unary operators perhaps with paratheses. */
7453 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
7454
7455 return rc;
7456}
7457
7458
7459/**
7460 * Parses the arguments of one command.
7461 *
7462 * @returns 0 on success.
7463 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
7464 * @param pDbgc Debugger console instance data.
7465 * @param pCmd Pointer to the command descriptor.
7466 * @param pszArg Pointer to the arguments to parse.
7467 * @param paArgs Where to store the parsed arguments.
7468 * @param cArgs Size of the paArgs array.
7469 * @param pcArgs Where to store the number of arguments.
7470 * In the event of an error this is used to store the index of the offending argument.
7471 */
7472static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
7473{
7474 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
7475 /*
7476 * Check if we have any argument and if the command takes any.
7477 */
7478 *pcArgs = 0;
7479 /* strip leading blanks. */
7480 while (*pszArgs && isblank(*pszArgs))
7481 pszArgs++;
7482 if (!*pszArgs)
7483 {
7484 if (!pCmd->cArgsMin)
7485 return 0;
7486 return VERR_PARSE_TOO_FEW_ARGUMENTS;
7487 }
7488 /** @todo fixme - foo() doesn't work. */
7489 if (!pCmd->cArgsMax)
7490 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7491
7492 /*
7493 * This is a hack, it's "temporary" and should go away "when" the parser is
7494 * modified to match arguments while parsing.
7495 */
7496 if ( pCmd->cArgsMax == 1
7497 && pCmd->cArgsMin == 1
7498 && pCmd->cArgDescs == 1
7499 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
7500 && cArgs >= 1)
7501 {
7502 *pcArgs = 1;
7503 RTStrStripR(pszArgs);
7504 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
7505 }
7506
7507
7508 /*
7509 * The parse loop.
7510 */
7511 PDBGCVAR pArg0 = &paArgs[0];
7512 PDBGCVAR pArg = pArg0;
7513 *pcArgs = 0;
7514 do
7515 {
7516 /*
7517 * Can we have another argument?
7518 */
7519 if (*pcArgs >= pCmd->cArgsMax)
7520 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7521 if (pArg >= &paArgs[cArgs])
7522 return VERR_PARSE_ARGUMENT_OVERFLOW;
7523
7524 /*
7525 * Find the end of the argument.
7526 */
7527 int cPar = 0;
7528 char chQuote = '\0';
7529 char *pszEnd = NULL;
7530 char *psz = pszArgs;
7531 char ch;
7532 for (;;)
7533 {
7534 /*
7535 * Check for the end.
7536 */
7537 if ((ch = *psz) == '\0')
7538 {
7539 if (chQuote)
7540 return VERR_PARSE_UNBALANCED_QUOTE;
7541 if (cPar)
7542 return VERR_PARSE_UNBALANCED_PARENTHESIS;
7543 pszEnd = psz;
7544 break;
7545 }
7546 /*
7547 * When quoted we ignore everything but the quotation char.
7548 * We use the REXX way of escaping the quotation char, i.e. double occurence.
7549 */
7550 else if (ch == '\'' || ch == '"' || ch == '`')
7551 {
7552 if (chQuote)
7553 {
7554 /* end quote? */
7555 if (ch == chQuote)
7556 {
7557 if (psz[1] == ch)
7558 psz++; /* skip the escaped quote char */
7559 else
7560 chQuote = '\0'; /* end of quoted string. */
7561 }
7562 }
7563 else
7564 chQuote = ch; /* open new quote */
7565 }
7566 /*
7567 * Parenthesis can of course be nested.
7568 */
7569 else if (ch == '(')
7570 cPar++;
7571 else if (ch == ')')
7572 {
7573 if (!cPar)
7574 return VERR_PARSE_UNBALANCED_PARENTHESIS;
7575 cPar--;
7576 }
7577 /*
7578 * Encountering blanks may mean the end of it all. But of course not
7579 * while inside a quotation or paranthesis. A binary operator will
7580 * also force continued parsing.
7581 */
7582 else if (isblank(ch) && !cPar && !chQuote)
7583 {
7584 pszEnd = psz++; /* just in case. */
7585 while (isblank(*psz))
7586 psz++;
7587 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, true, ' ');
7588 if (!pOp || !pOp->fBinary)
7589 break; /* the end. */
7590 if (pOp)
7591 psz += pOp->cchName;
7592
7593 while (isblank(*psz)) /* skip blanks so we don't get here again */
7594 psz++;
7595 continue;
7596 }
7597
7598 /* next char */
7599 psz++;
7600 }
7601 *pszEnd = '\0';
7602 /* (psz = next char to process) */
7603
7604 /*
7605 * Parse and evaluate the argument.
7606 */
7607 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
7608 if (VBOX_FAILURE(rc))
7609 return rc;
7610
7611 /*
7612 * Next.
7613 */
7614 pArg++;
7615 (*pcArgs)++;
7616 pszArgs = psz;
7617 while (*pszArgs && isblank(*pszArgs))
7618 pszArgs++;
7619 } while (*pszArgs);
7620
7621 /*
7622 * Match the arguments.
7623 */
7624 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
7625}
7626
7627
7628/**
7629 * Process one command.
7630 *
7631 * @returns VBox status code. Any error indicates the termination of the console session.
7632 * @param pDbgc Debugger console instance data.
7633 * @param pszCmd Pointer to the command.
7634 * @param cchCmd Length of the command.
7635 */
7636static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
7637{
7638 char *pszCmdInput = pszCmd;
7639
7640 /*
7641 * Skip blanks.
7642 */
7643 while (isblank(*pszCmd))
7644 pszCmd++, cchCmd--;
7645
7646 /* external command? */
7647 bool fExternal = *pszCmd == '.';
7648 if (fExternal)
7649 pszCmd++, cchCmd--;
7650
7651 /*
7652 * Find arguments.
7653 */
7654 char *pszArgs = pszCmd;
7655 while (isalnum(*pszArgs))
7656 pszArgs++;
7657 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
7658 {
7659 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
7660 return 0;
7661 }
7662
7663 /*
7664 * Find the command.
7665 */
7666 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
7667 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
7668 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
7669
7670 /*
7671 * Parse arguments (if any).
7672 */
7673 unsigned cArgs;
7674 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
7675
7676 /*
7677 * Execute the command.
7678 */
7679 if (!rc)
7680 {
7681 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
7682 }
7683 else
7684 {
7685 /* report parse / eval error. */
7686 switch (rc)
7687 {
7688 case VERR_PARSE_TOO_FEW_ARGUMENTS:
7689 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7690 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
7691 break;
7692 case VERR_PARSE_TOO_MANY_ARGUMENTS:
7693 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7694 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
7695 break;
7696 case VERR_PARSE_ARGUMENT_OVERFLOW:
7697 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7698 "Syntax error: Too many arguments.\n");
7699 break;
7700 case VERR_PARSE_UNBALANCED_QUOTE:
7701 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7702 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
7703 break;
7704 case VERR_PARSE_UNBALANCED_PARENTHESIS:
7705 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7706 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
7707 break;
7708 case VERR_PARSE_EMPTY_ARGUMENT:
7709 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7710 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
7711 break;
7712 case VERR_PARSE_UNEXPECTED_OPERATOR:
7713 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7714 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
7715 break;
7716 case VERR_PARSE_INVALID_NUMBER:
7717 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7718 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
7719 break;
7720 case VERR_PARSE_NUMBER_TOO_BIG:
7721 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7722 "Error: Numeric overflow (argument %d).\n", cArgs);
7723 break;
7724 case VERR_PARSE_INVALID_OPERATION:
7725 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7726 "Error: Invalid operation attempted (argument %d).\n", cArgs);
7727 break;
7728 case VERR_PARSE_FUNCTION_NOT_FOUND:
7729 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7730 "Error: Function not found (argument %d).\n", cArgs);
7731 break;
7732 case VERR_PARSE_NOT_A_FUNCTION:
7733 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7734 "Error: The function specified is not a function (argument %d).\n", cArgs);
7735 break;
7736 case VERR_PARSE_NO_MEMORY:
7737 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7738 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
7739 break;
7740 case VERR_PARSE_INCORRECT_ARG_TYPE:
7741 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7742 "Error: Incorrect argument type (argument %d?).\n", cArgs);
7743 break;
7744 case VERR_PARSE_VARIABLE_NOT_FOUND:
7745 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7746 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
7747 break;
7748 case VERR_PARSE_CONVERSION_FAILED:
7749 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7750 "Error: A conversion between two types failed (argument %d).\n", cArgs);
7751 break;
7752 case VERR_PARSE_NOT_IMPLEMENTED:
7753 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7754 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
7755 break;
7756 case VERR_PARSE_BAD_RESULT_TYPE:
7757 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7758 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
7759 break;
7760 case VERR_PARSE_WRITEONLY_SYMBOL:
7761 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7762 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
7763 break;
7764
7765 default:
7766 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
7767 "Error: Unknown error %d!\n", rc);
7768 return rc;
7769 }
7770
7771 /*
7772 * Parse errors are non fatal.
7773 */
7774 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
7775 rc = 0;
7776 }
7777
7778 return rc;
7779}
7780
7781
7782/**
7783 * Process all commands current in the buffer.
7784 *
7785 * @returns VBox status code. Any error indicates the termination of the console session.
7786 * @param pDbgc Debugger console instance data.
7787 */
7788static int dbgcProcessCommands(PDBGC pDbgc)
7789{
7790 int rc = 0;
7791 while (pDbgc->cInputLines)
7792 {
7793 /*
7794 * Empty the log buffer if we're hooking the log.
7795 */
7796 if (pDbgc->fLog)
7797 {
7798 rc = dbgcProcessLog(pDbgc);
7799 if (VBOX_FAILURE(rc))
7800 break;
7801 }
7802
7803 if (pDbgc->iRead == pDbgc->iWrite)
7804 {
7805 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
7806 pDbgc->cInputLines = 0;
7807 return 0;
7808 }
7809
7810 /*
7811 * Copy the command to the parse buffer.
7812 */
7813 char ch;
7814 char *psz = &pDbgc->achInput[pDbgc->iRead];
7815 char *pszTrg = &pDbgc->achScratch[0];
7816 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
7817 {
7818 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
7819 psz = &pDbgc->achInput[0];
7820
7821 if (psz == &pDbgc->achInput[pDbgc->iWrite])
7822 {
7823 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
7824 pDbgc->cInputLines = 0;
7825 return 0;
7826 }
7827
7828 pszTrg++;
7829 }
7830 *pszTrg = '\0';
7831
7832 /*
7833 * Advance the buffer.
7834 */
7835 pDbgc->iRead = psz - &pDbgc->achInput[0];
7836 if (ch == '\n')
7837 pDbgc->cInputLines--;
7838
7839 /*
7840 * Parse and execute this command.
7841 */
7842 pDbgc->pszScratch = psz;
7843 pDbgc->iArg = 0;
7844 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
7845 if (rc)
7846 break;
7847 }
7848
7849 return rc;
7850}
7851
7852
7853/**
7854 * Reads input, parses it and executes commands on '\n'.
7855 *
7856 * @returns VBox status.
7857 * @param pDbgc Debugger console instance data.
7858 */
7859static int dbgcProcessInput(PDBGC pDbgc)
7860{
7861 /*
7862 * We know there's input ready, so let's read it first.
7863 */
7864 int rc = dbgcInputRead(pDbgc);
7865 if (VBOX_FAILURE(rc))
7866 return rc;
7867
7868 /*
7869 * Now execute any ready commands.
7870 */
7871 if (pDbgc->cInputLines)
7872 {
7873 /** @todo this fReady stuff is broken. */
7874 pDbgc->fReady = false;
7875 rc = dbgcProcessCommands(pDbgc);
7876 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
7877 pDbgc->fReady = true;
7878 if ( VBOX_SUCCESS(rc)
7879 && pDbgc->iRead == pDbgc->iWrite
7880 && pDbgc->fReady)
7881 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
7882 }
7883
7884 return rc;
7885}
7886
7887
7888/**
7889 * Gets the event context identifier string.
7890 * @returns Read only string.
7891 * @param enmCtx The context.
7892 */
7893static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
7894{
7895 switch (enmCtx)
7896 {
7897 case DBGFEVENTCTX_RAW: return "raw";
7898 case DBGFEVENTCTX_REM: return "rem";
7899 case DBGFEVENTCTX_HWACCL: return "hwaccl";
7900 case DBGFEVENTCTX_HYPER: return "hyper";
7901 case DBGFEVENTCTX_OTHER: return "other";
7902
7903 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
7904 default:
7905 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
7906 return "!Unknown Event Ctx!";
7907 }
7908}
7909
7910
7911/**
7912 * Processes debugger events.
7913 *
7914 * @returns VBox status.
7915 * @param pDbgc DBGC Instance data.
7916 * @param pEvent Pointer to event data.
7917 */
7918static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
7919{
7920 /*
7921 * Flush log first.
7922 */
7923 if (pDbgc->fLog)
7924 {
7925 int rc = dbgcProcessLog(pDbgc);
7926 if (VBOX_FAILURE(rc))
7927 return rc;
7928 }
7929
7930 /*
7931 * Process the event.
7932 */
7933 pDbgc->pszScratch = &pDbgc->achInput[0];
7934 pDbgc->iArg = 0;
7935 bool fPrintPrompt = true;
7936 int rc = VINF_SUCCESS;
7937 switch (pEvent->enmType)
7938 {
7939 /*
7940 * The first part is events we have initiated with commands.
7941 */
7942 case DBGFEVENT_HALT_DONE:
7943 {
7944 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
7945 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
7946 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
7947 if (VBOX_SUCCESS(rc))
7948 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
7949 break;
7950 }
7951
7952
7953 /*
7954 * The second part is events which can occur at any time.
7955 */
7956 case DBGFEVENT_FATAL_ERROR:
7957 {
7958 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
7959 dbgcGetEventCtx(pEvent->enmCtx));
7960 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
7961 if (VBOX_SUCCESS(rc))
7962 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
7963 break;
7964 }
7965
7966 case DBGFEVENT_BREAKPOINT:
7967 case DBGFEVENT_BREAKPOINT_HYPER:
7968 {
7969 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
7970 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
7971
7972 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
7973 switch (rc)
7974 {
7975 case VERR_DBGC_BP_NOT_FOUND:
7976 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
7977 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
7978 break;
7979
7980 case VINF_DBGC_BP_NO_COMMAND:
7981 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
7982 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
7983 break;
7984
7985 case VINF_BUFFER_OVERFLOW:
7986 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
7987 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
7988 break;
7989
7990 default:
7991 break;
7992 }
7993 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
7994 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
7995 else
7996 pDbgc->fRegCtxGuest = fRegCtxGuest;
7997 break;
7998 }
7999
8000 case DBGFEVENT_STEPPED:
8001 case DBGFEVENT_STEPPED_HYPER:
8002 {
8003 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
8004
8005 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
8006 if (VBOX_SUCCESS(rc))
8007 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8008 break;
8009 }
8010
8011 case DBGFEVENT_ASSERTION_HYPER:
8012 {
8013 pDbgc->fRegCtxGuest = false;
8014
8015 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8016 "\ndbgf event: Hypervisor Assertion! (%s)\n"
8017 "%s"
8018 "%s"
8019 "\n",
8020 dbgcGetEventCtx(pEvent->enmCtx),
8021 pEvent->u.Assert.pszMsg1,
8022 pEvent->u.Assert.pszMsg2);
8023 if (VBOX_SUCCESS(rc))
8024 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8025 break;
8026 }
8027
8028 case DBGFEVENT_DEV_STOP:
8029 {
8030 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8031 "\n"
8032 "dbgf event: DBGFSTOP (%s)\n"
8033 "File: %s\n"
8034 "Line: %d\n"
8035 "Function: %s\n",
8036 dbgcGetEventCtx(pEvent->enmCtx),
8037 pEvent->u.Src.pszFile,
8038 pEvent->u.Src.uLine,
8039 pEvent->u.Src.pszFunction);
8040 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
8041 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8042 "Message: %s\n",
8043 pEvent->u.Src.pszMessage);
8044 if (VBOX_SUCCESS(rc))
8045 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8046 break;
8047 }
8048
8049
8050 case DBGFEVENT_INVALID_COMMAND:
8051 {
8052 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
8053 fPrintPrompt = !pDbgc->fReady;
8054 break;
8055 }
8056
8057 case DBGFEVENT_TERMINATING:
8058 {
8059 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
8060 rc = VERR_GENERAL_FAILURE;
8061 break;
8062 }
8063
8064
8065 default:
8066 {
8067 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
8068 fPrintPrompt = !pDbgc->fReady;
8069 break;
8070 }
8071 }
8072
8073 /*
8074 * Prompt, anyone?
8075 */
8076 if (fPrintPrompt && VBOX_SUCCESS(rc))
8077 {
8078 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
8079 }
8080
8081 return rc;
8082}
8083
8084
8085
8086
8087
8088/**
8089 * Make a console instance.
8090 *
8091 * This will not return until either an 'exit' command is issued or a error code
8092 * indicating connection loss is encountered.
8093 *
8094 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
8095 * @returns The VBox status code causing the console termination.
8096 *
8097 * @param pVM VM Handle.
8098 * @param pBack Pointer to the backend structure. This must contain
8099 * a full set of function pointers to service the console.
8100 * @param fFlags Reserved, must be zero.
8101 * @remark A forced termination of the console is easiest done by forcing the
8102 * callbacks to return fatal failures.
8103 */
8104DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
8105{
8106 /*
8107 * Validate input.
8108 */
8109 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
8110 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
8111 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
8112
8113 /*
8114 * Allocate and initialize instance data
8115 */
8116 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
8117 if (!pDbgc)
8118 return VERR_NO_MEMORY;
8119
8120 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;
8121 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;
8122 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;
8123 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
8124 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;
8125 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;
8126 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;
8127 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;
8128 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;
8129 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
8130 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
8131 pDbgc->pBack = pBack;
8132 pDbgc->pszScratch = &pDbgc->achScratch[0];
8133 pDbgc->fRegTerse = true;
8134 pDbgc->fRegCtxGuest = true;
8135 pDbgc->fLog = false;
8136 pDbgc->iRead = 0;
8137 pDbgc->iWrite = 0;
8138 pDbgc->fReady = true;
8139 pDbgc->fInputOverflow = false;
8140 pDbgc->cInputLines = 0;
8141
8142 /*
8143 * Print welcome message.
8144 */
8145 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8146 "Welcome to the VirtualBox Debugger!\n");
8147 if (VBOX_FAILURE(rc))
8148 goto l_failure;
8149
8150 /*
8151 * Attach to the VM.
8152 */
8153 rc = DBGFR3Attach(pVM);
8154 if (VBOX_FAILURE(rc))
8155 {
8156 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
8157 goto l_failure;
8158 }
8159 pDbgc->pVM = pVM;
8160
8161 /*
8162 * Print commandline and auto select result.
8163 */
8164 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8165 "Current VM is %08x\n" /** @todo get and print the VM name! */
8166 "VBoxDbg> ",
8167 pDbgc->pVM);
8168 if (VBOX_FAILURE(rc))
8169 goto l_failure;
8170
8171 /*
8172 * Main Debugger Loop.
8173 *
8174 * This loop will either block on waiting for input or on waiting on
8175 * debug events. If we're forwarding the log we cannot wait for long
8176 * before we must flush the log.
8177 */
8178 for (rc = 0;;)
8179 {
8180 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
8181 {
8182 /*
8183 * Wait for a debug event.
8184 */
8185 PCDBGFEVENT pEvent;
8186 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
8187 if (VBOX_SUCCESS(rc))
8188 {
8189 rc = dbgcProcessEvent(pDbgc, pEvent);
8190 if (VBOX_FAILURE(rc))
8191 break;
8192 }
8193 else if (rc != VERR_TIMEOUT)
8194 break;
8195
8196 /*
8197 * Check for input.
8198 */
8199 if (pBack->pfnInput(pDbgc->pBack, 0))
8200 {
8201 rc = dbgcProcessInput(pDbgc);
8202 if (VBOX_FAILURE(rc))
8203 break;
8204 }
8205 }
8206 else
8207 {
8208 /*
8209 * Wait for input. If Logging is enabled we'll only wait very briefly.
8210 */
8211 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
8212 {
8213 rc = dbgcProcessInput(pDbgc);
8214 if (VBOX_FAILURE(rc))
8215 break;
8216 }
8217 }
8218
8219 /*
8220 * Forward log output.
8221 */
8222 if (pDbgc->fLog)
8223 {
8224 rc = dbgcProcessLog(pDbgc);
8225 if (VBOX_FAILURE(rc))
8226 break;
8227 }
8228 }
8229
8230
8231l_failure:
8232 /*
8233 * Cleanup console debugger session.
8234 */
8235 /* Disable log hook. */
8236 if (pDbgc->fLog)
8237 {
8238
8239 }
8240
8241 /* Detach from the VM. */
8242 if (pDbgc->pVM)
8243 DBGFR3Detach(pDbgc->pVM);
8244
8245 /* finally, free the instance memory. */
8246 RTMemFree(pDbgc);
8247
8248 return rc;
8249}
8250
8251
8252
8253/**
8254 * Register one or more external commands.
8255 *
8256 * @returns VBox status.
8257 * @param paCommands Pointer to an array of command descriptors.
8258 * The commands must be unique. It's not possible
8259 * to register the same commands more than once.
8260 * @param cCommands Number of commands.
8261 */
8262DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
8263{
8264 /*
8265 * Lock the list.
8266 */
8267 DBGCEXTCMDS_LOCK_WR();
8268 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
8269 while (pCur)
8270 {
8271 if (paCommands == pCur->paCmds)
8272 {
8273 DBGCEXTCMDS_UNLOCK_WR();
8274 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
8275 return VWRN_DBGC_ALREADY_REGISTERED;
8276 }
8277 pCur = pCur->pNext;
8278 }
8279
8280 /*
8281 * Allocate new chunk.
8282 */
8283 int rc = 0;
8284 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
8285 if (pCur)
8286 {
8287 pCur->cCmds = cCommands;
8288 pCur->paCmds = paCommands;
8289 pCur->pNext = g_pExtCmdsHead;
8290 g_pExtCmdsHead = pCur;
8291 }
8292 else
8293 rc = VERR_NO_MEMORY;
8294 DBGCEXTCMDS_UNLOCK_WR();
8295
8296 return rc;
8297}
8298
8299
8300/**
8301 * Deregister one or more external commands previously registered by
8302 * DBGCRegisterCommands().
8303 *
8304 * @returns VBox status.
8305 * @param paCommands Pointer to an array of command descriptors
8306 * as given to DBGCRegisterCommands().
8307 * @param cCommands Number of commands.
8308 */
8309DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
8310{
8311 /*
8312 * Lock the list.
8313 */
8314 DBGCEXTCMDS_LOCK_WR();
8315 PDBGCEXTCMDS pPrev = NULL;
8316 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
8317 while (pCur)
8318 {
8319 if (paCommands == pCur->paCmds)
8320 {
8321 if (pPrev)
8322 pPrev->pNext = pCur->pNext;
8323 else
8324 g_pExtCmdsHead = pCur->pNext;
8325 DBGCEXTCMDS_UNLOCK_WR();
8326
8327 RTMemFree(pCur);
8328 return VINF_SUCCESS;
8329 }
8330 pPrev = pCur;
8331 pCur = pCur->pNext;
8332 }
8333 DBGCEXTCMDS_UNLOCK_WR();
8334
8335 NOREF(cCommands);
8336 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
8337}
8338
Note: See TracBrowser for help on using the repository browser.

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