VirtualBox

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

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

TSS corrections.

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