VirtualBox

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

Last change on this file since 5458 was 5079, checked in by vboxsync, 17 years ago

Fixed two copy & past bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 342.9 KB
Line 
1/** $Id: DBGConsole.cpp 5079 2007-09-27 14:39:05Z 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