VirtualBox

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

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

Moved some of the odd address conversion routines to PGMR3Dbg just to get them out of the way.

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

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