VirtualBox

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

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

Fixed an endless loop in 'd?'. Fixed parameter chopping so it respect multiple unary ops and lack of spaces around ops.

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