VirtualBox

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

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

Added dt, dl, di and dt (latter not implemented).

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