VirtualBox

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

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

echo and runscript.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 332.9 KB
Line 
1/** $Id: DBGConsole.cpp 4251 2007-08-20 23:53:15Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console.
4 */
5
6/*
7 * Copyright (C) 2006-2007 innotek GmbH
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.215389.xyz. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License as published by the Free Software Foundation,
13 * in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
14 * distribution. VirtualBox OSE is distributed in the hope that it will
15 * be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/** @page pg_dbgc DBGC - The Debug Console
20 *
21 * The debugger console is a first attempt to make some interactive
22 * debugging facilities for the VirtualBox backend (i.e. the VM). At a later
23 * stage we'll make a fancy gui around this, but for the present a telnet (or
24 * serial terminal) will have to suffice.
25 *
26 * The debugger is only built into the VM with debug builds or when
27 * VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this
28 * define to enable special debugger hooks, but the general approach is to
29 * make generic interfaces. The individual components also can register
30 * external commands, and such code must be within \#ifdef.
31 *
32 *
33 * @section sec_dbgc_op Operation (intentions)
34 *
35 * The console will process commands in a manner similar to the OS/2 and
36 * windows kernel debuggers. This means ';' is a command separator and
37 * that when possible we'll use the same command names as these two uses.
38 *
39 *
40 * @subsection sec_dbg_op_numbers Numbers
41 *
42 * Numbers are hexadecimal unless specified with a prefix indicating
43 * elsewise. Prefixes:
44 * - '0x' - hexadecimal.
45 * - '0i' - decimal
46 * - '0t' - octal.
47 * - '0y' - binary.
48 *
49 *
50 * @subsection sec_dbg_op_address Addressing modes
51 *
52 * - Default is flat. For compatability '%' also means flat.
53 * - Segmented addresses are specified selector:offset.
54 * - Physical addresses are specified using '%%'.
55 * - The default target for the addressing is the guest context, the '#'
56 * will override this and set it to the host.
57 *
58 *
59 * @subsection sec_dbg_op_evalution Evaluation
60 *
61 * As time permits support will be implemented support for a subset of the C
62 * binary operators, starting with '+', '-', '*' and '/'. Support for variables
63 * are provided thru commands 'set' and 'unset' and the unary operator '$'. The
64 * unary '@' operator will indicate function calls. The debugger needs a set of
65 * memory read functions, but we might later extend this to allow registration of
66 * external functions too.
67 *
68 * A special command '?' will then be added which evalutates a given expression
69 * and prints it in all the different formats.
70 *
71 *
72 * @subsection sec_dbg_op_registers Registers
73 *
74 * Registers are addressed using their name. Some registers which have several fields
75 * (like gdtr) will have separate names indicating the different fields. The default
76 * register set is the guest one. To access the hypervisor register one have to
77 * prefix the register names with '.'.
78 *
79 *
80 * @subsection sec_dbg_op_commands Commands
81 *
82 * The commands are all lowercase, case sensitive, and starting with a letter. We will
83 * later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')
84 *
85 *
86 * @section sec_dbg_tasks Tasks
87 *
88 * To implement DBGT and instrument VMM for basic state inspection and log
89 * viewing, the follwing task must be executed:
90 *
91 * -# Basic threading layer in RT.
92 * -# Basic tcpip server abstration in RT.
93 * -# Write DBGC.
94 * -# Write DBCTCP.
95 * -# Integrate with VMM and the rest.
96 * -# Start writing DBGF (VMM).
97 */
98
99
100
101
102/*******************************************************************************
103* Header Files *
104*******************************************************************************/
105#define LOG_GROUP LOG_GROUP_DBGC
106#include <VBox/dbg.h>
107#include <VBox/dbgf.h>
108#include <VBox/vm.h>
109#include <VBox/vmm.h>
110#include <VBox/mm.h>
111#include <VBox/pgm.h>
112#include <VBox/selm.h>
113#include <VBox/dis.h>
114#include <VBox/param.h>
115#include <VBox/err.h>
116#include <VBox/log.h>
117
118#include <iprt/alloc.h>
119#include <iprt/alloca.h>
120#include <iprt/string.h>
121#include <iprt/assert.h>
122#include <iprt/ctype.h>
123
124#include <stdlib.h>
125#include <stdio.h>
126
127/* to err.h! */
128#define VERR_DBGC_QUIT (-11999)
129#define VERR_PARSE_FIRST (-11000)
130#define VERR_PARSE_TOO_FEW_ARGUMENTS (VERR_PARSE_FIRST - 0)
131#define VERR_PARSE_TOO_MANY_ARGUMENTS (VERR_PARSE_FIRST - 1)
132#define VERR_PARSE_ARGUMENT_OVERFLOW (VERR_PARSE_FIRST - 2)
133#define VERR_PARSE_ARGUMENT_TYPE_MISMATCH (VERR_PARSE_FIRST - 3)
134#define VERR_PARSE_NO_RANGE_ALLOWED (VERR_PARSE_FIRST - 4)
135#define VERR_PARSE_UNBALANCED_QUOTE (VERR_PARSE_FIRST - 5)
136#define VERR_PARSE_UNBALANCED_PARENTHESIS (VERR_PARSE_FIRST - 6)
137#define VERR_PARSE_EMPTY_ARGUMENT (VERR_PARSE_FIRST - 7)
138#define VERR_PARSE_UNEXPECTED_OPERATOR (VERR_PARSE_FIRST - 8)
139#define VERR_PARSE_INVALID_NUMBER (VERR_PARSE_FIRST - 9)
140#define VERR_PARSE_NUMBER_TOO_BIG (VERR_PARSE_FIRST - 10)
141#define VERR_PARSE_INVALID_OPERATION (VERR_PARSE_FIRST - 11)
142#define VERR_PARSE_FUNCTION_NOT_FOUND (VERR_PARSE_FIRST - 12)
143#define VERR_PARSE_NOT_A_FUNCTION (VERR_PARSE_FIRST - 13)
144#define VERR_PARSE_NO_MEMORY (VERR_PARSE_FIRST - 14)
145#define VERR_PARSE_INCORRECT_ARG_TYPE (VERR_PARSE_FIRST - 15)
146#define VERR_PARSE_VARIABLE_NOT_FOUND (VERR_PARSE_FIRST - 16)
147#define VERR_PARSE_CONVERSION_FAILED (VERR_PARSE_FIRST - 17)
148#define VERR_PARSE_NOT_IMPLEMENTED (VERR_PARSE_FIRST - 18)
149#define VERR_PARSE_BAD_RESULT_TYPE (VERR_PARSE_FIRST - 19)
150#define VERR_PARSE_WRITEONLY_SYMBOL (VERR_PARSE_FIRST - 20)
151#define VERR_PARSE_NO_ARGUMENT_MATCH (VERR_PARSE_FIRST - 21)
152#define VERR_PARSE_LAST (VERR_PARSE_FIRST - 30)
153
154#define VWRN_DBGC_CMD_PENDING 12000
155#define VWRN_DBGC_ALREADY_REGISTERED 12001
156#define VERR_DBGC_COMMANDS_NOT_REGISTERED (-12002)
157#define VERR_DBGC_BP_NOT_FOUND (-12003)
158#define VERR_DBGC_BP_EXISTS (-12004)
159#define VINF_DBGC_BP_NO_COMMAND 12005
160
161
162
163/*******************************************************************************
164* Defined Constants And Macros *
165*******************************************************************************/
166/** Makes a DBGC variable type pair.
167 * Typically used by binary operators. */
168#define BINARY_TYPE_PAIR(type1, type2) (type1 | (type2 << 16))
169
170
171/*******************************************************************************
172* Structures and Typedefs *
173*******************************************************************************/
174
175/**
176 * Debugger console per breakpoint data.
177 */
178typedef struct DBGCBP
179{
180 /** Pointer to the next breakpoint in the list. */
181 struct DBGCBP *pNext;
182 /** The breakpoint identifier. */
183 RTUINT iBp;
184 /** The size of the command. */
185 size_t cchCmd;
186 /** The command to execute when the breakpoint is hit. */
187 char szCmd[1];
188} DBGCBP;
189/** Pointer to a breakpoint. */
190typedef DBGCBP *PDBGCBP;
191
192
193/**
194 * Named variable.
195 *
196 * Always allocated from heap in one signle block.
197 */
198typedef struct DBGCNAMEDVAR
199{
200 /** The variable. */
201 DBGCVAR Var;
202 /** It's name. */
203 char szName[1];
204} DBGCNAMEDVAR;
205/** Pointer to named variable. */
206typedef DBGCNAMEDVAR *PDBGCNAMEDVAR;
207
208
209/**
210 * Debugger console status
211 */
212typedef enum DBGCSTATUS
213{
214 /** Normal status, .*/
215 DBGC_HALTED
216
217} DBGCSTATUS;
218
219
220/**
221 * Debugger console instance data.
222 */
223typedef struct DBGC
224{
225 /** Command helpers. */
226 DBGCCMDHLP CmdHlp;
227 /** Pointer to backend callback structure. */
228 PDBGCBACK pBack;
229 /** Log indicator. (If set we're writing the log to the console.) */
230 bool fLog;
231 /** Pointer to the current VM. */
232 PVM pVM;
233 /** Indicates whether or we're ready for input. */
234 bool fReady;
235
236 /** Indicates whether we're in guest (true) or hypervisor (false) register context. */
237 bool fRegCtxGuest;
238 /** Indicates whether the register are terse or sparse. */
239 bool fRegTerse;
240
241 /** Input buffer. */
242 char achInput[2048];
243 /** To ease debugging. */
244 unsigned uInputZero;
245 /** Write index in the input buffer. */
246 unsigned iWrite;
247 /** Read index in the input buffer. */
248 unsigned iRead;
249 /** The number of lines in the buffer. */
250 unsigned cInputLines;
251 /** Indicates that we have a buffer overflow condition.
252 * This means that input is ignored up to the next newline. */
253 bool fInputOverflow;
254
255 /** Scratch buffer position. */
256 char *pszScratch;
257 /** Scratch buffer. */
258 char achScratch[16384];
259 /** Argument array position. */
260 unsigned iArg;
261 /** Array of argument variables. */
262 DBGCVAR aArgs[100];
263
264 /** rc from last dbgcHlpPrintfV(). */
265 int rcOutput;
266
267 /** Number of variables in papVars. */
268 unsigned cVars;
269 /** Array of global variables.
270 * Global variables can be referenced using the $ operator and set
271 * and unset using command with those names. */
272 PDBGCNAMEDVAR *papVars;
273
274 /** Current dissassembler position. */
275 DBGCVAR DisasmPos;
276 /** Current source position. (flat GC) */
277 DBGCVAR SourcePos;
278 /** Current memory dump position. */
279 DBGCVAR DumpPos;
280 /** Size of the previous dump element. */
281 unsigned cbDumpElement;
282
283 /** The list of breakpoints. (singly linked) */
284 PDBGCBP pFirstBp;
285} DBGC;
286/** Pointer to debugger console instance data. */
287typedef DBGC *PDBGC;
288
289/** Converts a Command Helper pointer to a pointer to DBGC instance data. */
290#define DBGC_CMDHLP2DBGC(pCmdHlp) ( (PDBGC)((uintptr_t)(pCmdHlp) - RT_OFFSETOF(DBGC, CmdHlp)) )
291
292
293/**
294 * Chunk of external commands.
295 */
296typedef struct DBGCEXTCMDS
297{
298 /** Number of commands descriptors. */
299 unsigned cCmds;
300 /** Pointer to array of command descriptors. */
301 PCDBGCCMD paCmds;
302 /** Pointer to the next chunk. */
303 struct DBGCEXTCMDS *pNext;
304} DBGCEXTCMDS;
305/** Pointer to chunk of external commands. */
306typedef DBGCEXTCMDS *PDBGCEXTCMDS;
307
308
309
310/**
311 * Unary operator handler function.
312 *
313 * @returns 0 on success.
314 * @returns VBox evaluation / parsing error code on failure.
315 * The caller does the bitching.
316 * @param pDbgc Debugger console instance data.
317 * @param pArg The argument.
318 * @param pResult Where to store the result.
319 */
320typedef DECLCALLBACK(int) FNDBGCOPUNARY(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult);
321/** Pointer to a unary operator handler function. */
322typedef FNDBGCOPUNARY *PFNDBGCOPUNARY;
323
324
325/**
326 * Binary operator handler function.
327 *
328 * @returns 0 on success.
329 * @returns VBox evaluation / parsing error code on failure.
330 * The caller does the bitching.
331 * @param pDbgc Debugger console instance data.
332 * @param pArg1 The first argument.
333 * @param pArg2 The 2nd argument.
334 * @param pResult Where to store the result.
335 */
336typedef DECLCALLBACK(int) FNDBGCOPBINARY(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
337/** Pointer to a binary operator handler function. */
338typedef FNDBGCOPBINARY *PFNDBGCOPBINARY;
339
340
341/**
342 * Operator descriptor.
343 */
344typedef struct DBGCOP
345{
346 /** Operator mnemonic. */
347 char szName[4];
348 /** Length of name. */
349 const unsigned cchName;
350 /** Whether or not this is a binary operator.
351 * Unary operators are evaluated right-to-left while binary are left-to-right. */
352 bool fBinary;
353 /** Precedence level. */
354 unsigned iPrecedence;
355 /** Unary operator handler. */
356 PFNDBGCOPUNARY pfnHandlerUnary;
357 /** Binary operator handler. */
358 PFNDBGCOPBINARY pfnHandlerBinary;
359 /** Operator description. */
360 const char *pszDescription;
361} DBGCOP;
362/** Pointer to an operator descriptor. */
363typedef DBGCOP *PDBGCOP;
364/** Pointer to a const operator descriptor. */
365typedef const DBGCOP *PCDBGCOP;
366
367
368
369/** Pointer to symbol descriptor. */
370typedef struct DBGCSYM *PDBGCSYM;
371/** Pointer to const symbol descriptor. */
372typedef const struct DBGCSYM *PCDBGCSYM;
373
374/**
375 * Get builtin symbol.
376 *
377 * @returns 0 on success.
378 * @returns VBox evaluation / parsing error code on failure.
379 * The caller does the bitching.
380 * @param pSymDesc Pointer to the symbol descriptor.
381 * @param pCmdHlp Pointer to the command callback structure.
382 * @param enmType The result type.
383 * @param pResult Where to store the result.
384 */
385typedef DECLCALLBACK(int) FNDBGCSYMGET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
386/** Pointer to get function for a builtin symbol. */
387typedef FNDBGCSYMGET *PFNDBGCSYMGET;
388
389/**
390 * Set builtin symbol.
391 *
392 * @returns 0 on success.
393 * @returns VBox evaluation / parsing error code on failure.
394 * The caller does the bitching.
395 * @param pSymDesc Pointer to the symbol descriptor.
396 * @param pCmdHlp Pointer to the command callback structure.
397 * @param pValue The value to assign the symbol.
398 */
399typedef DECLCALLBACK(int) FNDBGCSYMSET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue);
400/** Pointer to set function for a builtin symbol. */
401typedef FNDBGCSYMSET *PFNDBGCSYMSET;
402
403
404/**
405 * Symbol description (for builtin symbols).
406 */
407typedef struct DBGCSYM
408{
409 /** Symbol name. */
410 const char *pszName;
411 /** Get function. */
412 PFNDBGCSYMGET pfnGet;
413 /** Set function. (NULL if readonly) */
414 PFNDBGCSYMSET pfnSet;
415 /** User data. */
416 unsigned uUser;
417} DBGCSYM;
418
419
420/*******************************************************************************
421* Internal Functions *
422*******************************************************************************/
423static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
424static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
425static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
426static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
427static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
428static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
429static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
430static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
431static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
432static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
433static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
434static DECLCALLBACK(int) dbgcCmdDisasm(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
435static DECLCALLBACK(int) dbgcCmdSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
436static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
437static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
438static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
439static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
440static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
441static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
442static DECLCALLBACK(int) dbgcCmdDumpDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
443static DECLCALLBACK(int) dbgcCmdDumpIDT(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
444static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
445static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
446static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
447static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
448static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
449static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
450static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
451static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
452static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
453static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
454static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
455static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
456static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
457static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
458static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
459static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
460static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
461static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
462static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
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 * The 'dpd*' commands.
3128 *
3129 * @returns VBox status.
3130 * @param pCmd Pointer to the command descriptor (as registered).
3131 * @param pCmdHlp Pointer to command helper functions.
3132 * @param pVM Pointer to the current VM (if any).
3133 * @param paArgs Pointer to (readonly) array of arguments.
3134 * @param cArgs Number of arguments in the array.
3135 */
3136static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3137{
3138 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3139
3140 /*
3141 * Validate input.
3142 */
3143 if ( cArgs > 1
3144 || (cArgs == 1 && pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
3145 || (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
3146 )
3147 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
3148 if (!pVM)
3149 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3150
3151
3152 /*
3153 * Where to start dumping page directory entries?
3154 */
3155 int rc;
3156 unsigned cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE);
3157 unsigned cEntries = PAGE_SIZE / sizeof(VBOXPDE);
3158 unsigned off = ~0;
3159 uint32_t u32CR4 = X86_CR4_PSE;
3160 DBGCVAR VarAddr;
3161 if (cArgs == 0 || pCmd->pszCmd[3] != 'a')
3162 {
3163 /*
3164 * Get defaults.
3165 */
3166 off = 0;
3167 if ( pCmd->pszCmd[3] == 'g'
3168 || (pDbgc->fRegCtxGuest && (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')))
3169 {
3170 u32CR4 = CPUMGetGuestCR4(pVM);
3171 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%%%%cr3");
3172 }
3173 else
3174 {
3175 /** @todo fix hypervisor CR4 value! */
3176 //u32CR4 = CPUMGetHyperCR4(pVM);
3177 u32CR4 = X86_CR4_PGE | X86_CR4_PSE;
3178 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "#%%%%.cr3");
3179 }
3180 if (VBOX_FAILURE(rc))
3181 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(Getting (.)cr3.)");
3182
3183 if (cArgs > 0)
3184 {
3185 cEntries = 3;
3186 if (!DBGCVAR_ISPOINTER(paArgs[0].enmType))
3187 {
3188 /*
3189 * Add index.
3190 */
3191 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE));
3192 if (VBOX_FAILURE(rc))
3193 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE));
3194 if (paArgs[0].u.u64Number >= PAGE_SIZE / sizeof(VBOXPDE))
3195 off = ~0;
3196 else
3197 {
3198 off = (unsigned)paArgs[0].u.u64Number;
3199 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off;
3200 }
3201 }
3202 else
3203 {
3204 /*
3205 * Pointer which we want the page directory entry for.
3206 * Start by making sure it's a GC pointer.
3207 */
3208 DBGCVAR VarTmp;
3209 rc = pCmdHlp->pfnEval(pCmdHlp, &VarTmp, "%%(%Dv)", &paArgs[0]);
3210 if (VBOX_FAILURE(rc))
3211 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%Dv) failed.", &paArgs[0]);
3212
3213 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE));
3214 if (VBOX_FAILURE(rc))
3215 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE));
3216 off = VarTmp.u.GCFlat >> PGDIR_SHIFT;
3217 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off;
3218 }
3219 }
3220 }
3221 else
3222 VarAddr = paArgs[0];
3223
3224 /*
3225 * Range.
3226 */
3227 unsigned i = cArgs;
3228 while (i-- > 0)
3229 {
3230 if (paArgs[i].enmRangeType == DBGCVAR_RANGE_ELEMENTS)
3231 {
3232 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range, cEntriesMax);
3233 break;
3234 }
3235 else if (paArgs[i].enmRangeType == DBGCVAR_RANGE_BYTES)
3236 {
3237 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range / sizeof(VBOXPDE), cEntriesMax);
3238 break;
3239 }
3240 }
3241
3242 /*
3243 * Dump loop.
3244 */
3245 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (index %#x):\n" : "%DV:\n", &VarAddr, off);
3246 if (VBOX_FAILURE(rc))
3247 return rc;
3248 for (;;)
3249 {
3250 /*
3251 * Read.
3252 */
3253 VBOXPDE Pde;
3254 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarAddr, NULL);
3255 if (VBOX_FAILURE(rc))
3256 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &VarAddr);
3257
3258 /*
3259 * Display.
3260 */
3261 if (off != ~0U)
3262 {
3263 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%03x %08x: ", off, off << PGDIR_SHIFT);
3264 off++;
3265 }
3266 if ((u32CR4 & X86_CR4_PSE) && Pde.b.u1Size)
3267 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3268 "%08x big phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
3269 Pde.u, Pde.b.u10PageNo << PGDIR_SHIFT, Pde.b.u1Present ? "p " : "np", Pde.b.u1Write ? "w" : "r",
3270 Pde.b.u1User ? "u" : "s", Pde.b.u1Accessed ? "a " : "na", Pde.b.u1Dirty ? "d " : "nd",
3271 Pde.b.u3Available, Pde.b.u1Global ? "G" : " ", Pde.b.u1WriteThru ? "pwt" : " ",
3272 Pde.b.u1CacheDisable ? "pcd" : " ", Pde.b.u1PAT ? "pat" : "");
3273 else
3274 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3275 "%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
3276 Pde.u, Pde.n.u20PageNo << PAGE_SHIFT, Pde.n.u1Present ? "p " : "np", Pde.n.u1Write ? "w" : "r",
3277 Pde.n.u1User ? "u" : "s", Pde.n.u1Accessed ? "a " : "na", Pde.u & BIT(6) ? "6 " : " ",
3278 Pde.n.u3Available, Pde.u & BIT(8) ? "8" : " ", Pde.n.u1WriteThru ? "pwt" : " ",
3279 Pde.n.u1CacheDisable ? "pcd" : " ", Pde.u & BIT(7) ? "7" : "");
3280 if (VBOX_FAILURE(rc))
3281 return rc;
3282
3283 /*
3284 * Next
3285 */
3286 if (cEntries-- <= 1)
3287 break;
3288 rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, sizeof(VBOXPDE));
3289 if (VBOX_FAILURE(rc))
3290 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, sizeof(VBOXPDE));
3291 }
3292
3293 NOREF(pResult);
3294 return VINF_SUCCESS;
3295}
3296
3297/**
3298 * The 'dpdb' command.
3299 *
3300 * @returns VBox status.
3301 * @param pCmd Pointer to the command descriptor (as registered).
3302 * @param pCmdHlp Pointer to command helper functions.
3303 * @param pVM Pointer to the current VM (if any).
3304 * @param paArgs Pointer to (readonly) array of arguments.
3305 * @param cArgs Number of arguments in the array.
3306 */
3307static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3308{
3309 if (!pVM)
3310 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3311 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
3312 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
3313 if (VBOX_FAILURE(rc1))
3314 return rc1;
3315 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
3316 return rc2;
3317}
3318
3319
3320/**
3321 * The 'dpg*' commands.
3322 *
3323 * @returns VBox status.
3324 * @param pCmd Pointer to the command descriptor (as registered).
3325 * @param pCmdHlp Pointer to command helper functions.
3326 * @param pVM Pointer to the current VM (if any).
3327 * @param paArgs Pointer to (readonly) array of arguments.
3328 * @param cArgs Number of arguments in the array.
3329 */
3330static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3331{
3332 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
3333
3334 /*
3335 * Validate input.
3336 */
3337 if ( cArgs != 1
3338 || (pCmd->pszCmd[3] == 'a' && !DBGCVAR_ISPOINTER(paArgs[0].enmType))
3339 || (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
3340 )
3341 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
3342 if (!pVM)
3343 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3344
3345
3346 /*
3347 * Where to start dumping page directory entries?
3348 */
3349 int rc;
3350 unsigned cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE);
3351 unsigned cEntries = PAGE_SIZE / sizeof(VBOXPDE);
3352 unsigned off = ~0;
3353 DBGCVAR VarGCPtr; /* only valid with off == ~0 */
3354 DBGCVAR VarPTEAddr;
3355 if (pCmd->pszCmd[3] != 'a')
3356 {
3357 /*
3358 * Get page directory and cr4.
3359 */
3360 bool fHyper;
3361 uint32_t u32CR4;
3362 off = 0;
3363 if ( pCmd->pszCmd[3] == 'g'
3364 || (pDbgc->fRegCtxGuest && (!pCmd->pszCmd[3] || pCmd->pszCmd[3] == 'a')))
3365 {
3366 u32CR4 = CPUMGetGuestCR4(pVM);
3367 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%%%%cr3");
3368 fHyper = false;
3369 }
3370 else
3371 {
3372 /** @todo fix hypervisor CR4 value! */
3373 //u32CR4 = CPUMGetHyperCR4(pVM);
3374 u32CR4 = X86_CR4_PGE | X86_CR4_PSE;
3375 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "#%%%%.cr3");
3376 fHyper = true;
3377 }
3378 if (VBOX_FAILURE(rc))
3379 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(Getting (.)cr3.)");
3380
3381 /*
3382 * Find page directory entry for the address.
3383 * Make sure it's a flat address first.
3384 */
3385 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%%(%Dv)", &paArgs[0]);
3386 if (VBOX_FAILURE(rc))
3387 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%Dv)", &paArgs[0]);
3388
3389 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "(%Dv) + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE));
3390 if (VBOX_FAILURE(rc))
3391 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "(%Dv) + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE));
3392
3393
3394 /*
3395 * Now read the page directory entry for this GC address.
3396 */
3397 VBOXPDE Pde;
3398 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pde, sizeof(Pde), &VarPTEAddr, NULL);
3399 if (VBOX_FAILURE(rc))
3400 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &VarPTEAddr);
3401
3402 /*
3403 * Check for presentness and handle big using dpd[gh].
3404 */
3405 if ((u32CR4 & X86_CR4_PSE) && Pde.b.u1Size)
3406 return pCmdHlp->pfnExec(pCmdHlp, "dpd%s %Dv L3", &pCmd->pszCmd[3], &VarGCPtr);
3407
3408 if (!Pde.n.u1Present)
3409 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Page table for %Dv is not present.\n", &VarGCPtr);
3410
3411 /*
3412 * Calc page table address and setup offset and counts.
3413 */
3414 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK);
3415 if (VBOX_FAILURE(rc))
3416 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK);
3417
3418 cEntries = 10;
3419 off = (VarGCPtr.u.GCFlat >> PAGE_SHIFT) & PTE_MASK;
3420 cEntriesMax = PAGE_SIZE / sizeof(VBOXPDE) - off;
3421 VarGCPtr.u.GCFlat &= ~PAGE_OFFSET_MASK; /* Make it page table base address. */
3422 }
3423 else
3424 VarPTEAddr = paArgs[0];
3425
3426 /*
3427 * Range.
3428 */
3429 unsigned i = cArgs;
3430 while (i-- > 0)
3431 {
3432 if (paArgs[i].enmRangeType == DBGCVAR_RANGE_ELEMENTS)
3433 {
3434 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range, cEntriesMax);
3435 break;
3436 }
3437 else if (paArgs[i].enmRangeType == DBGCVAR_RANGE_BYTES)
3438 {
3439 cEntries = (unsigned)RT_MIN(paArgs[i].u64Range / sizeof(VBOXPDE), cEntriesMax);
3440 break;
3441 }
3442 }
3443
3444 /*
3445 * Dump loop.
3446 */
3447 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", &VarPTEAddr, &VarGCPtr, off);
3448 if (VBOX_FAILURE(rc))
3449 return rc;
3450 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPTE) * off);
3451 if (VBOX_FAILURE(rc))
3452 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPTE) * off);
3453 for (;;)
3454 {
3455 /*
3456 * Read.
3457 */
3458 VBOXPTE Pte;
3459 rc = pCmdHlp->pfnMemRead(pCmdHlp, pVM, &Pte, sizeof(Pte), &VarPTEAddr, NULL);
3460 if (VBOX_FAILURE(rc))
3461 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Reading memory at %DV.\n", &VarPTEAddr);
3462
3463 /*
3464 * Display.
3465 */
3466 if (off != ~0U)
3467 {
3468 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%03x %DV: ", off, &VarGCPtr);
3469 off++;
3470 }
3471 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3472 "%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
3473 Pte.u, Pte.n.u20PageNo << PAGE_SHIFT, Pte.n.u1Present ? "p " : "np", Pte.n.u1Write ? "w" : "r",
3474 Pte.n.u1User ? "u" : "s", Pte.n.u1Accessed ? "a " : "na", Pte.n.u1Dirty ? "d " : "nd",
3475 Pte.n.u3Available, Pte.n.u1Global ? "G" : " ", Pte.n.u1WriteThru ? "pwt" : " ",
3476 Pte.n.u1CacheDisable ? "pcd" : " ", Pte.n.u1PAT ? "pat" : " ");
3477 if (VBOX_FAILURE(rc))
3478 return rc;
3479
3480 /*
3481 * Next
3482 */
3483 if (cEntries-- <= 1)
3484 break;
3485 rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPDE));
3486 if (VBOX_FAILURE(rc))
3487 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarPTEAddr, sizeof(VBOXPDE));
3488 rc = pCmdHlp->pfnEval(pCmdHlp, &VarGCPtr, "%DV + %#x", &VarGCPtr, PAGE_SIZE);
3489 if (VBOX_FAILURE(rc))
3490 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarGCPtr, sizeof(VBOXPDE));
3491 }
3492
3493 NOREF(pResult);
3494 return VINF_SUCCESS;
3495}
3496
3497
3498/**
3499 * The 'dptb' command.
3500 *
3501 * @returns VBox status.
3502 * @param pCmd Pointer to the command descriptor (as registered).
3503 * @param pCmdHlp Pointer to command helper functions.
3504 * @param pVM Pointer to the current VM (if any).
3505 * @param paArgs Pointer to (readonly) array of arguments.
3506 * @param cArgs Number of arguments in the array.
3507 */
3508static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3509{
3510 if (!pVM)
3511 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3512 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
3513 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
3514 if (VBOX_FAILURE(rc1))
3515 return rc1;
3516 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3517 return rc2;
3518}
3519
3520
3521/**
3522 * The 'dt' command.
3523 *
3524 * @returns VBox status.
3525 * @param pCmd Pointer to the command descriptor (as registered).
3526 * @param pCmdHlp Pointer to command helper functions.
3527 * @param pVM Pointer to the current VM (if any).
3528 * @param paArgs Pointer to (readonly) array of arguments.
3529 * @param cArgs Number of arguments in the array.
3530 */
3531static DECLCALLBACK(int) dbgcCmdDumpTSS(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM /*pVM*/, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
3532{
3533 /*
3534 * We can get a TSS selector (number), a far pointer using a TSS selector, or some kind of TSS pointer.
3535 */
3536
3537 /** @todo */
3538 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dt is not implemented yet, feel free to do it. \n");
3539}
3540
3541
3542/**
3543 * The 'm' command.
3544 *
3545 * @returns VBox status.
3546 * @param pCmd Pointer to the command descriptor (as registered).
3547 * @param pCmdHlp Pointer to command helper functions.
3548 * @param pVM Pointer to the current VM (if any).
3549 * @param paArgs Pointer to (readonly) array of arguments.
3550 * @param cArgs Number of arguments in the array.
3551 */
3552static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3553{
3554 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Address: %DV\n", &paArgs[0]);
3555 if (!pVM)
3556 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3557 int rc1 = pCmdHlp->pfnExec(pCmdHlp, "dpdg %DV", &paArgs[0]);
3558 int rc2 = pCmdHlp->pfnExec(pCmdHlp, "dpdh %DV", &paArgs[0]);
3559 int rc3 = pCmdHlp->pfnExec(pCmdHlp, "dptg %DV", &paArgs[0]);
3560 int rc4 = pCmdHlp->pfnExec(pCmdHlp, "dpth %DV", &paArgs[0]);
3561 if (VBOX_FAILURE(rc1))
3562 return rc1;
3563 if (VBOX_FAILURE(rc2))
3564 return rc2;
3565 if (VBOX_FAILURE(rc3))
3566 return rc3;
3567 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3568 return rc4;
3569}
3570
3571
3572/**
3573 * The 'echo' command.
3574 *
3575 * @returns VBox status.
3576 * @param pCmd Pointer to the command descriptor (as registered).
3577 * @param pCmdHlp Pointer to command helper functions.
3578 * @param pVM Pointer to the current VM (if any).
3579 * @param paArgs Pointer to (readonly) array of arguments.
3580 * @param cArgs Number of arguments in the array.
3581 */
3582static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3583{
3584 /*
3585 * Loop thru the arguments and print them with one space between.
3586 */
3587 int rc = 0;
3588 for (unsigned i = 0; i < cArgs; i++)
3589 {
3590 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
3591 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
3592 else
3593 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
3594 if (VBOX_FAILURE(rc))
3595 return rc;
3596 }
3597 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
3598 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
3599}
3600
3601
3602/**
3603 * The 'echo' command.
3604 *
3605 * @returns VBox status.
3606 * @param pCmd Pointer to the command descriptor (as registered).
3607 * @param pCmdHlp Pointer to command helper functions.
3608 * @param pVM Pointer to the current VM (if any).
3609 * @param paArgs Pointer to (readonly) array of arguments.
3610 * @param cArgs Number of arguments in the array.
3611 */
3612static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3613{
3614 /* check that the parser did what it's supposed to do. */
3615 if ( cArgs != 1
3616 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
3617 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
3618
3619 /*
3620 * Try open the script.
3621 */
3622 const char *pszFilename = paArgs[0].u.pszString;
3623 FILE *pFile = fopen(pszFilename, "r");
3624 if (!pFile)
3625 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
3626
3627 /*
3628 * Execute it line by line.
3629 */
3630 int rc = 0;
3631 unsigned iLine = 0;
3632 char szLine[8192];
3633 while (fgets(szLine, sizeof(szLine), pFile))
3634 {
3635 /* check that the line isn't too long. */
3636 char *pszEnd = strchr(szLine, '\0');
3637 if (pszEnd == &szLine[sizeof(szLine) - 1])
3638 {
3639 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
3640 break;
3641 }
3642 iLine++;
3643
3644 /* strip leading blanks and check for comment / blank line. */
3645 char *psz = RTStrStripL(szLine);
3646 if ( *psz == '\0'
3647 || *psz == '\n'
3648 || *psz == '#')
3649 continue;
3650
3651 /* strip trailing blanks and check for empty line (\r case). */
3652 while ( pszEnd > psz
3653 && isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */
3654 *++pszEnd = '\0';
3655
3656 /** @todo check for Control-C / Cancel at this point... */
3657
3658 /*
3659 * Execute the command.
3660 *
3661 * This is a bit wasteful with scratch space btw., can fix it later.
3662 * The whole return code crap should be fixed too, so that it's possible
3663 * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and
3664 * more importantly why it failed.
3665 */
3666 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", szLine);
3667 if (VBOX_FAILURE(rc))
3668 {
3669 if (rc == VERR_BUFFER_OVERFLOW)
3670 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
3671 break;
3672 }
3673 if (rc == VWRN_DBGC_CMD_PENDING)
3674 {
3675 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
3676 break;
3677 }
3678 }
3679
3680 fclose(pFile);
3681
3682 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
3683 return rc;
3684}
3685
3686
3687
3688/**
3689 * Print formatted string.
3690 *
3691 * @param pHlp Pointer to this structure.
3692 * @param pszFormat The format string.
3693 * @param ... Arguments.
3694 */
3695static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
3696{
3697 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
3698 va_list args;
3699 va_start(args, pszFormat);
3700 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
3701 va_end(args);
3702}
3703
3704
3705/**
3706 * Print formatted string.
3707 *
3708 * @param pHlp Pointer to this structure.
3709 * @param pszFormat The format string.
3710 * @param args Argument list.
3711 */
3712static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
3713{
3714 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
3715 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
3716}
3717
3718
3719/**
3720 * The 'info' command.
3721 *
3722 * @returns VBox status.
3723 * @param pCmd Pointer to the command descriptor (as registered).
3724 * @param pCmdHlp Pointer to command helper functions.
3725 * @param pVM Pointer to the current VM (if any).
3726 * @param paArgs Pointer to (readonly) array of arguments.
3727 * @param cArgs Number of arguments in the array.
3728 */
3729static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3730{
3731 /*
3732 * Validate input.
3733 */
3734 if ( cArgs < 1
3735 || cArgs > 2
3736 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
3737 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
3738 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
3739 if (!pVM)
3740 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
3741
3742 /*
3743 * Dump it.
3744 */
3745 struct
3746 {
3747 DBGFINFOHLP Hlp;
3748 PDBGCCMDHLP pCmdHlp;
3749 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
3750 int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
3751 if (VBOX_FAILURE(rc))
3752 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
3753
3754 NOREF(pCmd); NOREF(pResult);
3755 return 0;
3756}
3757
3758
3759/**
3760 * The 'log' command.
3761 *
3762 * @returns VBox status.
3763 * @param pCmd Pointer to the command descriptor (as registered).
3764 * @param pCmdHlp Pointer to command helper functions.
3765 * @param pVM Pointer to the current VM (if any).
3766 * @param paArgs Pointer to (readonly) array of arguments.
3767 * @param cArgs Number of arguments in the array.
3768 */
3769static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3770{
3771 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
3772 if (VBOX_SUCCESS(rc))
3773 return VINF_SUCCESS;
3774 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3775 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
3776}
3777
3778
3779/**
3780 * The 'logdest' command.
3781 *
3782 * @returns VBox status.
3783 * @param pCmd Pointer to the command descriptor (as registered).
3784 * @param pCmdHlp Pointer to command helper functions.
3785 * @param pVM Pointer to the current VM (if any).
3786 * @param paArgs Pointer to (readonly) array of arguments.
3787 * @param cArgs Number of arguments in the array.
3788 */
3789static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3790{
3791 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
3792 if (VBOX_SUCCESS(rc))
3793 return VINF_SUCCESS;
3794 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3795 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
3796}
3797
3798
3799/**
3800 * The 'logflags' command.
3801 *
3802 * @returns VBox status.
3803 * @param pCmd Pointer to the command descriptor (as registered).
3804 * @param pCmdHlp Pointer to command helper functions.
3805 * @param pVM Pointer to the current VM (if any).
3806 * @param paArgs Pointer to (readonly) array of arguments.
3807 * @param cArgs Number of arguments in the array.
3808 */
3809static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3810{
3811 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
3812 if (VBOX_SUCCESS(rc))
3813 return VINF_SUCCESS;
3814 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
3815 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
3816}
3817
3818
3819/**
3820 * The 'format' command.
3821 *
3822 * @returns VBox status.
3823 * @param pCmd Pointer to the command descriptor (as registered).
3824 * @param pCmdHlp Pointer to command helper functions.
3825 * @param pVM Pointer to the current VM (if any).
3826 * @param paArgs Pointer to (readonly) array of arguments.
3827 * @param cArgs Number of arguments in the array.
3828 */
3829static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
3830{
3831 LogFlow(("dbgcCmdFormat\n"));
3832 static const char *apszRangeDesc[] =
3833 {
3834 "none", "bytes", "elements"
3835 };
3836 int rc;
3837
3838 for (unsigned iArg = 0; iArg < cArgs; iArg++)
3839 {
3840 switch (paArgs[iArg].enmType)
3841 {
3842 case DBGCVAR_TYPE_UNKNOWN:
3843 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3844 "Unknown variable type!\n");
3845 break;
3846 case DBGCVAR_TYPE_GC_FLAT:
3847 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3848 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3849 "Guest flat address: %%%08x range %lld %s\n",
3850 paArgs[iArg].u.GCFlat,
3851 paArgs[iArg].u64Range,
3852 apszRangeDesc[paArgs[iArg].enmRangeType]);
3853 else
3854 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3855 "Guest flat address: %%%08x\n",
3856 paArgs[iArg].u.GCFlat);
3857 break;
3858 case DBGCVAR_TYPE_GC_FAR:
3859 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3860 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3861 "Guest far address: %04x:%08x range %lld %s\n",
3862 paArgs[iArg].u.GCFar.sel,
3863 paArgs[iArg].u.GCFar.off,
3864 paArgs[iArg].u64Range,
3865 apszRangeDesc[paArgs[iArg].enmRangeType]);
3866 else
3867 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3868 "Guest far address: %04x:%08x\n",
3869 paArgs[iArg].u.GCFar.sel,
3870 paArgs[iArg].u.GCFar.off);
3871 break;
3872 case DBGCVAR_TYPE_GC_PHYS:
3873 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3874 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3875 "Guest physical address: %%%%%08x range %lld %s\n",
3876 paArgs[iArg].u.GCPhys,
3877 paArgs[iArg].u64Range,
3878 apszRangeDesc[paArgs[iArg].enmRangeType]);
3879 else
3880 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3881 "Guest physical address: %%%%%08x\n",
3882 paArgs[iArg].u.GCPhys);
3883 break;
3884 case DBGCVAR_TYPE_HC_FLAT:
3885 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3886 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3887 "Host flat address: %%%08x range %lld %s\n",
3888 paArgs[iArg].u.pvHCFlat,
3889 paArgs[iArg].u64Range,
3890 apszRangeDesc[paArgs[iArg].enmRangeType]);
3891 else
3892 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3893 "Host flat address: %%%08x\n",
3894 paArgs[iArg].u.pvHCFlat);
3895 break;
3896 case DBGCVAR_TYPE_HC_FAR:
3897 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3898 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3899 "Host far address: %04x:%08x range %lld %s\n",
3900 paArgs[iArg].u.HCFar.sel,
3901 paArgs[iArg].u.HCFar.off,
3902 paArgs[iArg].u64Range,
3903 apszRangeDesc[paArgs[iArg].enmRangeType]);
3904 else
3905 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3906 "Host far address: %04x:%08x\n",
3907 paArgs[iArg].u.HCFar.sel,
3908 paArgs[iArg].u.HCFar.off);
3909 break;
3910 case DBGCVAR_TYPE_HC_PHYS:
3911 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3912 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3913 "Host physical address: %VHp range %lld %s\n",
3914 paArgs[iArg].u.HCPhys,
3915 paArgs[iArg].u64Range,
3916 apszRangeDesc[paArgs[iArg].enmRangeType]);
3917 else
3918 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3919 "Host physical address: %VHp\n",
3920 paArgs[iArg].u.HCPhys);
3921 break;
3922
3923 case DBGCVAR_TYPE_STRING:
3924 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3925 "String, %lld bytes long: %s\n",
3926 paArgs[iArg].u64Range,
3927 paArgs[iArg].u.pszString);
3928 break;
3929
3930 case DBGCVAR_TYPE_NUMBER:
3931 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
3932 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3933 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
3934 paArgs[iArg].u.u64Number,
3935 paArgs[iArg].u.u64Number,
3936 paArgs[iArg].u.u64Number,
3937 paArgs[iArg].u64Range,
3938 apszRangeDesc[paArgs[iArg].enmRangeType]);
3939 else
3940 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3941 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
3942 paArgs[iArg].u.u64Number,
3943 paArgs[iArg].u.u64Number,
3944 paArgs[iArg].u.u64Number);
3945 break;
3946
3947 default:
3948 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
3949 "Invalid argument type %d\n",
3950 paArgs[iArg].enmType);
3951 break;
3952 }
3953 } /* arg loop */
3954
3955 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
3956 return 0;
3957}
3958
3959
3960/**
3961 * List near symbol.
3962 *
3963 * @returns VBox status code.
3964 * @param pCmdHlp Pointer to command helper functions.
3965 * @param pVM Pointer to the current VM (if any).
3966 * @param pArg Pointer to the address or symbol to lookup.
3967 */
3968static int dbgcDoListNear(PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR pArg, PDBGCVAR pResult)
3969{
3970 dbgcVarSetGCFlat(pResult, 0);
3971
3972 DBGFSYMBOL Symbol;
3973 int rc;
3974 if (pArg->enmType == DBGCVAR_TYPE_SYMBOL)
3975 {
3976 /*
3977 * Lookup the symbol address.
3978 */
3979 rc = DBGFR3SymbolByName(pVM, pArg->u.pszString, &Symbol);
3980 if (VBOX_FAILURE(rc))
3981 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByName(, %s,)\n", pArg->u.pszString);
3982
3983 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */
3984 dbgcVarSetGCFlatByteRange(pResult, Symbol.Value, Symbol.cb);
3985 }
3986 else
3987 {
3988 /*
3989 * Convert it to a flat GC address and lookup that address.
3990 */
3991 DBGCVAR AddrVar;
3992 rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%DV)", pArg);
3993 if (VBOX_FAILURE(rc))
3994 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(%DV)\n", pArg);
3995
3996 dbgcVarSetVar(pResult, &AddrVar);
3997
3998 RTGCINTPTR offDisp = 0;
3999 rc = DBGFR3SymbolByAddr(pVM, AddrVar.u.GCFlat, &offDisp, &Symbol);
4000 if (VBOX_FAILURE(rc))
4001 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3SymbolByAddr(, %VGv,,)\n", AddrVar.u.GCFlat);
4002
4003 if (!offDisp)
4004 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s", &AddrVar, Symbol.szName);
4005 else if (offDisp > 0)
4006 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s + %RGv", &AddrVar, Symbol.szName, offDisp);
4007 else
4008 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%DV %s - %RGv", &AddrVar, Symbol.szName, -offDisp);
4009 if ((RTGCINTPTR)Symbol.cb > -offDisp)
4010 {
4011 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " LB %RGv\n", Symbol.cb + offDisp);
4012 dbgcVarSetByteRange(pResult, Symbol.cb + offDisp);
4013 }
4014 else
4015 {
4016 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
4017 dbgcVarSetNoRange(pResult);
4018 }
4019 }
4020
4021 return rc;
4022}
4023
4024
4025/**
4026 * The 'ln' (listnear) command.
4027 *
4028 * @returns VBox status.
4029 * @param pCmd Pointer to the command descriptor (as registered).
4030 * @param pCmdHlp Pointer to command helper functions.
4031 * @param pVM Pointer to the current VM (if any).
4032 * @param paArgs Pointer to (readonly) array of arguments.
4033 * @param cArgs Number of arguments in the array.
4034 */
4035static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4036{
4037 dbgcVarSetGCFlat(pResult, 0);
4038 if (!cArgs)
4039 {
4040 /*
4041 * Current cs:eip symbol.
4042 */
4043 DBGCVAR AddrVar;
4044 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(cs:eip)");
4045 if (VBOX_FAILURE(rc))
4046 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%%(cs:eip)\n");
4047 return dbgcDoListNear(pCmdHlp, pVM, &AddrVar, pResult);
4048 }
4049
4050 /*
4051 * Iterate arguments.
4052 */
4053 for (unsigned iArg = 0; iArg < cArgs; iArg++)
4054 {
4055 int rc = dbgcDoListNear(pCmdHlp, pVM, &paArgs[iArg], pResult);
4056 if (VBOX_FAILURE(rc))
4057 return rc;
4058 }
4059
4060 NOREF(pCmd); NOREF(pResult);
4061 return VINF_SUCCESS;
4062}
4063
4064
4065/**
4066 * The 'loadsyms' command.
4067 *
4068 * @returns VBox status.
4069 * @param pCmd Pointer to the command descriptor (as registered).
4070 * @param pCmdHlp Pointer to command helper functions.
4071 * @param pVM Pointer to the current VM (if any).
4072 * @param paArgs Pointer to (readonly) array of arguments.
4073 * @param cArgs Number of arguments in the array.
4074 */
4075static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4076{
4077 /*
4078 * Validate the parsing and make sense of the input.
4079 * This is a mess as usual because we don't trust the parser yet.
4080 */
4081 if ( cArgs < 1
4082 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
4083 {
4084 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
4085 return VERR_PARSE_INCORRECT_ARG_TYPE;
4086 }
4087 DBGCVAR AddrVar;
4088 RTGCUINTPTR Delta = 0;
4089 const char *pszModule = NULL;
4090 RTGCUINTPTR ModuleAddress = 0;
4091 unsigned cbModule = 0;
4092 if (cArgs > 1)
4093 {
4094 unsigned iArg = 1;
4095 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
4096 {
4097 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
4098 iArg++;
4099 }
4100 if (iArg < cArgs)
4101 {
4102 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
4103 {
4104 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
4105 return VERR_PARSE_INCORRECT_ARG_TYPE;
4106 }
4107 pszModule = paArgs[iArg].u.pszString;
4108 iArg++;
4109 if (iArg < cArgs)
4110 {
4111 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
4112 {
4113 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
4114 return VERR_PARSE_INCORRECT_ARG_TYPE;
4115 }
4116 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
4117 if (VBOX_FAILURE(rc))
4118 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
4119 ModuleAddress = paArgs[iArg].u.GCFlat;
4120 iArg++;
4121 if (iArg < cArgs)
4122 {
4123 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
4124 {
4125 AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
4126 return VERR_PARSE_INCORRECT_ARG_TYPE;
4127 }
4128 cbModule = (unsigned)paArgs[iArg].u.u64Number;
4129 iArg++;
4130 if (iArg < cArgs)
4131 {
4132 AssertMsgFailed(("Parse error, too many arguments!\n"));
4133 return VERR_PARSE_TOO_MANY_ARGUMENTS;
4134 }
4135 }
4136 }
4137 }
4138 }
4139
4140 /*
4141 * Call the debug info manager about this loading...
4142 */
4143 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
4144 if (VBOX_FAILURE(rc))
4145 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",
4146 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
4147
4148 NOREF(pCmd); NOREF(pResult);
4149 return VINF_SUCCESS;
4150}
4151
4152
4153/**
4154 * The 'set' command.
4155 *
4156 * @returns VBox status.
4157 * @param pCmd Pointer to the command descriptor (as registered).
4158 * @param pCmdHlp Pointer to command helper functions.
4159 * @param pVM Pointer to the current VM (if any).
4160 * @param paArgs Pointer to (readonly) array of arguments.
4161 * @param cArgs Number of arguments in the array.
4162 */
4163static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4164{
4165 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4166
4167 /* parse sanity check. */
4168 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
4169 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
4170 return VERR_PARSE_INCORRECT_ARG_TYPE;
4171
4172
4173 /*
4174 * A variable must start with an alpha chars and only contain alpha numerical chars.
4175 */
4176 const char *pszVar = paArgs[0].u.pszString;
4177 if (!isalpha(*pszVar) || *pszVar == '_')
4178 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
4179 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
4180
4181 while (isalnum(*pszVar) || *pszVar == '_')
4182 *pszVar++;
4183 if (*pszVar)
4184 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
4185 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
4186
4187
4188 /*
4189 * Calc variable size.
4190 */
4191 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
4192 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
4193 cbVar += 1 + (size_t)paArgs[1].u64Range;
4194
4195 /*
4196 * Look for existing one.
4197 */
4198 pszVar = paArgs[0].u.pszString;
4199 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
4200 {
4201 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
4202 {
4203 /*
4204 * Update existing variable.
4205 */
4206 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
4207 if (!pv)
4208 return VERR_PARSE_NO_MEMORY;
4209 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
4210
4211 pVar->Var = paArgs[1];
4212 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
4213 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
4214 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
4215 return 0;
4216 }
4217 }
4218
4219 /*
4220 * Allocate another.
4221 */
4222 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
4223
4224 pVar->Var = paArgs[1];
4225 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
4226 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
4227 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
4228
4229 /* need to reallocate the pointer array too? */
4230 if (!(pDbgc->cVars % 0x20))
4231 {
4232 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
4233 if (!pv)
4234 {
4235 RTMemFree(pVar);
4236 return VERR_PARSE_NO_MEMORY;
4237 }
4238 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
4239 }
4240 pDbgc->papVars[pDbgc->cVars++] = pVar;
4241
4242 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
4243 return 0;
4244}
4245
4246
4247/**
4248 * The 'unset' command.
4249 *
4250 * @returns VBox status.
4251 * @param pCmd Pointer to the command descriptor (as registered).
4252 * @param pCmdHlp Pointer to command helper functions.
4253 * @param pVM Pointer to the current VM (if any).
4254 * @param paArgs Pointer to (readonly) array of arguments.
4255 * @param cArgs Number of arguments in the array.
4256 */
4257static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4258{
4259 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4260
4261 /*
4262 * Don't trust the parser.
4263 */
4264 for (unsigned i = 0; i < cArgs; i++)
4265 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
4266 {
4267 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
4268 return VERR_PARSE_INCORRECT_ARG_TYPE;
4269 }
4270
4271 /*
4272 * Iterate the variables and unset them.
4273 */
4274 for (unsigned iArg = 0; iArg < cArgs; iArg++)
4275 {
4276 const char *pszVar = paArgs[iArg].u.pszString;
4277
4278 /*
4279 * Look up the variable.
4280 */
4281 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
4282 {
4283 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
4284 {
4285 /*
4286 * Shuffle the array removing this entry.
4287 */
4288 void *pvFree = pDbgc->papVars[iVar];
4289 if (iVar + 1 < pDbgc->cVars)
4290 memmove(&pDbgc->papVars[iVar],
4291 &pDbgc->papVars[iVar + 1],
4292 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
4293 pDbgc->papVars[--pDbgc->cVars] = NULL;
4294
4295 RTMemFree(pvFree);
4296 }
4297 } /* lookup */
4298 } /* arg loop */
4299
4300 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
4301 return 0;
4302}
4303
4304
4305/**
4306 * The 'loadvars' command.
4307 *
4308 * @returns VBox status.
4309 * @param pCmd Pointer to the command descriptor (as registered).
4310 * @param pCmdHlp Pointer to command helper functions.
4311 * @param pVM Pointer to the current VM (if any).
4312 * @param paArgs Pointer to (readonly) array of arguments.
4313 * @param cArgs Number of arguments in the array.
4314 */
4315static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4316{
4317 /*
4318 * Don't trust the parser.
4319 */
4320 if ( cArgs != 1
4321 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
4322 {
4323 AssertMsgFailed(("Expected one string exactly!\n"));
4324 return VERR_PARSE_INCORRECT_ARG_TYPE;
4325 }
4326
4327 /*
4328 * Iterate the variables and unset them.
4329 */
4330 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
4331 if (pFile)
4332 {
4333 char szLine[4096];
4334 while (fgets(szLine, sizeof(szLine), pFile))
4335 {
4336 /* Strip it. */
4337 char *psz = szLine;
4338 while (isblank(*psz))
4339 psz++;
4340 int i = strlen(psz) - 1;
4341 while (i >= 0 && isspace(psz[i]))
4342 psz[i--] ='\0';
4343 /* Execute it if not comment or empty line. */
4344 if ( *psz != '\0'
4345 && *psz != '#'
4346 && *psz != ';')
4347 {
4348 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
4349 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
4350 }
4351 }
4352 fclose(pFile);
4353 }
4354 else
4355 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
4356
4357 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
4358 return 0;
4359}
4360
4361
4362/**
4363 * The 'showvars' command.
4364 *
4365 * @returns VBox status.
4366 * @param pCmd Pointer to the command descriptor (as registered).
4367 * @param pCmdHlp Pointer to command helper functions.
4368 * @param pVM Pointer to the current VM (if any).
4369 * @param paArgs Pointer to (readonly) array of arguments.
4370 * @param cArgs Number of arguments in the array.
4371 */
4372static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4373{
4374 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4375
4376 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
4377 {
4378 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
4379 if (!rc)
4380 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
4381 if (rc)
4382 return rc;
4383 }
4384
4385 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
4386 return 0;
4387}
4388
4389
4390/**
4391 * The 'harakiri' command.
4392 *
4393 * @returns VBox status.
4394 * @param pCmd Pointer to the command descriptor (as registered).
4395 * @param pCmdHlp Pointer to command helper functions.
4396 * @param pVM Pointer to the current VM (if any).
4397 * @param paArgs Pointer to (readonly) array of arguments.
4398 * @param cArgs Number of arguments in the array.
4399 */
4400static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
4401{
4402 Log(("dbgcCmdHarakiri\n"));
4403 for (;;)
4404 exit(126);
4405 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
4406}
4407
4408
4409
4410
4411
4412//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
4413//
4414//
4415// B u l t i n S y m b o l s
4416//
4417//
4418//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
4419
4420
4421
4422/**
4423 * Get builtin register symbol.
4424 *
4425 * The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
4426 *
4427 * @returns 0 on success.
4428 * @returns VBox evaluation / parsing error code on failure.
4429 * The caller does the bitching.
4430 * @param pSymDesc Pointer to the symbol descriptor.
4431 * @param pCmdHlp Pointer to the command callback structure.
4432 * @param enmType The result type.
4433 * @param pResult Where to store the result.
4434 */
4435static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
4436{
4437 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
4438
4439 /*
4440 * pVM is required.
4441 */
4442 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4443 Assert(pDbgc->pVM);
4444
4445 /*
4446 * Get the right CPU context.
4447 */
4448 PCPUMCTX pCtx;
4449 int rc;
4450 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
4451 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4452 else
4453 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
4454 if (VBOX_FAILURE(rc))
4455 return rc;
4456
4457 /*
4458 * Get the value.
4459 */
4460 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
4461 uint64_t u64;
4462 switch (SYMREG_SIZE(pSymDesc->uUser))
4463 {
4464 case 1: u64 = *(uint8_t *)pvValue; break;
4465 case 2: u64 = *(uint16_t *)pvValue; break;
4466 case 4: u64 = *(uint32_t *)pvValue; break;
4467 case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
4468 case 8: u64 = *(uint64_t *)pvValue; break;
4469 default:
4470 return VERR_PARSE_NOT_IMPLEMENTED;
4471 }
4472
4473 /*
4474 * Construct the desired result.
4475 */
4476 if (enmType == DBGCVAR_TYPE_ANY)
4477 enmType = DBGCVAR_TYPE_NUMBER;
4478 pResult->pDesc = NULL;
4479 pResult->pNext = NULL;
4480 pResult->enmType = enmType;
4481 pResult->enmRangeType = DBGCVAR_RANGE_NONE;
4482 pResult->u64Range = 0;
4483
4484 switch (enmType)
4485 {
4486 case DBGCVAR_TYPE_GC_FLAT:
4487 pResult->u.GCFlat = (RTGCPTR)u64;
4488 break;
4489
4490 case DBGCVAR_TYPE_GC_FAR:
4491 switch (SYMREG_SIZE(pSymDesc->uUser))
4492 {
4493 case 4:
4494 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
4495 {
4496 pResult->u.GCFar.off = (uint16_t)u64;
4497 pResult->u.GCFar.sel = (uint16_t)(u64 >> 16);
4498 }
4499 else
4500 {
4501 pResult->u.GCFar.sel = (uint16_t)u64;
4502 pResult->u.GCFar.off = (uint16_t)(u64 >> 16);
4503 }
4504 break;
4505 case 6:
4506 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
4507 {
4508 pResult->u.GCFar.off = (uint32_t)u64;
4509 pResult->u.GCFar.sel = (uint16_t)(u64 >> 32);
4510 }
4511 else
4512 {
4513 pResult->u.GCFar.sel = (uint32_t)u64;
4514 pResult->u.GCFar.off = (uint16_t)(u64 >> 32);
4515 }
4516 break;
4517
4518 default:
4519 return VERR_PARSE_BAD_RESULT_TYPE;
4520 }
4521 break;
4522
4523 case DBGCVAR_TYPE_GC_PHYS:
4524 pResult->u.GCPhys = (RTGCPHYS)u64;
4525 break;
4526
4527 case DBGCVAR_TYPE_HC_FLAT:
4528 pResult->u.pvHCFlat = (void *)(uintptr_t)u64;
4529 break;
4530
4531 case DBGCVAR_TYPE_HC_FAR:
4532 switch (SYMREG_SIZE(pSymDesc->uUser))
4533 {
4534 case 4:
4535 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
4536 {
4537 pResult->u.HCFar.off = (uint16_t)u64;
4538 pResult->u.HCFar.sel = (uint16_t)(u64 >> 16);
4539 }
4540 else
4541 {
4542 pResult->u.HCFar.sel = (uint16_t)u64;
4543 pResult->u.HCFar.off = (uint16_t)(u64 >> 16);
4544 }
4545 break;
4546 case 6:
4547 if (!(pSymDesc->uUser & SYMREG_FLAGS_HIGH_SEL))
4548 {
4549 pResult->u.HCFar.off = (uint32_t)u64;
4550 pResult->u.HCFar.sel = (uint16_t)(u64 >> 32);
4551 }
4552 else
4553 {
4554 pResult->u.HCFar.sel = (uint32_t)u64;
4555 pResult->u.HCFar.off = (uint16_t)(u64 >> 32);
4556 }
4557 break;
4558
4559 default:
4560 return VERR_PARSE_BAD_RESULT_TYPE;
4561 }
4562 break;
4563
4564 case DBGCVAR_TYPE_HC_PHYS:
4565 pResult->u.GCPhys = (RTGCPHYS)u64;
4566 break;
4567
4568 case DBGCVAR_TYPE_NUMBER:
4569 pResult->u.u64Number = u64;
4570 break;
4571
4572 case DBGCVAR_TYPE_STRING:
4573 case DBGCVAR_TYPE_UNKNOWN:
4574 default:
4575 return VERR_PARSE_BAD_RESULT_TYPE;
4576
4577 }
4578
4579 return 0;
4580}
4581
4582
4583/**
4584 * Set builtin register symbol.
4585 *
4586 * The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
4587 *
4588 * @returns 0 on success.
4589 * @returns VBox evaluation / parsing error code on failure.
4590 * The caller does the bitching.
4591 * @param pSymDesc Pointer to the symbol descriptor.
4592 * @param pCmdHlp Pointer to the command callback structure.
4593 * @param pValue The value to assign the symbol.
4594 */
4595static DECLCALLBACK(int) dbgcSymSetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, PCDBGCVAR pValue)
4596{
4597 LogFlow(("dbgcSymSetReg: pSymDesc->pszName=%d\n", pSymDesc->pszName));
4598
4599 /*
4600 * pVM is required.
4601 */
4602 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
4603 Assert(pDbgc->pVM);
4604
4605 /*
4606 * Get the right CPU context.
4607 */
4608 PCPUMCTX pCtx;
4609 int rc;
4610 if (!(pSymDesc->uUser & SYMREG_FLAGS_HYPER))
4611 rc = CPUMQueryGuestCtxPtr(pDbgc->pVM, &pCtx);
4612 else
4613 rc = CPUMQueryHyperCtxPtr(pDbgc->pVM, &pCtx);
4614 if (VBOX_FAILURE(rc))
4615 return rc;
4616
4617 /*
4618 * Check the new value.
4619 */
4620 if (pValue->enmType != DBGCVAR_TYPE_NUMBER)
4621 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
4622
4623 /*
4624 * Set the value.
4625 */
4626 void *pvValue = (char *)pCtx + SYMREG_OFFSET(pSymDesc->uUser);
4627 switch (SYMREG_SIZE(pSymDesc->uUser))
4628 {
4629 case 1:
4630 *(uint8_t *)pvValue = (uint8_t)pValue->u.u64Number;
4631 break;
4632 case 2:
4633 *(uint16_t *)pvValue = (uint16_t)pValue->u.u64Number;
4634 break;
4635 case 4:
4636 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
4637 break;
4638 case 6:
4639 *(uint32_t *)pvValue = (uint32_t)pValue->u.u64Number;
4640 ((uint16_t *)pvValue)[3] = (uint16_t)(pValue->u.u64Number >> 32);
4641 break;
4642 case 8:
4643 *(uint64_t *)pvValue = pValue->u.u64Number;
4644 break;
4645 default:
4646 return VERR_PARSE_NOT_IMPLEMENTED;
4647 }
4648
4649 return VINF_SUCCESS;
4650}
4651
4652
4653
4654
4655
4656
4657
4658//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
4659//
4660//
4661// O p e r a t o r s
4662//
4663//
4664//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
4665
4666
4667/**
4668 * Minus (unary).
4669 *
4670 * @returns 0 on success.
4671 * @returns VBox evaluation / parsing error code on failure.
4672 * The caller does the bitching.
4673 * @param pDbgc Debugger console instance data.
4674 * @param pArg The argument.
4675 * @param pResult Where to store the result.
4676 */
4677static DECLCALLBACK(int) dbgcOpMinus(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4678{
4679// LogFlow(("dbgcOpMinus\n"));
4680 *pResult = *pArg;
4681 switch (pArg->enmType)
4682 {
4683 case DBGCVAR_TYPE_GC_FLAT:
4684 pResult->u.GCFlat = -(RTGCINTPTR)pResult->u.GCFlat;
4685 break;
4686 case DBGCVAR_TYPE_GC_FAR:
4687 pResult->u.GCFar.off = -(int32_t)pResult->u.GCFar.off;
4688 break;
4689 case DBGCVAR_TYPE_GC_PHYS:
4690 pResult->u.GCPhys = (RTGCPHYS) -(int64_t)pResult->u.GCPhys;
4691 break;
4692 case DBGCVAR_TYPE_HC_FLAT:
4693 pResult->u.pvHCFlat = (void *) -(intptr_t)pResult->u.pvHCFlat;
4694 break;
4695 case DBGCVAR_TYPE_HC_FAR:
4696 pResult->u.HCFar.off = -(int32_t)pResult->u.HCFar.off;
4697 break;
4698 case DBGCVAR_TYPE_HC_PHYS:
4699 pResult->u.HCPhys = (RTHCPHYS) -(int64_t)pResult->u.HCPhys;
4700 break;
4701 case DBGCVAR_TYPE_NUMBER:
4702 pResult->u.u64Number = -(int64_t)pResult->u.u64Number;
4703 break;
4704
4705 case DBGCVAR_TYPE_UNKNOWN:
4706 case DBGCVAR_TYPE_STRING:
4707 default:
4708 return VERR_PARSE_INCORRECT_ARG_TYPE;
4709 }
4710 NOREF(pDbgc);
4711 return 0;
4712}
4713
4714
4715/**
4716 * Pluss (unary).
4717 *
4718 * @returns 0 on success.
4719 * @returns VBox evaluation / parsing error code on failure.
4720 * The caller does the bitching.
4721 * @param pDbgc Debugger console instance data.
4722 * @param pArg The argument.
4723 * @param pResult Where to store the result.
4724 */
4725static DECLCALLBACK(int) dbgcOpPluss(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4726{
4727// LogFlow(("dbgcOpPluss\n"));
4728 *pResult = *pArg;
4729 switch (pArg->enmType)
4730 {
4731 case DBGCVAR_TYPE_GC_FLAT:
4732 case DBGCVAR_TYPE_GC_FAR:
4733 case DBGCVAR_TYPE_GC_PHYS:
4734 case DBGCVAR_TYPE_HC_FLAT:
4735 case DBGCVAR_TYPE_HC_FAR:
4736 case DBGCVAR_TYPE_HC_PHYS:
4737 case DBGCVAR_TYPE_NUMBER:
4738 break;
4739
4740 case DBGCVAR_TYPE_UNKNOWN:
4741 case DBGCVAR_TYPE_STRING:
4742 default:
4743 return VERR_PARSE_INCORRECT_ARG_TYPE;
4744 }
4745 NOREF(pDbgc);
4746 return 0;
4747}
4748
4749
4750/**
4751 * Boolean not (unary).
4752 *
4753 * @returns 0 on success.
4754 * @returns VBox evaluation / parsing error code on failure.
4755 * The caller does the bitching.
4756 * @param pDbgc Debugger console instance data.
4757 * @param pArg The argument.
4758 * @param pResult Where to store the result.
4759 */
4760static DECLCALLBACK(int) dbgcOpBooleanNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4761{
4762// LogFlow(("dbgcOpBooleanNot\n"));
4763 *pResult = *pArg;
4764 switch (pArg->enmType)
4765 {
4766 case DBGCVAR_TYPE_GC_FLAT:
4767 pResult->u.u64Number = !pResult->u.GCFlat;
4768 break;
4769 case DBGCVAR_TYPE_GC_FAR:
4770 pResult->u.u64Number = !pResult->u.GCFar.off && pResult->u.GCFar.sel <= 3;
4771 break;
4772 case DBGCVAR_TYPE_GC_PHYS:
4773 pResult->u.u64Number = !pResult->u.GCPhys;
4774 break;
4775 case DBGCVAR_TYPE_HC_FLAT:
4776 pResult->u.u64Number = !pResult->u.pvHCFlat;
4777 break;
4778 case DBGCVAR_TYPE_HC_FAR:
4779 pResult->u.u64Number = !pResult->u.HCFar.off && pResult->u.HCFar.sel <= 3;
4780 break;
4781 case DBGCVAR_TYPE_HC_PHYS:
4782 pResult->u.u64Number = !pResult->u.HCPhys;
4783 break;
4784 case DBGCVAR_TYPE_NUMBER:
4785 pResult->u.u64Number = !pResult->u.u64Number;
4786 break;
4787 case DBGCVAR_TYPE_STRING:
4788 pResult->u.u64Number = !pResult->u64Range;
4789 break;
4790
4791 case DBGCVAR_TYPE_UNKNOWN:
4792 default:
4793 return VERR_PARSE_INCORRECT_ARG_TYPE;
4794 }
4795 pResult->enmType = DBGCVAR_TYPE_NUMBER;
4796 NOREF(pDbgc);
4797 return 0;
4798}
4799
4800
4801/**
4802 * Bitwise not (unary).
4803 *
4804 * @returns 0 on success.
4805 * @returns VBox evaluation / parsing error code on failure.
4806 * The caller does the bitching.
4807 * @param pDbgc Debugger console instance data.
4808 * @param pArg The argument.
4809 * @param pResult Where to store the result.
4810 */
4811static DECLCALLBACK(int) dbgcOpBitwiseNot(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4812{
4813// LogFlow(("dbgcOpBitwiseNot\n"));
4814 *pResult = *pArg;
4815 switch (pArg->enmType)
4816 {
4817 case DBGCVAR_TYPE_GC_FLAT:
4818 pResult->u.GCFlat = ~pResult->u.GCFlat;
4819 break;
4820 case DBGCVAR_TYPE_GC_FAR:
4821 pResult->u.GCFar.off = ~pResult->u.GCFar.off;
4822 break;
4823 case DBGCVAR_TYPE_GC_PHYS:
4824 pResult->u.GCPhys = ~pResult->u.GCPhys;
4825 break;
4826 case DBGCVAR_TYPE_HC_FLAT:
4827 pResult->u.pvHCFlat = (void *)~(uintptr_t)pResult->u.pvHCFlat;
4828 break;
4829 case DBGCVAR_TYPE_HC_FAR:
4830 pResult->u.HCFar.off= ~pResult->u.HCFar.off;
4831 break;
4832 case DBGCVAR_TYPE_HC_PHYS:
4833 pResult->u.HCPhys = ~pResult->u.HCPhys;
4834 break;
4835 case DBGCVAR_TYPE_NUMBER:
4836 pResult->u.u64Number = ~pResult->u.u64Number;
4837 break;
4838
4839 case DBGCVAR_TYPE_UNKNOWN:
4840 case DBGCVAR_TYPE_STRING:
4841 default:
4842 return VERR_PARSE_INCORRECT_ARG_TYPE;
4843 }
4844 NOREF(pDbgc);
4845 return 0;
4846}
4847
4848
4849/**
4850 * Reference variable (unary).
4851 *
4852 * @returns 0 on success.
4853 * @returns VBox evaluation / parsing error code on failure.
4854 * The caller does the bitching.
4855 * @param pDbgc Debugger console instance data.
4856 * @param pArg The argument.
4857 * @param pResult Where to store the result.
4858 */
4859static DECLCALLBACK(int) dbgcOpVar(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4860{
4861// LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));
4862 /*
4863 * Parse sanity.
4864 */
4865 if (pArg->enmType != DBGCVAR_TYPE_STRING)
4866 return VERR_PARSE_INCORRECT_ARG_TYPE;
4867
4868 /*
4869 * Lookup the variable.
4870 */
4871 const char *pszVar = pArg->u.pszString;
4872 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
4873 {
4874 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
4875 {
4876 *pResult = pDbgc->papVars[iVar]->Var;
4877 return 0;
4878 }
4879 }
4880
4881 return VERR_PARSE_VARIABLE_NOT_FOUND;
4882}
4883
4884
4885/**
4886 * Flat address (unary).
4887 *
4888 * @returns VINF_SUCCESS on success.
4889 * @returns VBox evaluation / parsing error code on failure.
4890 * The caller does the bitching.
4891 * @param pDbgc Debugger console instance data.
4892 * @param pArg The argument.
4893 * @param pResult Where to store the result.
4894 */
4895static DECLCALLBACK(int) dbgcOpAddrFlat(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4896{
4897// LogFlow(("dbgcOpAddrFlat\n"));
4898 int rc;
4899 *pResult = *pArg;
4900
4901 switch (pArg->enmType)
4902 {
4903 case DBGCVAR_TYPE_GC_FLAT:
4904 return VINF_SUCCESS;
4905
4906 case DBGCVAR_TYPE_GC_FAR:
4907 {
4908 Assert(pDbgc->pVM);
4909 DBGFADDRESS Address;
4910 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
4911 if (VBOX_SUCCESS(rc))
4912 {
4913 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
4914 pResult->u.GCFlat = Address.FlatPtr;
4915 return VINF_SUCCESS;
4916 }
4917 return VERR_PARSE_CONVERSION_FAILED;
4918 }
4919
4920 case DBGCVAR_TYPE_GC_PHYS:
4921 //rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
4922 return VERR_PARSE_INCORRECT_ARG_TYPE;
4923
4924 case DBGCVAR_TYPE_HC_FLAT:
4925 return VINF_SUCCESS;
4926
4927 case DBGCVAR_TYPE_HC_FAR:
4928 return VERR_PARSE_INCORRECT_ARG_TYPE;
4929
4930 case DBGCVAR_TYPE_HC_PHYS:
4931 Assert(pDbgc->pVM);
4932 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
4933 rc = MMR3HCPhys2HCVirt(pDbgc->pVM, pResult->u.HCPhys, &pResult->u.pvHCFlat);
4934 if (VBOX_SUCCESS(rc))
4935 return VINF_SUCCESS;
4936 return VERR_PARSE_CONVERSION_FAILED;
4937
4938 case DBGCVAR_TYPE_NUMBER:
4939 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
4940 pResult->u.GCFlat = (RTGCPTR)pResult->u.u64Number;
4941 return VINF_SUCCESS;
4942
4943 case DBGCVAR_TYPE_STRING:
4944 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_FLAT, pResult);
4945
4946 case DBGCVAR_TYPE_UNKNOWN:
4947 default:
4948 return VERR_PARSE_INCORRECT_ARG_TYPE;
4949 }
4950}
4951
4952
4953/**
4954 * Physical address (unary).
4955 *
4956 * @returns 0 on success.
4957 * @returns VBox evaluation / parsing error code on failure.
4958 * The caller does the bitching.
4959 * @param pDbgc Debugger console instance data.
4960 * @param pArg The argument.
4961 * @param pResult Where to store the result.
4962 */
4963static DECLCALLBACK(int) dbgcOpAddrPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
4964{
4965// LogFlow(("dbgcOpAddrPhys\n"));
4966 int rc;
4967
4968 *pResult = *pArg;
4969 switch (pArg->enmType)
4970 {
4971 case DBGCVAR_TYPE_GC_FLAT:
4972 Assert(pDbgc->pVM);
4973 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4974 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.GCPhys);
4975 if (VBOX_SUCCESS(rc))
4976 return 0;
4977 /** @todo more memory types! */
4978 return VERR_PARSE_CONVERSION_FAILED;
4979
4980 case DBGCVAR_TYPE_GC_FAR:
4981 {
4982 Assert(pDbgc->pVM);
4983 DBGFADDRESS Address;
4984 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
4985 if (VBOX_SUCCESS(rc))
4986 {
4987 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
4988 rc = PGMPhysGCPtr2GCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.GCPhys);
4989 if (VBOX_SUCCESS(rc))
4990 return 0;
4991 /** @todo more memory types! */
4992 }
4993 return VERR_PARSE_CONVERSION_FAILED;
4994 }
4995
4996 case DBGCVAR_TYPE_GC_PHYS:
4997 return 0;
4998
4999 case DBGCVAR_TYPE_HC_FLAT:
5000 Assert(pDbgc->pVM);
5001 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
5002 rc = PGMPhysHCPtr2GCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.GCPhys);
5003 if (VBOX_SUCCESS(rc))
5004 return 0;
5005 /** @todo more memory types! */
5006 return VERR_PARSE_CONVERSION_FAILED;
5007
5008 case DBGCVAR_TYPE_HC_FAR:
5009 return VERR_PARSE_INCORRECT_ARG_TYPE;
5010
5011 case DBGCVAR_TYPE_HC_PHYS:
5012 return 0;
5013
5014 case DBGCVAR_TYPE_NUMBER:
5015 pResult->enmType = DBGCVAR_TYPE_GC_PHYS;
5016 pResult->u.GCPhys = (RTGCPHYS)pResult->u.u64Number;
5017 return 0;
5018
5019 case DBGCVAR_TYPE_STRING:
5020 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_GC_PHYS, pResult);
5021
5022 case DBGCVAR_TYPE_UNKNOWN:
5023 default:
5024 return VERR_PARSE_INCORRECT_ARG_TYPE;
5025 }
5026 return 0;
5027}
5028
5029
5030/**
5031 * Physical host address (unary).
5032 *
5033 * @returns 0 on success.
5034 * @returns VBox evaluation / parsing error code on failure.
5035 * The caller does the bitching.
5036 * @param pDbgc Debugger console instance data.
5037 * @param pArg The argument.
5038 * @param pResult Where to store the result.
5039 */
5040static DECLCALLBACK(int) dbgcOpAddrHostPhys(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
5041{
5042// LogFlow(("dbgcOpAddrPhys\n"));
5043 int rc;
5044
5045 *pResult = *pArg;
5046 switch (pArg->enmType)
5047 {
5048 case DBGCVAR_TYPE_GC_FLAT:
5049 Assert(pDbgc->pVM);
5050 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
5051 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
5052 if (VBOX_SUCCESS(rc))
5053 return 0;
5054 /** @todo more memory types. */
5055 return VERR_PARSE_CONVERSION_FAILED;
5056
5057 case DBGCVAR_TYPE_GC_FAR:
5058 {
5059 Assert(pDbgc->pVM);
5060 DBGFADDRESS Address;
5061 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
5062 if (VBOX_SUCCESS(rc))
5063 {
5064 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
5065 rc = PGMPhysGCPtr2HCPhys(pDbgc->pVM, Address.FlatPtr, &pResult->u.HCPhys);
5066 if (VBOX_SUCCESS(rc))
5067 return 0;
5068 /** @todo more memory types. */
5069 }
5070 return VERR_PARSE_CONVERSION_FAILED;
5071 }
5072
5073 case DBGCVAR_TYPE_GC_PHYS:
5074 Assert(pDbgc->pVM);
5075 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
5076 rc = PGMPhysGCPhys2HCPhys(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.HCPhys);
5077 if (VBOX_SUCCESS(rc))
5078 return 0;
5079 return VERR_PARSE_CONVERSION_FAILED;
5080
5081 case DBGCVAR_TYPE_HC_FLAT:
5082 Assert(pDbgc->pVM);
5083 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
5084 rc = PGMPhysHCPtr2HCPhys(pDbgc->pVM, pArg->u.pvHCFlat, &pResult->u.HCPhys);
5085 if (VBOX_SUCCESS(rc))
5086 return 0;
5087 /** @todo more memory types! */
5088 return VERR_PARSE_CONVERSION_FAILED;
5089
5090 case DBGCVAR_TYPE_HC_FAR:
5091 return VERR_PARSE_INCORRECT_ARG_TYPE;
5092
5093 case DBGCVAR_TYPE_HC_PHYS:
5094 return 0;
5095
5096 case DBGCVAR_TYPE_NUMBER:
5097 pResult->enmType = DBGCVAR_TYPE_HC_PHYS;
5098 pResult->u.HCPhys = (RTGCPHYS)pResult->u.u64Number;
5099 return 0;
5100
5101 case DBGCVAR_TYPE_STRING:
5102 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_PHYS, pResult);
5103
5104 case DBGCVAR_TYPE_UNKNOWN:
5105 default:
5106 return VERR_PARSE_INCORRECT_ARG_TYPE;
5107 }
5108 return 0;
5109}
5110
5111
5112/**
5113 * Host address (unary).
5114 *
5115 * @returns 0 on success.
5116 * @returns VBox evaluation / parsing error code on failure.
5117 * The caller does the bitching.
5118 * @param pDbgc Debugger console instance data.
5119 * @param pArg The argument.
5120 * @param pResult Where to store the result.
5121 */
5122static DECLCALLBACK(int) dbgcOpAddrHost(PDBGC pDbgc, PCDBGCVAR pArg, PDBGCVAR pResult)
5123{
5124// LogFlow(("dbgcOpAddrHost\n"));
5125 int rc;
5126
5127 *pResult = *pArg;
5128 switch (pArg->enmType)
5129 {
5130 case DBGCVAR_TYPE_GC_FLAT:
5131 Assert(pDbgc->pVM);
5132 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
5133 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, pArg->u.GCFlat, &pResult->u.pvHCFlat);
5134 if (VBOX_SUCCESS(rc))
5135 return 0;
5136 /** @todo more memory types. */
5137 return VERR_PARSE_CONVERSION_FAILED;
5138
5139 case DBGCVAR_TYPE_GC_FAR:
5140 {
5141 Assert(pDbgc->pVM);
5142 DBGFADDRESS Address;
5143 rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
5144 if (VBOX_SUCCESS(rc))
5145 {
5146 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
5147 rc = PGMPhysGCPtr2HCPtr(pDbgc->pVM, Address.FlatPtr, &pResult->u.pvHCFlat);
5148 if (VBOX_SUCCESS(rc))
5149 return 0;
5150 /** @todo more memory types. */
5151 }
5152 return VERR_PARSE_CONVERSION_FAILED;
5153 }
5154
5155 case DBGCVAR_TYPE_GC_PHYS:
5156 Assert(pDbgc->pVM);
5157 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
5158 rc = PGMPhysGCPhys2HCPtr(pDbgc->pVM, pArg->u.GCPhys, 1, &pResult->u.pvHCFlat);
5159 if (VBOX_SUCCESS(rc))
5160 return 0;
5161 return VERR_PARSE_CONVERSION_FAILED;
5162
5163 case DBGCVAR_TYPE_HC_FLAT:
5164 return 0;
5165
5166 case DBGCVAR_TYPE_HC_FAR:
5167 case DBGCVAR_TYPE_HC_PHYS:
5168 /** @todo !*/
5169 return VERR_PARSE_CONVERSION_FAILED;
5170
5171 case DBGCVAR_TYPE_NUMBER:
5172 pResult->enmType = DBGCVAR_TYPE_HC_FLAT;
5173 pResult->u.pvHCFlat = (void *)(uintptr_t)pResult->u.u64Number;
5174 return 0;
5175
5176 case DBGCVAR_TYPE_STRING:
5177 return dbgcSymbolGet(pDbgc, pArg->u.pszString, DBGCVAR_TYPE_HC_FLAT, pResult);
5178
5179 case DBGCVAR_TYPE_UNKNOWN:
5180 default:
5181 return VERR_PARSE_INCORRECT_ARG_TYPE;
5182 }
5183}
5184
5185/**
5186 * Bitwise not (unary).
5187 *
5188 * @returns 0 on success.
5189 * @returns VBox evaluation / parsing error code on failure.
5190 * The caller does the bitching.
5191 * @param pDbgc Debugger console instance data.
5192 * @param pArg The argument.
5193 * @param pResult Where to store the result.
5194 */
5195static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5196{
5197// LogFlow(("dbgcOpAddrFar\n"));
5198 int rc;
5199
5200 switch (pArg1->enmType)
5201 {
5202 case DBGCVAR_TYPE_STRING:
5203 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
5204 if (VBOX_FAILURE(rc))
5205 return rc;
5206 break;
5207 case DBGCVAR_TYPE_NUMBER:
5208 *pResult = *pArg1;
5209 break;
5210
5211 case DBGCVAR_TYPE_GC_FLAT:
5212 case DBGCVAR_TYPE_GC_FAR:
5213 case DBGCVAR_TYPE_GC_PHYS:
5214 case DBGCVAR_TYPE_HC_FLAT:
5215 case DBGCVAR_TYPE_HC_FAR:
5216 case DBGCVAR_TYPE_HC_PHYS:
5217 case DBGCVAR_TYPE_UNKNOWN:
5218 default:
5219 return VERR_PARSE_INCORRECT_ARG_TYPE;
5220 }
5221 pResult->u.GCFar.sel = (RTSEL)pResult->u.u64Number;
5222
5223 /* common code for the two types we support. */
5224 switch (pArg2->enmType)
5225 {
5226 case DBGCVAR_TYPE_GC_FLAT:
5227 pResult->u.GCFar.off = pArg2->u.GCFlat;
5228 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
5229 break;
5230
5231 case DBGCVAR_TYPE_HC_FLAT:
5232 pResult->u.HCFar.off = pArg2->u.GCFlat;
5233 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
5234 break;
5235
5236 case DBGCVAR_TYPE_NUMBER:
5237 pResult->u.GCFar.off = (RTGCPTR)pArg2->u.u64Number;
5238 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
5239 break;
5240
5241 case DBGCVAR_TYPE_STRING:
5242 {
5243 DBGCVAR Var;
5244 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
5245 if (VBOX_FAILURE(rc))
5246 return rc;
5247 pResult->u.GCFar.off = (RTGCPTR)Var.u.u64Number;
5248 pResult->enmType = DBGCVAR_TYPE_GC_FAR;
5249 break;
5250 }
5251
5252 case DBGCVAR_TYPE_GC_FAR:
5253 case DBGCVAR_TYPE_GC_PHYS:
5254 case DBGCVAR_TYPE_HC_FAR:
5255 case DBGCVAR_TYPE_HC_PHYS:
5256 case DBGCVAR_TYPE_UNKNOWN:
5257 default:
5258 return VERR_PARSE_INCORRECT_ARG_TYPE;
5259 }
5260 return 0;
5261
5262}
5263
5264
5265/**
5266 * Multiplication operator (binary).
5267 *
5268 * @returns 0 on success.
5269 * @returns VBox evaluation / parsing error code on failure.
5270 * The caller does the bitching.
5271 * @param pDbgc Debugger console instance data.
5272 * @param pArg1 The first argument.
5273 * @param pArg2 The 2nd argument.
5274 * @param pResult Where to store the result.
5275 */
5276static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5277{
5278// LogFlow(("dbgcOpMult\n"));
5279 int rc;
5280
5281 /*
5282 * Switch the factors so we preserve pointers, far pointers are considered more
5283 * important that physical and flat pointers.
5284 */
5285 if ( DBGCVAR_ISPOINTER(pArg2->enmType)
5286 && ( !DBGCVAR_ISPOINTER(pArg1->enmType)
5287 || ( DBGCVAR_IS_FAR_PTR(pArg2->enmType)
5288 && !DBGCVAR_IS_FAR_PTR(pArg1->enmType))))
5289 {
5290 PCDBGCVAR pTmp = pArg1;
5291 pArg2 = pArg1;
5292 pArg1 = pTmp;
5293 }
5294
5295 /*
5296 * Convert the 2nd number into a number we use multiply the first with.
5297 */
5298 DBGCVAR Factor2 = *pArg2;
5299 if ( Factor2.enmType == DBGCVAR_TYPE_STRING
5300 || Factor2.enmType == DBGCVAR_TYPE_SYMBOL)
5301 {
5302 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Factor2);
5303 if (VBOX_FAILURE(rc))
5304 return rc;
5305 }
5306 uint64_t u64Factor;
5307 switch (Factor2.enmType)
5308 {
5309 case DBGCVAR_TYPE_GC_FLAT: u64Factor = Factor2.u.GCFlat; break;
5310 case DBGCVAR_TYPE_GC_FAR: u64Factor = Factor2.u.GCFar.off; break;
5311 case DBGCVAR_TYPE_GC_PHYS: u64Factor = Factor2.u.GCPhys; break;
5312 case DBGCVAR_TYPE_HC_FLAT: u64Factor = (uintptr_t)Factor2.u.pvHCFlat; break;
5313 case DBGCVAR_TYPE_HC_FAR: u64Factor = Factor2.u.HCFar.off; break;
5314 case DBGCVAR_TYPE_HC_PHYS: u64Factor = Factor2.u.HCPhys; break;
5315 case DBGCVAR_TYPE_NUMBER: u64Factor = Factor2.u.u64Number; break;
5316 default:
5317 return VERR_PARSE_INCORRECT_ARG_TYPE;
5318 }
5319
5320 /*
5321 * Fix symbols in the 1st factor.
5322 */
5323 *pResult = *pArg1;
5324 if ( pResult->enmType == DBGCVAR_TYPE_STRING
5325 || pResult->enmType == DBGCVAR_TYPE_SYMBOL)
5326 {
5327 rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
5328 if (VBOX_FAILURE(rc))
5329 return rc;
5330 }
5331
5332 /*
5333 * Do the multiplication.
5334 */
5335 switch (pArg1->enmType)
5336 {
5337 case DBGCVAR_TYPE_GC_FLAT: pResult->u.GCFlat *= u64Factor; break;
5338 case DBGCVAR_TYPE_GC_FAR: pResult->u.GCFar.off *= u64Factor; break;
5339 case DBGCVAR_TYPE_GC_PHYS: pResult->u.GCPhys *= u64Factor; break;
5340 case DBGCVAR_TYPE_HC_FLAT:
5341 pResult->u.pvHCFlat = (void *)(uintptr_t)((uintptr_t)pResult->u.pvHCFlat * u64Factor);
5342 break;
5343 case DBGCVAR_TYPE_HC_FAR: pResult->u.HCFar.off *= u64Factor; break;
5344 case DBGCVAR_TYPE_HC_PHYS: pResult->u.HCPhys *= u64Factor; break;
5345 case DBGCVAR_TYPE_NUMBER: pResult->u.u64Number *= u64Factor; break;
5346 default:
5347 return VERR_PARSE_INCORRECT_ARG_TYPE;
5348 }
5349 return 0;
5350}
5351
5352
5353/**
5354 * Division operator (binary).
5355 *
5356 * @returns 0 on success.
5357 * @returns VBox evaluation / parsing error code on failure.
5358 * The caller does the bitching.
5359 * @param pDbgc Debugger console instance data.
5360 * @param pArg1 The first argument.
5361 * @param pArg2 The 2nd argument.
5362 * @param pResult Where to store the result.
5363 */
5364static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5365{
5366 LogFlow(("dbgcOpDiv\n"));
5367 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5368 return -1;
5369}
5370
5371
5372/**
5373 * Modulus operator (binary).
5374 *
5375 * @returns 0 on success.
5376 * @returns VBox evaluation / parsing error code on failure.
5377 * The caller does the bitching.
5378 * @param pDbgc Debugger console instance data.
5379 * @param pArg1 The first argument.
5380 * @param pArg2 The 2nd argument.
5381 * @param pResult Where to store the result.
5382 */
5383static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5384{
5385 LogFlow(("dbgcOpMod\n"));
5386 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5387 return -1;
5388}
5389
5390
5391/**
5392 * Addition operator (binary).
5393 *
5394 * @returns 0 on success.
5395 * @returns VBox evaluation / parsing error code on failure.
5396 * The caller does the bitching.
5397 * @param pDbgc Debugger console instance data.
5398 * @param pArg1 The first argument.
5399 * @param pArg2 The 2nd argument.
5400 * @param pResult Where to store the result.
5401 */
5402static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5403{
5404// LogFlow(("dbgcOpAdd\n"));
5405
5406 /*
5407 * An addition operation will return (when possible) the left side type in the
5408 * expression. We make an omission for numbers, where we'll take the right side
5409 * type instead. An expression where only the left hand side is a string we'll
5410 * use the right hand type assuming that the string is a symbol.
5411 */
5412 if ( (pArg1->enmType == DBGCVAR_TYPE_NUMBER && pArg2->enmType != DBGCVAR_TYPE_STRING)
5413 || (pArg1->enmType == DBGCVAR_TYPE_STRING && pArg2->enmType != DBGCVAR_TYPE_STRING))
5414 {
5415 PCDBGCVAR pTmp = pArg2;
5416 pArg2 = pArg1;
5417 pArg1 = pTmp;
5418 }
5419 DBGCVAR Sym1, Sym2;
5420 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
5421 {
5422 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
5423 if (VBOX_FAILURE(rc))
5424 return rc;
5425 pArg1 = &Sym1;
5426
5427 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
5428 if (VBOX_FAILURE(rc))
5429 return rc;
5430 pArg2 = &Sym2;
5431 }
5432
5433 int rc;
5434 DBGCVAR Var;
5435 DBGCVAR Var2;
5436 switch (pArg1->enmType)
5437 {
5438 /*
5439 * GC Flat
5440 */
5441 case DBGCVAR_TYPE_GC_FLAT:
5442 switch (pArg2->enmType)
5443 {
5444 case DBGCVAR_TYPE_HC_FLAT:
5445 case DBGCVAR_TYPE_HC_FAR:
5446 case DBGCVAR_TYPE_HC_PHYS:
5447 return VERR_PARSE_INVALID_OPERATION;
5448 default:
5449 *pResult = *pArg1;
5450 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5451 if (VBOX_FAILURE(rc))
5452 return rc;
5453 pResult->u.GCFlat += pArg2->u.GCFlat;
5454 break;
5455 }
5456 break;
5457
5458 /*
5459 * GC Far
5460 */
5461 case DBGCVAR_TYPE_GC_FAR:
5462 switch (pArg2->enmType)
5463 {
5464 case DBGCVAR_TYPE_HC_FLAT:
5465 case DBGCVAR_TYPE_HC_FAR:
5466 case DBGCVAR_TYPE_HC_PHYS:
5467 return VERR_PARSE_INVALID_OPERATION;
5468 case DBGCVAR_TYPE_NUMBER:
5469 *pResult = *pArg1;
5470 pResult->u.GCFar.off += (RTGCPTR)pArg2->u.u64Number;
5471 break;
5472 default:
5473 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5474 if (VBOX_FAILURE(rc))
5475 return rc;
5476 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5477 if (VBOX_FAILURE(rc))
5478 return rc;
5479 pResult->u.GCFlat += pArg2->u.GCFlat;
5480 break;
5481 }
5482 break;
5483
5484 /*
5485 * GC Phys
5486 */
5487 case DBGCVAR_TYPE_GC_PHYS:
5488 switch (pArg2->enmType)
5489 {
5490 case DBGCVAR_TYPE_HC_FLAT:
5491 case DBGCVAR_TYPE_HC_FAR:
5492 case DBGCVAR_TYPE_HC_PHYS:
5493 return VERR_PARSE_INVALID_OPERATION;
5494 default:
5495 *pResult = *pArg1;
5496 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
5497 if (VBOX_FAILURE(rc))
5498 return rc;
5499 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
5500 return VERR_PARSE_INVALID_OPERATION;
5501 pResult->u.GCPhys += Var.u.GCPhys;
5502 break;
5503 }
5504 break;
5505
5506 /*
5507 * HC Flat
5508 */
5509 case DBGCVAR_TYPE_HC_FLAT:
5510 *pResult = *pArg1;
5511 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5512 if (VBOX_FAILURE(rc))
5513 return rc;
5514 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5515 if (VBOX_FAILURE(rc))
5516 return rc;
5517 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
5518 break;
5519
5520 /*
5521 * HC Far
5522 */
5523 case DBGCVAR_TYPE_HC_FAR:
5524 switch (pArg2->enmType)
5525 {
5526 case DBGCVAR_TYPE_NUMBER:
5527 *pResult = *pArg1;
5528 pResult->u.HCFar.off += (uintptr_t)pArg2->u.u64Number;
5529 break;
5530
5531 default:
5532 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5533 if (VBOX_FAILURE(rc))
5534 return rc;
5535 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5536 if (VBOX_FAILURE(rc))
5537 return rc;
5538 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5539 if (VBOX_FAILURE(rc))
5540 return rc;
5541 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat + (uintptr_t)Var.u.pvHCFlat;
5542 break;
5543 }
5544 break;
5545
5546 /*
5547 * HC Phys
5548 */
5549 case DBGCVAR_TYPE_HC_PHYS:
5550 *pResult = *pArg1;
5551 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
5552 if (VBOX_FAILURE(rc))
5553 return rc;
5554 pResult->u.HCPhys += Var.u.HCPhys;
5555 break;
5556
5557 /*
5558 * Numbers (see start of function)
5559 */
5560 case DBGCVAR_TYPE_NUMBER:
5561 *pResult = *pArg1;
5562 switch (pArg2->enmType)
5563 {
5564 case DBGCVAR_TYPE_SYMBOL:
5565 case DBGCVAR_TYPE_STRING:
5566 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
5567 if (VBOX_FAILURE(rc))
5568 return rc;
5569 case DBGCVAR_TYPE_NUMBER:
5570 pResult->u.u64Number += pArg2->u.u64Number;
5571 break;
5572 default:
5573 return VERR_PARSE_INVALID_OPERATION;
5574 }
5575 break;
5576
5577 default:
5578 return VERR_PARSE_INVALID_OPERATION;
5579
5580 }
5581 return 0;
5582}
5583
5584
5585/**
5586 * Subtration 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) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5597{
5598// LogFlow(("dbgcOpSub\n"));
5599
5600 /*
5601 * An subtraction operation will return the left side type in the expression.
5602 * However, if the left hand side is a number and the right hand a pointer of
5603 * some kind we'll convert the left hand side to the same type as the right hand.
5604 * Any strings will be attempted resolved as symbols.
5605 */
5606 DBGCVAR Sym1, Sym2;
5607 if ( pArg2->enmType == DBGCVAR_TYPE_STRING
5608 && ( pArg1->enmType == DBGCVAR_TYPE_NUMBER
5609 || pArg1->enmType == DBGCVAR_TYPE_STRING))
5610 {
5611 int rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_ANY, &Sym2);
5612 if (VBOX_FAILURE(rc))
5613 return rc;
5614 pArg2 = &Sym2;
5615 }
5616
5617 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
5618 {
5619 DBGCVARTYPE enmType;
5620 switch (pArg2->enmType)
5621 {
5622 case DBGCVAR_TYPE_NUMBER:
5623 enmType = DBGCVAR_TYPE_ANY;
5624 break;
5625 case DBGCVAR_TYPE_GC_FLAT:
5626 case DBGCVAR_TYPE_GC_PHYS:
5627 case DBGCVAR_TYPE_HC_FLAT:
5628 case DBGCVAR_TYPE_HC_PHYS:
5629 enmType = pArg2->enmType;
5630 break;
5631 case DBGCVAR_TYPE_GC_FAR:
5632 enmType = DBGCVAR_TYPE_GC_FLAT;
5633 break;
5634 case DBGCVAR_TYPE_HC_FAR:
5635 enmType = DBGCVAR_TYPE_HC_FLAT;
5636 break;
5637
5638 default:
5639 case DBGCVAR_TYPE_STRING:
5640 AssertMsgFailed(("Can't happen\n"));
5641 enmType = DBGCVAR_TYPE_STRING;
5642 break;
5643 }
5644 if (enmType != DBGCVAR_TYPE_STRING)
5645 {
5646 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, &Sym1);
5647 if (VBOX_FAILURE(rc))
5648 return rc;
5649 pArg1 = &Sym1;
5650 }
5651 }
5652 else if (pArg1->enmType == DBGCVAR_TYPE_NUMBER)
5653 {
5654 PFNDBGCOPUNARY pOp = NULL;
5655 switch (pArg2->enmType)
5656 {
5657 case DBGCVAR_TYPE_GC_FAR:
5658 case DBGCVAR_TYPE_GC_FLAT:
5659 pOp = dbgcOpAddrFlat;
5660 break;
5661 case DBGCVAR_TYPE_GC_PHYS:
5662 pOp = dbgcOpAddrPhys;
5663 break;
5664 case DBGCVAR_TYPE_HC_FAR:
5665 case DBGCVAR_TYPE_HC_FLAT:
5666 pOp = dbgcOpAddrHost;
5667 break;
5668 case DBGCVAR_TYPE_HC_PHYS:
5669 pOp = dbgcOpAddrHostPhys;
5670 break;
5671 case DBGCVAR_TYPE_NUMBER:
5672 break;
5673 default:
5674 case DBGCVAR_TYPE_STRING:
5675 AssertMsgFailed(("Can't happen\n"));
5676 break;
5677 }
5678 if (pOp)
5679 {
5680 int rc = pOp(pDbgc, pArg1, &Sym1);
5681 if (VBOX_FAILURE(rc))
5682 return rc;
5683 pArg1 = &Sym1;
5684 }
5685 }
5686
5687
5688 /*
5689 * Normal processing.
5690 */
5691 int rc;
5692 DBGCVAR Var;
5693 DBGCVAR Var2;
5694 switch (pArg1->enmType)
5695 {
5696 /*
5697 * GC Flat
5698 */
5699 case DBGCVAR_TYPE_GC_FLAT:
5700 switch (pArg2->enmType)
5701 {
5702 case DBGCVAR_TYPE_HC_FLAT:
5703 case DBGCVAR_TYPE_HC_FAR:
5704 case DBGCVAR_TYPE_HC_PHYS:
5705 return VERR_PARSE_INVALID_OPERATION;
5706 default:
5707 *pResult = *pArg1;
5708 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5709 if (VBOX_FAILURE(rc))
5710 return rc;
5711 pResult->u.GCFlat -= pArg2->u.GCFlat;
5712 break;
5713 }
5714 break;
5715
5716 /*
5717 * GC Far
5718 */
5719 case DBGCVAR_TYPE_GC_FAR:
5720 switch (pArg2->enmType)
5721 {
5722 case DBGCVAR_TYPE_HC_FLAT:
5723 case DBGCVAR_TYPE_HC_FAR:
5724 case DBGCVAR_TYPE_HC_PHYS:
5725 return VERR_PARSE_INVALID_OPERATION;
5726 case DBGCVAR_TYPE_NUMBER:
5727 *pResult = *pArg1;
5728 pResult->u.GCFar.off -= (RTGCPTR)pArg2->u.u64Number;
5729 break;
5730 default:
5731 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5732 if (VBOX_FAILURE(rc))
5733 return rc;
5734 rc = dbgcOpAddrFlat(pDbgc, pArg2, &Var);
5735 if (VBOX_FAILURE(rc))
5736 return rc;
5737 pResult->u.GCFlat -= pArg2->u.GCFlat;
5738 break;
5739 }
5740 break;
5741
5742 /*
5743 * GC Phys
5744 */
5745 case DBGCVAR_TYPE_GC_PHYS:
5746 switch (pArg2->enmType)
5747 {
5748 case DBGCVAR_TYPE_HC_FLAT:
5749 case DBGCVAR_TYPE_HC_FAR:
5750 case DBGCVAR_TYPE_HC_PHYS:
5751 return VERR_PARSE_INVALID_OPERATION;
5752 default:
5753 *pResult = *pArg1;
5754 rc = dbgcOpAddrPhys(pDbgc, pArg2, &Var);
5755 if (VBOX_FAILURE(rc))
5756 return rc;
5757 if (Var.enmType != DBGCVAR_TYPE_GC_PHYS)
5758 return VERR_PARSE_INVALID_OPERATION;
5759 pResult->u.GCPhys -= Var.u.GCPhys;
5760 break;
5761 }
5762 break;
5763
5764 /*
5765 * HC Flat
5766 */
5767 case DBGCVAR_TYPE_HC_FLAT:
5768 *pResult = *pArg1;
5769 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5770 if (VBOX_FAILURE(rc))
5771 return rc;
5772 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5773 if (VBOX_FAILURE(rc))
5774 return rc;
5775 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
5776 break;
5777
5778 /*
5779 * HC Far
5780 */
5781 case DBGCVAR_TYPE_HC_FAR:
5782 switch (pArg2->enmType)
5783 {
5784 case DBGCVAR_TYPE_NUMBER:
5785 *pResult = *pArg1;
5786 pResult->u.HCFar.off -= (uintptr_t)pArg2->u.u64Number;
5787 break;
5788
5789 default:
5790 rc = dbgcOpAddrFlat(pDbgc, pArg1, pResult);
5791 if (VBOX_FAILURE(rc))
5792 return rc;
5793 rc = dbgcOpAddrHost(pDbgc, pArg2, &Var2);
5794 if (VBOX_FAILURE(rc))
5795 return rc;
5796 rc = dbgcOpAddrFlat(pDbgc, &Var2, &Var);
5797 if (VBOX_FAILURE(rc))
5798 return rc;
5799 pResult->u.pvHCFlat = (char *)pResult->u.pvHCFlat - (uintptr_t)Var.u.pvHCFlat;
5800 break;
5801 }
5802 break;
5803
5804 /*
5805 * HC Phys
5806 */
5807 case DBGCVAR_TYPE_HC_PHYS:
5808 *pResult = *pArg1;
5809 rc = dbgcOpAddrHostPhys(pDbgc, pArg2, &Var);
5810 if (VBOX_FAILURE(rc))
5811 return rc;
5812 pResult->u.HCPhys -= Var.u.HCPhys;
5813 break;
5814
5815 /*
5816 * Numbers (see start of function)
5817 */
5818 case DBGCVAR_TYPE_NUMBER:
5819 *pResult = *pArg1;
5820 switch (pArg2->enmType)
5821 {
5822 case DBGCVAR_TYPE_SYMBOL:
5823 case DBGCVAR_TYPE_STRING:
5824 rc = dbgcSymbolGet(pDbgc, pArg2->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
5825 if (VBOX_FAILURE(rc))
5826 return rc;
5827 case DBGCVAR_TYPE_NUMBER:
5828 pResult->u.u64Number -= pArg2->u.u64Number;
5829 break;
5830 default:
5831 return VERR_PARSE_INVALID_OPERATION;
5832 }
5833 break;
5834
5835 default:
5836 return VERR_PARSE_INVALID_OPERATION;
5837
5838 }
5839 return 0;
5840}
5841
5842
5843/**
5844 * Bitwise shift left operator (binary).
5845 *
5846 * @returns 0 on success.
5847 * @returns VBox evaluation / parsing error code on failure.
5848 * The caller does the bitching.
5849 * @param pDbgc Debugger console instance data.
5850 * @param pArg1 The first argument.
5851 * @param pArg2 The 2nd argument.
5852 * @param pResult Where to store the result.
5853 */
5854static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5855{
5856 LogFlow(("dbgcOpBitwiseShiftLeft\n"));
5857 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5858 return -1;
5859}
5860
5861
5862/**
5863 * Bitwise shift right operator (binary).
5864 *
5865 * @returns 0 on success.
5866 * @returns VBox evaluation / parsing error code on failure.
5867 * The caller does the bitching.
5868 * @param pDbgc Debugger console instance data.
5869 * @param pArg1 The first argument.
5870 * @param pArg2 The 2nd argument.
5871 * @param pResult Where to store the result.
5872 */
5873static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5874{
5875 LogFlow(("dbgcOpBitwiseShiftRight\n"));
5876 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5877 return -1;
5878}
5879
5880
5881/**
5882 * Bitwise and operator (binary).
5883 *
5884 * @returns 0 on success.
5885 * @returns VBox evaluation / parsing error code on failure.
5886 * The caller does the bitching.
5887 * @param pDbgc Debugger console instance data.
5888 * @param pArg1 The first argument.
5889 * @param pArg2 The 2nd argument.
5890 * @param pResult Where to store the result.
5891 */
5892static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5893{
5894 LogFlow(("dbgcOpBitwiseAnd\n"));
5895 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5896 return -1;
5897}
5898
5899
5900/**
5901 * Bitwise exclusive or operator (binary).
5902 *
5903 * @returns 0 on success.
5904 * @returns VBox evaluation / parsing error code on failure.
5905 * The caller does the bitching.
5906 * @param pDbgc Debugger console instance data.
5907 * @param pArg1 The first argument.
5908 * @param pArg2 The 2nd argument.
5909 * @param pResult Where to store the result.
5910 */
5911static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5912{
5913 LogFlow(("dbgcOpBitwiseXor\n"));
5914 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5915 return -1;
5916}
5917
5918
5919/**
5920 * Bitwise inclusive or operator (binary).
5921 *
5922 * @returns 0 on success.
5923 * @returns VBox evaluation / parsing error code on failure.
5924 * The caller does the bitching.
5925 * @param pDbgc Debugger console instance data.
5926 * @param pArg1 The first argument.
5927 * @param pArg2 The 2nd argument.
5928 * @param pResult Where to store the result.
5929 */
5930static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5931{
5932 LogFlow(("dbgcOpBitwiseOr\n"));
5933 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5934 return -1;
5935}
5936
5937
5938/**
5939 * Boolean and operator (binary).
5940 *
5941 * @returns 0 on success.
5942 * @returns VBox evaluation / parsing error code on failure.
5943 * The caller does the bitching.
5944 * @param pDbgc Debugger console instance data.
5945 * @param pArg1 The first argument.
5946 * @param pArg2 The 2nd argument.
5947 * @param pResult Where to store the result.
5948 */
5949static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5950{
5951 LogFlow(("dbgcOpBooleanAnd\n"));
5952 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5953 return -1;
5954}
5955
5956
5957/**
5958 * Boolean or operator (binary).
5959 *
5960 * @returns 0 on success.
5961 * @returns VBox evaluation / parsing error code on failure.
5962 * The caller does the bitching.
5963 * @param pDbgc Debugger console instance data.
5964 * @param pArg1 The first argument.
5965 * @param pArg2 The 2nd argument.
5966 * @param pResult Where to store the result.
5967 */
5968static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5969{
5970 LogFlow(("dbgcOpBooleanOr\n"));
5971 NOREF(pDbgc); NOREF(pArg1); NOREF(pArg2); NOREF(pResult);
5972 return -1;
5973}
5974
5975
5976/**
5977 * Range to operator (binary).
5978 *
5979 * @returns 0 on success.
5980 * @returns VBox evaluation / parsing error code on failure.
5981 * The caller does the bitching.
5982 * @param pDbgc Debugger console instance data.
5983 * @param pArg1 The first argument.
5984 * @param pArg2 The 2nd argument.
5985 * @param pResult Where to store the result.
5986 */
5987static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
5988{
5989// LogFlow(("dbgcOpRangeLength\n"));
5990 /*
5991 * Make result. Strings needs to be resolved into symbols.
5992 */
5993 if (pArg1->enmType == DBGCVAR_TYPE_STRING)
5994 {
5995 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_ANY, pResult);
5996 if (VBOX_FAILURE(rc))
5997 return rc;
5998 }
5999 else
6000 *pResult = *pArg1;
6001
6002 /*
6003 * Convert 2nd argument to element count.
6004 */
6005 pResult->enmRangeType = DBGCVAR_RANGE_ELEMENTS;
6006 switch (pArg2->enmType)
6007 {
6008 case DBGCVAR_TYPE_NUMBER:
6009 pResult->u64Range = pArg2->u.u64Number;
6010 break;
6011
6012 case DBGCVAR_TYPE_STRING:
6013 {
6014 int rc = dbgcSymbolGet(pDbgc, pArg1->u.pszString, DBGCVAR_TYPE_NUMBER, pResult);
6015 if (VBOX_FAILURE(rc))
6016 return rc;
6017 pResult->u64Range = pArg2->u.u64Number;
6018 break;
6019 }
6020
6021 default:
6022 return VERR_PARSE_INVALID_OPERATION;
6023 }
6024
6025 return VINF_SUCCESS;
6026}
6027
6028
6029/**
6030 * Range to operator (binary).
6031 *
6032 * @returns 0 on success.
6033 * @returns VBox evaluation / parsing error code on failure.
6034 * The caller does the bitching.
6035 * @param pDbgc Debugger console instance data.
6036 * @param pArg1 The first argument.
6037 * @param pArg2 The 2nd argument.
6038 * @param pResult Where to store the result.
6039 */
6040static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
6041{
6042// LogFlow(("dbgcOpRangeLengthBytes\n"));
6043 int rc = dbgcOpRangeLength(pDbgc, pArg1, pArg2, pResult);
6044 if (VBOX_SUCCESS(rc))
6045 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
6046 return rc;
6047}
6048
6049
6050/**
6051 * Range to operator (binary).
6052 *
6053 * @returns 0 on success.
6054 * @returns VBox evaluation / parsing error code on failure.
6055 * The caller does the bitching.
6056 * @param pDbgc Debugger console instance data.
6057 * @param pArg1 The first argument.
6058 * @param pArg2 The 2nd argument.
6059 * @param pResult Where to store the result.
6060 */
6061static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
6062{
6063// LogFlow(("dbgcOpRangeTo\n"));
6064 /*
6065 * Calc number of bytes between the two args.
6066 */
6067 DBGCVAR Diff;
6068 int rc = dbgcOpSub(pDbgc, pArg2, pArg1, &Diff);
6069 if (VBOX_FAILURE(rc))
6070 return rc;
6071
6072 /*
6073 * Use the diff as the range of Arg1.
6074 */
6075 *pResult = *pArg1;
6076 pResult->enmRangeType = DBGCVAR_RANGE_BYTES;
6077 switch (Diff.enmType)
6078 {
6079 case DBGCVAR_TYPE_GC_FLAT:
6080 pResult->u64Range = (RTGCUINTPTR)Diff.u.GCFlat;
6081 break;
6082 case DBGCVAR_TYPE_GC_PHYS:
6083 pResult->u64Range = Diff.u.GCPhys;
6084 break;
6085 case DBGCVAR_TYPE_HC_FLAT:
6086 pResult->u64Range = (uintptr_t)Diff.u.pvHCFlat;
6087 break;
6088 case DBGCVAR_TYPE_HC_PHYS:
6089 pResult->u64Range = Diff.u.HCPhys;
6090 break;
6091 case DBGCVAR_TYPE_NUMBER:
6092 pResult->u64Range = Diff.u.u64Number;
6093 break;
6094
6095 case DBGCVAR_TYPE_GC_FAR:
6096 case DBGCVAR_TYPE_STRING:
6097 case DBGCVAR_TYPE_HC_FAR:
6098 default:
6099 AssertMsgFailed(("Impossible!\n"));
6100 return VERR_PARSE_INVALID_OPERATION;
6101 }
6102
6103 return 0;
6104}
6105
6106
6107
6108
6109
6110/**
6111 * Output callback.
6112 *
6113 * @returns number of bytes written.
6114 * @param pvArg User argument.
6115 * @param pachChars Pointer to an array of utf-8 characters.
6116 * @param cbChars Number of bytes in the character array pointed to by pachChars.
6117 */
6118static DECLCALLBACK(size_t) dbgcFormatOutput(void *pvArg, const char *pachChars, size_t cbChars)
6119{
6120 PDBGC pDbgc = (PDBGC)pvArg;
6121 if (cbChars)
6122 {
6123 int rc = pDbgc->pBack->pfnWrite(pDbgc->pBack, pachChars, cbChars, NULL);
6124 if (VBOX_FAILURE(rc))
6125 {
6126 pDbgc->rcOutput = rc;
6127 cbChars = 0;
6128 }
6129 }
6130
6131 return cbChars;
6132}
6133
6134
6135
6136
6137
6138
6139
6140
6141
6142//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6143//
6144//
6145// C a l l b a c k H e l p e r s
6146//
6147//
6148//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6149
6150
6151
6152/**
6153 * Command helper for writing text to the debug console.
6154 *
6155 * @returns VBox status.
6156 * @param pCmdHlp Pointer to the command callback structure.
6157 * @param pvBuf What to write.
6158 * @param cbBuf Number of bytes to write.
6159 * @param pcbWritten Where to store the number of bytes actually written.
6160 * If NULL the entire buffer must be successfully written.
6161 */
6162static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
6163{
6164 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6165 return pDbgc->pBack->pfnWrite(pDbgc->pBack, pvBuf, cbBuf, pcbWritten);
6166}
6167
6168
6169/**
6170 * Command helper for writing formatted text to the debug console.
6171 *
6172 * @returns VBox status.
6173 * @param pCmdHlp Pointer to the command callback structure.
6174 * @param pcb Where to store the number of bytes written.
6175 * @param pszFormat The format string.
6176 * This is using the log formatter, so it's format extensions can be used.
6177 * @param ... Arguments specified in the format string.
6178 */
6179static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
6180{
6181 /*
6182 * Do the formatting and output.
6183 */
6184 va_list args;
6185 va_start(args, pszFormat);
6186 int rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, args);
6187 va_end(args);
6188
6189 return rc;
6190}
6191
6192/**
6193 * Callback to format non-standard format specifiers.
6194 *
6195 * @returns The number of bytes formatted.
6196 * @param pvArg Formatter argument.
6197 * @param pfnOutput Pointer to output function.
6198 * @param pvArgOutput Argument for the output function.
6199 * @param ppszFormat Pointer to the format string pointer. Advance this till the char
6200 * after the format specifier.
6201 * @param pArgs Pointer to the argument list. Use this to fetch the arguments.
6202 * @param cchWidth Format Width. -1 if not specified.
6203 * @param cchPrecision Format Precision. -1 if not specified.
6204 * @param fFlags Flags (RTSTR_NTFS_*).
6205 * @param chArgSize The argument size specifier, 'l' or 'L'.
6206 */
6207static DECLCALLBACK(int) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
6208 const char **ppszFormat, va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
6209{
6210 NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags); NOREF(chArgSize); NOREF(pvArg);
6211 if (**ppszFormat != 'D')
6212 {
6213 (*ppszFormat)++;
6214 return 0;
6215 }
6216
6217 (*ppszFormat)++;
6218 switch (**ppszFormat)
6219 {
6220 /*
6221 * Print variable without range.
6222 * The argument is a const pointer to the variable.
6223 */
6224 case 'V':
6225 {
6226 (*ppszFormat)++;
6227 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
6228 switch (pVar->enmType)
6229 {
6230 case DBGCVAR_TYPE_GC_FLAT:
6231 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv", pVar->u.GCFlat);
6232 case DBGCVAR_TYPE_GC_FAR:
6233 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
6234 case DBGCVAR_TYPE_GC_PHYS:
6235 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp", pVar->u.GCPhys);
6236 case DBGCVAR_TYPE_HC_FLAT:
6237 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv", (uintptr_t)pVar->u.pvHCFlat);
6238 case DBGCVAR_TYPE_HC_FAR:
6239 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
6240 case DBGCVAR_TYPE_HC_PHYS:
6241 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp", pVar->u.HCPhys);
6242 case DBGCVAR_TYPE_STRING:
6243 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
6244 case DBGCVAR_TYPE_NUMBER:
6245 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx", pVar->u.u64Number);
6246
6247 case DBGCVAR_TYPE_UNKNOWN:
6248 default:
6249 return pfnOutput(pvArgOutput, "??", 2);
6250 }
6251 }
6252
6253 /*
6254 * Print variable with range.
6255 * The argument is a const pointer to the variable.
6256 */
6257 case 'v':
6258 {
6259 (*ppszFormat)++;
6260 PCDBGCVAR pVar = va_arg(*pArgs, PCDBGCVAR);
6261
6262 char szRange[32];
6263 switch (pVar->enmRangeType)
6264 {
6265 case DBGCVAR_RANGE_NONE:
6266 szRange[0] = '\0';
6267 break;
6268 case DBGCVAR_RANGE_ELEMENTS:
6269 RTStrPrintf(szRange, sizeof(szRange), " L %llx", pVar->u64Range);
6270 break;
6271 case DBGCVAR_RANGE_BYTES:
6272 RTStrPrintf(szRange, sizeof(szRange), " LB %llx", pVar->u64Range);
6273 break;
6274 }
6275
6276 switch (pVar->enmType)
6277 {
6278 case DBGCVAR_TYPE_GC_FLAT:
6279 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%VGv%s", pVar->u.GCFlat, szRange);
6280 case DBGCVAR_TYPE_GC_FAR:
6281 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
6282 case DBGCVAR_TYPE_GC_PHYS:
6283 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%%%%VGp%s", pVar->u.GCPhys, szRange);
6284 case DBGCVAR_TYPE_HC_FLAT:
6285 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
6286 case DBGCVAR_TYPE_HC_FAR:
6287 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
6288 case DBGCVAR_TYPE_HC_PHYS:
6289 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%%%%%VHp%s", pVar->u.HCPhys, szRange);
6290 case DBGCVAR_TYPE_STRING:
6291 return pfnOutput(pvArgOutput, pVar->u.pszString, (size_t)pVar->u64Range);
6292 case DBGCVAR_TYPE_NUMBER:
6293 return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%llx%s", pVar->u.u64Number, szRange);
6294
6295 case DBGCVAR_TYPE_UNKNOWN:
6296 default:
6297 return pfnOutput(pvArgOutput, "??", 2);
6298 }
6299 }
6300
6301 default:
6302 AssertMsgFailed(("Invalid format type '%s'!\n", **ppszFormat));
6303 return 0;
6304 }
6305}
6306
6307
6308/**
6309 * Command helper for writing formatted text to the debug console.
6310 *
6311 * @returns VBox status.
6312 * @param pCmdHlp Pointer to the command callback structure.
6313 * @param pcb Where to store the number of bytes written.
6314 * @param pszFormat The format string.
6315 * This is using the log formatter, so it's format extensions can be used.
6316 * @param args Arguments specified in the format string.
6317 */
6318static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
6319{
6320 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6321
6322 /*
6323 * Do the formatting and output.
6324 */
6325 pDbgc->rcOutput = 0;
6326 size_t cb = RTStrFormatV(dbgcFormatOutput, pDbgc, dbgcStringFormatter, pDbgc, pszFormat, args);
6327
6328 if (pcbWritten)
6329 *pcbWritten = cb;
6330
6331 return pDbgc->rcOutput;
6332}
6333
6334
6335/**
6336 * Reports an error from a DBGF call.
6337 *
6338 * @returns VBox status code appropriate to return from a command.
6339 * @param pCmdHlp Pointer to command helpers.
6340 * @param rc The VBox status code returned by a DBGF call.
6341 * @param pszFormat Format string for additional messages. Can be NULL.
6342 * @param ... Format arguments, optional.
6343 */
6344static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
6345{
6346 switch (rc)
6347 {
6348 case VINF_SUCCESS:
6349 break;
6350
6351 default:
6352 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: %Vrc: %s", rc, pszFormat ? " " : "\n");
6353 if (VBOX_SUCCESS(rc) && pszFormat)
6354 rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
6355 break;
6356 }
6357 return rc;
6358}
6359
6360
6361/**
6362 * Reports an error from a DBGF call.
6363 *
6364 * @returns VBox status code appropriate to return from a command.
6365 * @param pCmdHlp Pointer to command helpers.
6366 * @param rc The VBox status code returned by a DBGF call.
6367 * @param pszFormat Format string for additional messages. Can be NULL.
6368 * @param ... Format arguments, optional.
6369 */
6370static DECLCALLBACK(int) dbgcHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)
6371{
6372 va_list args;
6373 va_start(args, pszFormat);
6374 int rcRet = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, args);
6375 va_end(args);
6376 return rcRet;
6377}
6378
6379
6380/**
6381 * Command helper for reading memory specified by a DBGC variable.
6382 *
6383 * @returns VBox status code appropriate to return from a command.
6384 * @param pCmdHlp Pointer to the command callback structure.
6385 * @param pVM VM handle if GC or physical HC address.
6386 * @param pvBuffer Where to store the read data.
6387 * @param cbRead Number of bytes to read.
6388 * @param pVarPointer DBGC variable specifying where to start reading.
6389 * @param pcbRead Where to store the number of bytes actually read.
6390 * This optional, but it's useful when read GC virtual memory where a
6391 * page in the requested range might not be present.
6392 * If not specified not-present failure or end of a HC physical page
6393 * will cause failure.
6394 */
6395static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
6396{
6397 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6398
6399 /*
6400 * Dummy check.
6401 */
6402 if (cbRead == 0)
6403 {
6404 if (*pcbRead)
6405 *pcbRead = 0;
6406 return VINF_SUCCESS;
6407 }
6408
6409 /*
6410 * Convert Far addresses getting size and the correct base address.
6411 * Getting and checking the size is what makes this messy and slow.
6412 */
6413 DBGCVAR Var = *pVarPointer;
6414 switch (pVarPointer->enmType)
6415 {
6416 case DBGCVAR_TYPE_GC_FAR:
6417 {
6418 /* Use DBGFR3AddrFromSelOff for the conversion. */
6419 Assert(pDbgc->pVM);
6420 DBGFADDRESS Address;
6421 int rc = DBGFR3AddrFromSelOff(pDbgc->pVM, &Address, Var.u.GCFar.sel, Var.u.GCFar.off);
6422 if (VBOX_FAILURE(rc))
6423 return rc;
6424
6425 /* don't bother with flat selectors (for now). */
6426 if (!DBGFADDRESS_IS_FLAT(&Address))
6427 {
6428 SELMSELINFO SelInfo;
6429 rc = SELMR3GetSelectorInfo(pDbgc->pVM, Address.Sel, &SelInfo);
6430 if (VBOX_SUCCESS(rc))
6431 {
6432 RTGCUINTPTR cb; /* -1 byte */
6433 if (SELMSelInfoIsExpandDown(&SelInfo))
6434 {
6435 if ( !SelInfo.Raw.Gen.u1Granularity
6436 && Address.off > UINT16_C(0xffff))
6437 return VERR_OUT_OF_SELECTOR_BOUNDS;
6438 if (Address.off <= SelInfo.cbLimit)
6439 return VERR_OUT_OF_SELECTOR_BOUNDS;
6440 cb = (SelInfo.Raw.Gen.u1Granularity ? UINT32_C(0xffffffff) : UINT32_C(0xffff)) - Address.off;
6441 }
6442 else
6443 {
6444 if (Address.off > SelInfo.cbLimit)
6445 return VERR_OUT_OF_SELECTOR_BOUNDS;
6446 cb = SelInfo.cbLimit - Address.off;
6447 }
6448 if (cbRead - 1 > cb)
6449 {
6450 if (!pcbRead)
6451 return VERR_OUT_OF_SELECTOR_BOUNDS;
6452 cbRead = cb + 1;
6453 }
6454 }
6455
6456 Var.enmType = DBGCVAR_TYPE_GC_FLAT;
6457 Var.u.GCFlat = Address.FlatPtr;
6458 }
6459 break;
6460 }
6461
6462 case DBGCVAR_TYPE_GC_FLAT:
6463 case DBGCVAR_TYPE_GC_PHYS:
6464 case DBGCVAR_TYPE_HC_FLAT:
6465 case DBGCVAR_TYPE_HC_PHYS:
6466 break;
6467
6468 case DBGCVAR_TYPE_HC_FAR: /* not supported yet! */
6469 default:
6470 return VERR_NOT_IMPLEMENTED;
6471 }
6472
6473
6474
6475 /*
6476 * Copy page by page.
6477 */
6478 size_t cbLeft = cbRead;
6479 for (;;)
6480 {
6481 /*
6482 * Calc read size.
6483 */
6484 size_t cb = RT_MIN(PAGE_SIZE, cbLeft);
6485 switch (pVarPointer->enmType)
6486 {
6487 case DBGCVAR_TYPE_GC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCFlat & PAGE_OFFSET_MASK)); break;
6488 case DBGCVAR_TYPE_GC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - (Var.u.GCPhys & PAGE_OFFSET_MASK)); break;
6489 case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
6490 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! */
6491 default: break;
6492 }
6493
6494 /*
6495 * Perform read.
6496 */
6497 int rc;
6498 switch (Var.enmType)
6499 {
6500 case DBGCVAR_TYPE_GC_FLAT:
6501 rc = MMR3ReadGCVirt(pVM, pvBuffer, Var.u.GCFlat, cb);
6502 break;
6503 case DBGCVAR_TYPE_GC_PHYS:
6504 rc = PGMPhysReadGCPhys(pVM, pvBuffer, Var.u.GCPhys, cb);
6505 break;
6506
6507 case DBGCVAR_TYPE_HC_PHYS:
6508 case DBGCVAR_TYPE_HC_FLAT:
6509 case DBGCVAR_TYPE_HC_FAR:
6510 {
6511 DBGCVAR Var2;
6512 rc = dbgcOpAddrFlat(pDbgc, &Var, &Var2);
6513 if (VBOX_SUCCESS(rc))
6514 {
6515 /** @todo protect this!!! */
6516 memcpy(pvBuffer, Var2.u.pvHCFlat, cb);
6517 rc = 0;
6518 }
6519 else
6520 rc = VERR_INVALID_POINTER;
6521 break;
6522 }
6523
6524 default:
6525 rc = VERR_PARSE_INCORRECT_ARG_TYPE;
6526 }
6527
6528 /*
6529 * Check for failure.
6530 */
6531 if (VBOX_FAILURE(rc))
6532 {
6533 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
6534 return VINF_SUCCESS;
6535 return rc;
6536 }
6537
6538 /*
6539 * Next.
6540 */
6541 cbLeft -= cb;
6542 if (!cbLeft)
6543 break;
6544 pvBuffer = (char *)pvBuffer + cb;
6545 rc = pCmdHlp->pfnEval(pCmdHlp, &Var, "%DV + %d", &Var, cb);
6546 if (VBOX_FAILURE(rc))
6547 {
6548 if (pcbRead && (*pcbRead = cbRead - cbLeft) > 0)
6549 return VINF_SUCCESS;
6550 return rc;
6551 }
6552 }
6553
6554 /*
6555 * Done
6556 */
6557 if (pcbRead)
6558 *pcbRead = cbRead;
6559 return 0;
6560}
6561
6562/**
6563 * Command helper for writing memory specified by a DBGC variable.
6564 *
6565 * @returns VBox status code appropriate to return from a command.
6566 * @param pCmdHlp Pointer to the command callback structure.
6567 * @param pVM VM handle if GC or physical HC address.
6568 * @param pvBuffer What to write.
6569 * @param cbWrite Number of bytes to write.
6570 * @param pVarPointer DBGC variable specifying where to start reading.
6571 * @param pcbWritten Where to store the number of bytes written.
6572 * This is optional. If NULL be aware that some of the buffer
6573 * might have been written to the specified address.
6574 */
6575static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
6576{
6577 NOREF(pCmdHlp); NOREF(pVM); NOREF(pvBuffer); NOREF(cbWrite); NOREF(pVarPointer); NOREF(pcbWritten);
6578 return VERR_NOT_IMPLEMENTED;
6579}
6580
6581
6582/**
6583 * Evaluates an expression.
6584 * (Hopefully the parser and functions are fully reentrant.)
6585 *
6586 * @returns VBox status code appropriate to return from a command.
6587 * @param pCmdHlp Pointer to the command callback structure.
6588 * @param pResult Where to store the result.
6589 * @param pszExpr The expression. Format string with the format DBGC extensions.
6590 * @param ... Format arguments.
6591 */
6592static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
6593{
6594 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6595
6596 /*
6597 * Format the expression.
6598 */
6599 char szExprFormatted[2048];
6600 va_list args;
6601 va_start(args, pszExpr);
6602 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
6603 va_end(args);
6604 /* ignore overflows. */
6605
6606 return dbgcEvalSub(pDbgc, &szExprFormatted[0], cb, pResult);
6607}
6608
6609
6610/**
6611 * Executes one command expression.
6612 * (Hopefully the parser and functions are fully reentrant.)
6613 *
6614 * @returns VBox status code appropriate to return from a command.
6615 * @param pCmdHlp Pointer to the command callback structure.
6616 * @param pszExpr The expression. Format string with the format DBGC extensions.
6617 * @param ... Format arguments.
6618 */
6619static DECLCALLBACK(int) dbgcHlpExec(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)
6620{
6621 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6622 /* Save the scratch state. */
6623 char *pszScratch = pDbgc->pszScratch;
6624 unsigned iArg = pDbgc->iArg;
6625
6626 /*
6627 * Format the expression.
6628 */
6629 va_list args;
6630 va_start(args, pszExpr);
6631 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
6632 size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
6633 va_end(args);
6634 if (cb >= cbScratch)
6635 return VERR_BUFFER_OVERFLOW;
6636
6637 /*
6638 * Execute the command.
6639 * We save and restore the arg index and scratch buffer pointer.
6640 */
6641 pDbgc->pszScratch = pDbgc->pszScratch + cb + 1;
6642 int rc = dbgcProcessCommand(pDbgc, pszScratch, cb);
6643
6644 /* Restore the scratch state. */
6645 pDbgc->iArg = iArg;
6646 pDbgc->pszScratch = pszScratch;
6647
6648 return rc;
6649}
6650
6651
6652/**
6653 * Converts a DBGC variable to a DBGF address structure.
6654 *
6655 * @returns VBox status code.
6656 * @param pCmdHlp Pointer to the command callback structure.
6657 * @param pVar The variable to convert.
6658 * @param pAddress The target address.
6659 */
6660static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
6661{
6662 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6663 return dbgcVarToDbgfAddr(pDbgc, pVar, pAddress);
6664}
6665
6666
6667/**
6668 * Converts a DBGC variable to a boolean.
6669 *
6670 * @returns VBox status code.
6671 * @param pCmdHlp Pointer to the command callback structure.
6672 * @param pVar The variable to convert.
6673 * @param pf Where to store the boolean.
6674 */
6675static DECLCALLBACK(int) dbgcHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)
6676{
6677 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
6678 NOREF(pDbgc);
6679
6680 switch (pVar->enmType)
6681 {
6682 case DBGCVAR_TYPE_STRING:
6683 /** @todo add strcasecmp / stricmp wrappers to iprt/string.h. */
6684 if ( !strcmp(pVar->u.pszString, "true")
6685 || !strcmp(pVar->u.pszString, "True")
6686 || !strcmp(pVar->u.pszString, "TRUE")
6687 || !strcmp(pVar->u.pszString, "on")
6688 || !strcmp(pVar->u.pszString, "On")
6689 || !strcmp(pVar->u.pszString, "oN")
6690 || !strcmp(pVar->u.pszString, "ON")
6691 || !strcmp(pVar->u.pszString, "enabled")
6692 || !strcmp(pVar->u.pszString, "Enabled")
6693 || !strcmp(pVar->u.pszString, "DISABLED"))
6694 {
6695 *pf = true;
6696 return VINF_SUCCESS;
6697 }
6698 if ( !strcmp(pVar->u.pszString, "false")
6699 || !strcmp(pVar->u.pszString, "False")
6700 || !strcmp(pVar->u.pszString, "FALSE")
6701 || !strcmp(pVar->u.pszString, "off")
6702 || !strcmp(pVar->u.pszString, "Off")
6703 || !strcmp(pVar->u.pszString, "OFF")
6704 || !strcmp(pVar->u.pszString, "disabled")
6705 || !strcmp(pVar->u.pszString, "Disabled")
6706 || !strcmp(pVar->u.pszString, "DISABLED"))
6707 {
6708 *pf = false;
6709 return VINF_SUCCESS;
6710 }
6711 return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
6712
6713 case DBGCVAR_TYPE_GC_FLAT:
6714 case DBGCVAR_TYPE_GC_PHYS:
6715 case DBGCVAR_TYPE_HC_FLAT:
6716 case DBGCVAR_TYPE_HC_PHYS:
6717 case DBGCVAR_TYPE_NUMBER:
6718 *pf = pVar->u.u64Number != 0;
6719 return VINF_SUCCESS;
6720
6721 case DBGCVAR_TYPE_HC_FAR:
6722 case DBGCVAR_TYPE_GC_FAR:
6723 case DBGCVAR_TYPE_SYMBOL:
6724 default:
6725 return VERR_PARSE_INCORRECT_ARG_TYPE;
6726 }
6727}
6728
6729
6730
6731
6732
6733//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6734//
6735//
6736// V a r i a b l e M a n i p u l a t i o n
6737//
6738//
6739//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6740
6741
6742
6743/** @todo move me!*/
6744static void dbgcVarSetGCFlat(PDBGCVAR pVar, RTGCPTR GCFlat)
6745{
6746 if (pVar)
6747 {
6748 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6749 pVar->u.GCFlat = GCFlat;
6750 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6751 pVar->u64Range = 0;
6752 }
6753}
6754
6755
6756/** @todo move me!*/
6757static void dbgcVarSetGCFlatByteRange(PDBGCVAR pVar, RTGCPTR GCFlat, uint64_t cb)
6758{
6759 if (pVar)
6760 {
6761 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
6762 pVar->u.GCFlat = GCFlat;
6763 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
6764 pVar->u64Range = cb;
6765 }
6766}
6767
6768
6769/** @todo move me!*/
6770static void dbgcVarSetVar(PDBGCVAR pVar, PCDBGCVAR pVar2)
6771{
6772 if (pVar)
6773 {
6774 if (pVar2)
6775 *pVar = *pVar2;
6776 else
6777 {
6778 pVar->enmType = DBGCVAR_TYPE_UNKNOWN;
6779 memset(&pVar->u, 0, sizeof(pVar->u));
6780 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6781 pVar->u64Range = 0;
6782 }
6783 }
6784}
6785
6786
6787/** @todo move me!*/
6788static void dbgcVarSetByteRange(PDBGCVAR pVar, uint64_t cb)
6789{
6790 if (pVar)
6791 {
6792 pVar->enmRangeType = DBGCVAR_RANGE_BYTES;
6793 pVar->u64Range = cb;
6794 }
6795}
6796
6797
6798/** @todo move me!*/
6799static void dbgcVarSetNoRange(PDBGCVAR pVar)
6800{
6801 if (pVar)
6802 {
6803 pVar->enmRangeType = DBGCVAR_RANGE_NONE;
6804 pVar->u64Range = 0;
6805 }
6806}
6807
6808
6809/**
6810 * Converts a DBGC variable to a DBGF address.
6811 *
6812 * @returns VBox status code.
6813 * @param pDbgc The DBGC instance.
6814 * @param pVar The variable.
6815 * @param pAddress Where to store the address.
6816 */
6817static int dbgcVarToDbgfAddr(PDBGC pDbgc, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
6818{
6819 AssertReturn(pVar, VERR_INVALID_PARAMETER);
6820 switch (pVar->enmType)
6821 {
6822 case DBGCVAR_TYPE_GC_FLAT:
6823 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, pVar->u.GCFlat);
6824 return VINF_SUCCESS;
6825
6826 case DBGCVAR_TYPE_NUMBER:
6827 DBGFR3AddrFromFlat(pDbgc->pVM, pAddress, (RTGCUINTPTR)pVar->u.u64Number);
6828 return VINF_SUCCESS;
6829
6830 case DBGCVAR_TYPE_GC_FAR:
6831 return DBGFR3AddrFromSelOff(pDbgc->pVM, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.sel);
6832
6833 case DBGCVAR_TYPE_STRING:
6834 case DBGCVAR_TYPE_SYMBOL:
6835 {
6836 DBGCVAR Var;
6837 int rc = pDbgc->CmdHlp.pfnEval(&pDbgc->CmdHlp, &Var, "%%(%DV)", pVar);
6838 if (VBOX_FAILURE(rc))
6839 return rc;
6840 return dbgcVarToDbgfAddr(pDbgc, &Var, pAddress);
6841 }
6842
6843 case DBGCVAR_TYPE_GC_PHYS:
6844 case DBGCVAR_TYPE_HC_FLAT:
6845 case DBGCVAR_TYPE_HC_FAR:
6846 case DBGCVAR_TYPE_HC_PHYS:
6847 default:
6848 return VERR_PARSE_CONVERSION_FAILED;
6849 }
6850}
6851
6852
6853
6854//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6855//
6856//
6857// B r e a k p o i n t M a n a g e m e n t
6858//
6859//
6860//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
6861
6862
6863/**
6864 * Adds a breakpoint to the DBGC breakpoint list.
6865 */
6866static int dbgcBpAdd(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
6867{
6868 /*
6869 * Check if it already exists.
6870 */
6871 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
6872 if (pBp)
6873 return VERR_DBGC_BP_EXISTS;
6874
6875 /*
6876 * Add the breakpoint.
6877 */
6878 if (pszCmd)
6879 pszCmd = RTStrStripL(pszCmd);
6880 size_t cchCmd = pszCmd ? strlen(pszCmd) : 0;
6881 pBp = (PDBGCBP)RTMemAlloc(RT_OFFSETOF(DBGCBP, szCmd[cchCmd + 1]));
6882 if (!pBp)
6883 return VERR_NO_MEMORY;
6884 if (cchCmd)
6885 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
6886 else
6887 pBp->szCmd[0] = '\0';
6888 pBp->cchCmd = cchCmd;
6889 pBp->iBp = iBp;
6890 pBp->pNext = pDbgc->pFirstBp;
6891 pDbgc->pFirstBp = pBp;
6892
6893 return VINF_SUCCESS;
6894}
6895
6896/**
6897 * Updates the a breakpoint.
6898 *
6899 * @returns VBox status code.
6900 * @param pDbgc The DBGC instance.
6901 * @param iBp The breakpoint to update.
6902 * @param pszCmd The new command.
6903 */
6904static int dbgcBpUpdate(PDBGC pDbgc, RTUINT iBp, const char *pszCmd)
6905{
6906 /*
6907 * Find the breakpoint.
6908 */
6909 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
6910 if (!pBp)
6911 return VERR_DBGC_BP_NOT_FOUND;
6912
6913 /*
6914 * Do we need to reallocate?
6915 */
6916 if (pszCmd)
6917 pszCmd = RTStrStripL(pszCmd);
6918 if (!pszCmd || !*pszCmd)
6919 pBp->szCmd[0] = '\0';
6920 else
6921 {
6922 size_t cchCmd = strlen(pszCmd);
6923 if (strlen(pBp->szCmd) >= cchCmd)
6924 {
6925 memcpy(pBp->szCmd, pszCmd, cchCmd + 1);
6926 pBp->cchCmd = cchCmd;
6927 }
6928 else
6929 {
6930 /*
6931 * Yes, let's do it the simple way...
6932 */
6933 int rc = dbgcBpDelete(pDbgc, iBp);
6934 AssertRC(rc);
6935 return dbgcBpAdd(pDbgc, iBp, pszCmd);
6936 }
6937 }
6938 return VINF_SUCCESS;
6939}
6940
6941
6942/**
6943 * Deletes a breakpoint.
6944 *
6945 * @returns VBox status code.
6946 * @param pDbgc The DBGC instance.
6947 * @param iBp The breakpoint to delete.
6948 */
6949static int dbgcBpDelete(PDBGC pDbgc, RTUINT iBp)
6950{
6951 /*
6952 * Search thru the list, when found unlink and free it.
6953 */
6954 PDBGCBP pBpPrev = NULL;
6955 PDBGCBP pBp = pDbgc->pFirstBp;
6956 for (; pBp; pBp = pBp->pNext)
6957 {
6958 if (pBp->iBp == iBp)
6959 {
6960 if (pBpPrev)
6961 pBpPrev->pNext = pBp->pNext;
6962 else
6963 pDbgc->pFirstBp = pBp->pNext;
6964 RTMemFree(pBp);
6965 return VINF_SUCCESS;
6966 }
6967 pBpPrev = pBp;
6968 }
6969
6970 return VERR_DBGC_BP_NOT_FOUND;
6971}
6972
6973
6974/**
6975 * Get a breakpoint.
6976 *
6977 * @returns Pointer to the breakpoint.
6978 * @returns NULL if the breakpoint wasn't found.
6979 * @param pDbgc The DBGC instance.
6980 * @param iBp The breakpoint to get.
6981 */
6982static PDBGCBP dbgcBpGet(PDBGC pDbgc, RTUINT iBp)
6983{
6984 /*
6985 * Enumerate the list.
6986 */
6987 PDBGCBP pBp = pDbgc->pFirstBp;
6988 for (; pBp; pBp = pBp->pNext)
6989 if (pBp->iBp == iBp)
6990 return pBp;
6991 return NULL;
6992}
6993
6994
6995/**
6996 * Executes the command of a breakpoint.
6997 *
6998 * @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
6999 * @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
7000 * @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
7001 * @returns VBox status code from dbgcProcessCommand() other wise.
7002 * @param pDbgc The DBGC instance.
7003 * @param iBp The breakpoint to execute.
7004 */
7005static int dbgcBpExec(PDBGC pDbgc, RTUINT iBp)
7006{
7007 /*
7008 * Find the breakpoint.
7009 */
7010 PDBGCBP pBp = dbgcBpGet(pDbgc, iBp);
7011 if (!pBp)
7012 return VERR_DBGC_BP_NOT_FOUND;
7013
7014 /*
7015 * Anything to do?
7016 */
7017 if (!pBp->cchCmd)
7018 return VINF_DBGC_BP_NO_COMMAND;
7019
7020 /*
7021 * Execute the command.
7022 * This means copying it to the scratch buffer and process it as if it
7023 * were user input. We must save and restore the state of the scratch buffer.
7024 */
7025 /* Save the scratch state. */
7026 char *pszScratch = pDbgc->pszScratch;
7027 unsigned iArg = pDbgc->iArg;
7028
7029 /* Copy the command to the scratch buffer. */
7030 size_t cbScratch = sizeof(pDbgc->achScratch) - (pDbgc->pszScratch - &pDbgc->achScratch[0]);
7031 if (pBp->cchCmd >= cbScratch)
7032 return VERR_BUFFER_OVERFLOW;
7033 memcpy(pDbgc->pszScratch, pBp->szCmd, pBp->cchCmd + 1);
7034
7035 /* Execute the command. */
7036 pDbgc->pszScratch = pDbgc->pszScratch + pBp->cchCmd + 1;
7037 int rc = dbgcProcessCommand(pDbgc, pszScratch, pBp->cchCmd);
7038
7039 /* Restore the scratch state. */
7040 pDbgc->iArg = iArg;
7041 pDbgc->pszScratch = pszScratch;
7042
7043 return rc;
7044}
7045
7046
7047
7048
7049
7050//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
7051//
7052//
7053// I n p u t , p a r s i n g a n d l o g g i n g
7054//
7055//
7056//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
7057
7058
7059
7060/**
7061 * Prints any log lines from the log buffer.
7062 *
7063 * The caller must not call function this unless pDbgc->fLog is set.
7064 *
7065 * @returns VBox status. (output related)
7066 * @param pDbgc Debugger console instance data.
7067 */
7068static int dbgcProcessLog(PDBGC pDbgc)
7069{
7070 /** @todo */
7071 NOREF(pDbgc);
7072 return 0;
7073}
7074
7075
7076
7077/**
7078 * Handle input buffer overflow.
7079 *
7080 * Will read any available input looking for a '\n' to reset the buffer on.
7081 *
7082 * @returns VBox status.
7083 * @param pDbgc Debugger console instance data.
7084 */
7085static int dbgcInputOverflow(PDBGC pDbgc)
7086{
7087 /*
7088 * Assert overflow status and reset the input buffer.
7089 */
7090 if (!pDbgc->fInputOverflow)
7091 {
7092 pDbgc->fInputOverflow = true;
7093 pDbgc->iRead = pDbgc->iWrite = 0;
7094 pDbgc->cInputLines = 0;
7095 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Input overflow!!\n");
7096 }
7097
7098 /*
7099 * Eat input till no more or there is a '\n'.
7100 * When finding a '\n' we'll continue normal processing.
7101 */
7102 while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0))
7103 {
7104 size_t cbRead;
7105 int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
7106 if (VBOX_FAILURE(rc))
7107 return rc;
7108 char *psz = (char *)memchr(&pDbgc->achInput[0], '\n', cbRead);
7109 if (psz)
7110 {
7111 pDbgc->fInputOverflow = false;
7112 pDbgc->iRead = psz - &pDbgc->achInput[0] + 1;
7113 pDbgc->iWrite = cbRead;
7114 pDbgc->cInputLines = 0;
7115 break;
7116 }
7117 }
7118
7119 return 0;
7120}
7121
7122
7123
7124/**
7125 * Read input and do some preprocessing.
7126 *
7127 * @returns VBox status.
7128 * In addition to the iWrite and achInput, cInputLines is maintained.
7129 * In case of an input overflow the fInputOverflow flag will be set.
7130 * @param pDbgc Debugger console instance data.
7131 */
7132static int dbgcInputRead(PDBGC pDbgc)
7133{
7134 /*
7135 * We have ready input.
7136 * Read it till we don't have any or we have a full input buffer.
7137 */
7138 int rc = 0;
7139 do
7140 {
7141 /*
7142 * More available buffer space?
7143 */
7144 size_t cbLeft;
7145 if (pDbgc->iWrite > pDbgc->iRead)
7146 cbLeft = sizeof(pDbgc->achInput) - pDbgc->iWrite - (pDbgc->iRead == 0);
7147 else
7148 cbLeft = pDbgc->iRead - pDbgc->iWrite - 1;
7149 if (!cbLeft)
7150 {
7151 /* overflow? */
7152 if (!pDbgc->cInputLines)
7153 rc = dbgcInputOverflow(pDbgc);
7154 break;
7155 }
7156
7157 /*
7158 * Read one char and interpret it.
7159 */
7160 char achRead[128];
7161 size_t cbRead;
7162 rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &achRead[0], RT_MIN(cbLeft, sizeof(achRead)), &cbRead);
7163 if (VBOX_FAILURE(rc))
7164 return rc;
7165 char *psz = &achRead[0];
7166 while (cbRead-- > 0)
7167 {
7168 char ch = *psz++;
7169 switch (ch)
7170 {
7171 /*
7172 * Ignore.
7173 */
7174 case '\0':
7175 case '\r':
7176 case '\a':
7177 break;
7178
7179 /*
7180 * Backspace.
7181 */
7182 case '\b':
7183 Log2(("DBGC: backspace\n"));
7184 if (pDbgc->iRead != pDbgc->iWrite)
7185 {
7186 unsigned iWriteUndo = pDbgc->iWrite;
7187 if (pDbgc->iWrite)
7188 pDbgc->iWrite--;
7189 else
7190 pDbgc->iWrite = sizeof(pDbgc->achInput) - 1;
7191
7192 if (pDbgc->achInput[pDbgc->iWrite] == '\n')
7193 pDbgc->iWrite = iWriteUndo;
7194 }
7195 break;
7196
7197 /*
7198 * Add char to buffer.
7199 */
7200 case '\t':
7201 case '\n':
7202 case ';':
7203 switch (ch)
7204 {
7205 case '\t': ch = ' '; break;
7206 case '\n': pDbgc->cInputLines++; break;
7207 }
7208 default:
7209 Log2(("DBGC: ch=%02x\n", (unsigned char)ch));
7210 pDbgc->achInput[pDbgc->iWrite] = ch;
7211 if (++pDbgc->iWrite >= sizeof(pDbgc->achInput))
7212 pDbgc->iWrite = 0;
7213 break;
7214 }
7215 }
7216
7217 /* Terminate it to make it easier to read in the debugger. */
7218 pDbgc->achInput[pDbgc->iWrite] = '\0';
7219 } while (pDbgc->pBack->pfnInput(pDbgc->pBack, 0));
7220
7221 return rc;
7222}
7223
7224
7225/**
7226 * Finds a builtin symbol.
7227 * @returns Pointer to symbol descriptor on success.
7228 * @returns NULL on failure.
7229 * @param pDbgc The debug console instance.
7230 * @param pszSymbol The symbol name.
7231 */
7232static PCDBGCSYM dbgcLookupRegisterSymbol(PDBGC pDbgc, const char *pszSymbol)
7233{
7234 for (unsigned iSym = 0; iSym < ELEMENTS(g_aSyms); iSym++)
7235 if (!strcmp(pszSymbol, g_aSyms[iSym].pszName))
7236 return &g_aSyms[iSym];
7237
7238 /** @todo externally registered symbols. */
7239 NOREF(pDbgc);
7240 return NULL;
7241}
7242
7243
7244/**
7245 * Resolves a symbol (or tries to do so at least).
7246 *
7247 * @returns 0 on success.
7248 * @returns VBox status on failure.
7249 * @param pDbgc The debug console instance.
7250 * @param pszSymbol The symbol name.
7251 * @param enmType The result type.
7252 * @param pResult Where to store the result.
7253 */
7254static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult)
7255{
7256 /*
7257 * Builtin?
7258 */
7259 PCDBGCSYM pSymDesc = dbgcLookupRegisterSymbol(pDbgc, pszSymbol);
7260 if (pSymDesc)
7261 {
7262 if (!pSymDesc->pfnGet)
7263 return VERR_PARSE_WRITEONLY_SYMBOL;
7264 return pSymDesc->pfnGet(pSymDesc, &pDbgc->CmdHlp, enmType, pResult);
7265 }
7266
7267
7268 /*
7269 * Ask PDM.
7270 */
7271 /** @todo resolve symbols using PDM. */
7272
7273
7274 /*
7275 * Ask the debug info manager.
7276 */
7277 DBGFSYMBOL Symbol;
7278 int rc = DBGFR3SymbolByName(pDbgc->pVM, pszSymbol, &Symbol);
7279 if (VBOX_SUCCESS(rc))
7280 {
7281 /*
7282 * Default return is a flat gc address.
7283 */
7284 memset(pResult, 0, sizeof(*pResult));
7285 pResult->enmRangeType = Symbol.cb ? DBGCVAR_RANGE_BYTES : DBGCVAR_RANGE_NONE;
7286 pResult->u64Range = Symbol.cb;
7287 pResult->enmType = DBGCVAR_TYPE_GC_FLAT;
7288 pResult->u.GCFlat = Symbol.Value;
7289 DBGCVAR VarTmp;
7290 switch (enmType)
7291 {
7292 /* nothing to do. */
7293 case DBGCVAR_TYPE_GC_FLAT:
7294 case DBGCVAR_TYPE_GC_FAR:
7295 case DBGCVAR_TYPE_ANY:
7296 return VINF_SUCCESS;
7297
7298 /* simply make it numeric. */
7299 case DBGCVAR_TYPE_NUMBER:
7300 pResult->enmType = DBGCVAR_TYPE_NUMBER;
7301 pResult->u.u64Number = Symbol.Value;
7302 return VINF_SUCCESS;
7303
7304 /* cast it. */
7305
7306 case DBGCVAR_TYPE_GC_PHYS:
7307 VarTmp = *pResult;
7308 return dbgcOpAddrPhys(pDbgc, &VarTmp, pResult);
7309
7310 case DBGCVAR_TYPE_HC_FAR:
7311 case DBGCVAR_TYPE_HC_FLAT:
7312 VarTmp = *pResult;
7313 return dbgcOpAddrHost(pDbgc, &VarTmp, pResult);
7314
7315 case DBGCVAR_TYPE_HC_PHYS:
7316 VarTmp = *pResult;
7317 return dbgcOpAddrHostPhys(pDbgc, &VarTmp, pResult);
7318
7319 default:
7320 AssertMsgFailed(("Internal error enmType=%d\n", enmType));
7321 return VERR_INVALID_PARAMETER;
7322 }
7323 }
7324
7325 return VERR_PARSE_NOT_IMPLEMENTED;
7326}
7327
7328
7329
7330/**
7331 * Finds a routine.
7332 *
7333 * @returns Pointer to the command descriptor.
7334 * If the request was for an external command, the caller is responsible for
7335 * unlocking the external command list.
7336 * @returns NULL if not found.
7337 * @param pDbgc The debug console instance.
7338 * @param pachName Pointer to the routine string (not terminated).
7339 * @param cchName Length of the routine name.
7340 * @param fExternal Whether or not the routine is external.
7341 */
7342static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
7343{
7344 if (!fExternal)
7345 {
7346 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
7347 {
7348 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
7349 && !g_aCmds[iCmd].pszCmd[cchName])
7350 return &g_aCmds[iCmd];
7351 }
7352 }
7353 else
7354 {
7355 DBGCEXTCMDS_LOCK_RD();
7356 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
7357 {
7358 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
7359 {
7360 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
7361 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])
7362 return &pExtCmds->paCmds[iCmd];
7363 }
7364 }
7365 DBGCEXTCMDS_UNLOCK_RD();
7366 }
7367
7368 NOREF(pDbgc);
7369 return NULL;
7370}
7371
7372
7373/**
7374 * Searches for an operator descriptor which matches the start of
7375 * the expression given us.
7376 *
7377 * @returns Pointer to the operator on success.
7378 * @param pDbgc The debug console instance.
7379 * @param pszExpr Pointer to the expression string which might start with an operator.
7380 * @param fPreferBinary Whether to favour binary or unary operators.
7381 * Caller must assert that it's the disired type! Both types will still
7382 * be returned, this is only for resolving duplicates.
7383 * @param chPrev The previous char. Some operators requires a blank in front of it.
7384 */
7385static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
7386{
7387 PCDBGCOP pOp = NULL;
7388 for (unsigned iOp = 0; iOp < ELEMENTS(g_aOps); iOp++)
7389 {
7390 if ( g_aOps[iOp].szName[0] == pszExpr[0]
7391 && (!g_aOps[iOp].szName[1] || g_aOps[iOp].szName[1] == pszExpr[1])
7392 && (!g_aOps[iOp].szName[2] || g_aOps[iOp].szName[2] == pszExpr[2]))
7393 {
7394 /*
7395 * Check that we don't mistake it for some other operator which have more chars.
7396 */
7397 unsigned j;
7398 for (j = iOp + 1; j < ELEMENTS(g_aOps); j++)
7399 if ( g_aOps[j].cchName > g_aOps[iOp].cchName
7400 && g_aOps[j].szName[0] == pszExpr[0]
7401 && (!g_aOps[j].szName[1] || g_aOps[j].szName[1] == pszExpr[1])
7402 && (!g_aOps[j].szName[2] || g_aOps[j].szName[2] == pszExpr[2]) )
7403 break;
7404 if (j < ELEMENTS(g_aOps))
7405 continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */
7406 pOp = &g_aOps[iOp];
7407
7408 /*
7409 * Prefered type?
7410 */
7411 if (g_aOps[iOp].fBinary == fPreferBinary)
7412 break;
7413 }
7414 }
7415
7416 if (pOp)
7417 Log2(("dbgcOperatorLookup: pOp=%p %s\n", pOp, pOp->szName));
7418 NOREF(pDbgc); NOREF(chPrev);
7419 return pOp;
7420}
7421
7422
7423/**
7424 * Initalizes g_bmOperatorChars.
7425 */
7426static void dbgcInitOpCharBitMap(void)
7427{
7428 memset(g_bmOperatorChars, 0, sizeof(g_bmOperatorChars));
7429 for (unsigned iOp = 0; iOp < RT_ELEMENTS(g_aOps); iOp++)
7430 ASMBitSet(&g_bmOperatorChars[0], (uint8_t)g_aOps[iOp].szName[0]);
7431}
7432
7433
7434/**
7435 * Checks whether the character may be the start of an operator.
7436 *
7437 * @returns true/false.
7438 * @param ch The character.
7439 */
7440DECLINLINE(bool) dbgcIsOpChar(char ch)
7441{
7442 return ASMBitTest(&g_bmOperatorChars[0], (uint8_t)ch);
7443}
7444
7445
7446static int dbgcEvalSubString(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pArg)
7447{
7448 Log2(("dbgcEvalSubString: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7449
7450 /*
7451 * Removing any quoting and escapings.
7452 */
7453 char ch = *pszExpr;
7454 if (ch == '"' || ch == '\'' || ch == '`')
7455 {
7456 if (pszExpr[--cchExpr] != ch)
7457 return VERR_PARSE_UNBALANCED_QUOTE;
7458 cchExpr--;
7459 pszExpr++;
7460
7461 /** @todo string unescaping. */
7462 }
7463 pszExpr[cchExpr] = '\0';
7464
7465 /*
7466 * Make the argument.
7467 */
7468 pArg->pDesc = NULL;
7469 pArg->pNext = NULL;
7470 pArg->enmType = DBGCVAR_TYPE_STRING;
7471 pArg->u.pszString = pszExpr;
7472 pArg->enmRangeType = DBGCVAR_RANGE_BYTES;
7473 pArg->u64Range = cchExpr;
7474
7475 NOREF(pDbgc);
7476 return 0;
7477}
7478
7479
7480static int dbgcEvalSubNum(char *pszExpr, unsigned uBase, PDBGCVAR pArg)
7481{
7482 Log2(("dbgcEvalSubNum: uBase=%d pszExpr=%s\n", uBase, pszExpr));
7483 /*
7484 * Convert to number.
7485 */
7486 uint64_t u64 = 0;
7487 char ch;
7488 while ((ch = *pszExpr) != '\0')
7489 {
7490 uint64_t u64Prev = u64;
7491 unsigned u = ch - '0';
7492 if (u < 10 && u < uBase)
7493 u64 = u64 * uBase + u;
7494 else if (ch >= 'a' && (u = ch - ('a' - 10)) < uBase)
7495 u64 = u64 * uBase + u;
7496 else if (ch >= 'A' && (u = ch - ('A' - 10)) < uBase)
7497 u64 = u64 * uBase + u;
7498 else
7499 return VERR_PARSE_INVALID_NUMBER;
7500
7501 /* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
7502 if (u64Prev != u64 / uBase)
7503 return VERR_PARSE_NUMBER_TOO_BIG;
7504
7505 /* next */
7506 pszExpr++;
7507 }
7508
7509 /*
7510 * Initialize the argument.
7511 */
7512 pArg->pDesc = NULL;
7513 pArg->pNext = NULL;
7514 pArg->enmType = DBGCVAR_TYPE_NUMBER;
7515 pArg->u.u64Number = u64;
7516 pArg->enmRangeType = DBGCVAR_RANGE_NONE;
7517 pArg->u64Range = 0;
7518
7519 return 0;
7520}
7521
7522
7523/**
7524 * Match variable and variable descriptor, promoting the variable if necessary.
7525 *
7526 * @returns VBox status code.
7527 * @param pDbgc Debug console instanace.
7528 * @param pVar Variable.
7529 * @param pVarDesc Variable descriptor.
7530 */
7531static int dbgcEvalSubMatchVar(PDBGC pDbgc, PDBGCVAR pVar, PCDBGCVARDESC pVarDesc)
7532{
7533 /*
7534 * (If match or promoted to match, return, else break.)
7535 */
7536 switch (pVarDesc->enmCategory)
7537 {
7538 /*
7539 * Anything goes
7540 */
7541 case DBGCVAR_CAT_ANY:
7542 return VINF_SUCCESS;
7543
7544 /*
7545 * Pointer with and without range.
7546 * We can try resolve strings and symbols as symbols and
7547 * promote numbers to flat GC pointers.
7548 */
7549 case DBGCVAR_CAT_POINTER_NO_RANGE:
7550 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
7551 return VERR_PARSE_NO_RANGE_ALLOWED;
7552 /* fallthru */
7553 case DBGCVAR_CAT_POINTER:
7554 switch (pVar->enmType)
7555 {
7556 case DBGCVAR_TYPE_GC_FLAT:
7557 case DBGCVAR_TYPE_GC_FAR:
7558 case DBGCVAR_TYPE_GC_PHYS:
7559 case DBGCVAR_TYPE_HC_FLAT:
7560 case DBGCVAR_TYPE_HC_FAR:
7561 case DBGCVAR_TYPE_HC_PHYS:
7562 return VINF_SUCCESS;
7563
7564 case DBGCVAR_TYPE_SYMBOL:
7565 case DBGCVAR_TYPE_STRING:
7566 {
7567 DBGCVAR Var;
7568 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
7569 if (VBOX_SUCCESS(rc))
7570 {
7571 /* deal with range */
7572 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
7573 {
7574 Var.enmRangeType = pVar->enmRangeType;
7575 Var.u64Range = pVar->u64Range;
7576 }
7577 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
7578 Var.enmRangeType = DBGCVAR_RANGE_NONE;
7579 *pVar = Var;
7580 return rc;
7581 }
7582 break;
7583 }
7584
7585 case DBGCVAR_TYPE_NUMBER:
7586 {
7587 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
7588 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
7589 pVar->u.GCFlat = GCPtr;
7590 return VINF_SUCCESS;
7591 }
7592
7593 default:
7594 break;
7595 }
7596 break;
7597
7598 /*
7599 * GC pointer with and without range.
7600 * We can try resolve strings and symbols as symbols and
7601 * promote numbers to flat GC pointers.
7602 */
7603 case DBGCVAR_CAT_GC_POINTER_NO_RANGE:
7604 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
7605 return VERR_PARSE_NO_RANGE_ALLOWED;
7606 /* fallthru */
7607 case DBGCVAR_CAT_GC_POINTER:
7608 switch (pVar->enmType)
7609 {
7610 case DBGCVAR_TYPE_GC_FLAT:
7611 case DBGCVAR_TYPE_GC_FAR:
7612 case DBGCVAR_TYPE_GC_PHYS:
7613 return VINF_SUCCESS;
7614
7615 case DBGCVAR_TYPE_HC_FLAT:
7616 case DBGCVAR_TYPE_HC_FAR:
7617 case DBGCVAR_TYPE_HC_PHYS:
7618 return VERR_PARSE_CONVERSION_FAILED;
7619
7620 case DBGCVAR_TYPE_SYMBOL:
7621 case DBGCVAR_TYPE_STRING:
7622 {
7623 DBGCVAR Var;
7624 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_GC_FLAT, &Var);
7625 if (VBOX_SUCCESS(rc))
7626 {
7627 /* deal with range */
7628 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
7629 {
7630 Var.enmRangeType = pVar->enmRangeType;
7631 Var.u64Range = pVar->u64Range;
7632 }
7633 else if (pVarDesc->enmCategory == DBGCVAR_CAT_POINTER_NO_RANGE)
7634 Var.enmRangeType = DBGCVAR_RANGE_NONE;
7635 *pVar = Var;
7636 return rc;
7637 }
7638 break;
7639 }
7640
7641 case DBGCVAR_TYPE_NUMBER:
7642 {
7643 RTGCPTR GCPtr = (RTGCPTR)pVar->u.u64Number;
7644 pVar->enmType = DBGCVAR_TYPE_GC_FLAT;
7645 pVar->u.GCFlat = GCPtr;
7646 return VINF_SUCCESS;
7647 }
7648
7649 default:
7650 break;
7651 }
7652 break;
7653
7654 /*
7655 * Number with or without a range.
7656 * Numbers can be resolved from symbols, but we cannot demote a pointer
7657 * to a number.
7658 */
7659 case DBGCVAR_CAT_NUMBER_NO_RANGE:
7660 if (pVar->enmRangeType != DBGCVAR_RANGE_NONE)
7661 return VERR_PARSE_NO_RANGE_ALLOWED;
7662 /* fallthru */
7663 case DBGCVAR_CAT_NUMBER:
7664 switch (pVar->enmType)
7665 {
7666 case DBGCVAR_TYPE_NUMBER:
7667 return VINF_SUCCESS;
7668
7669 case DBGCVAR_TYPE_SYMBOL:
7670 case DBGCVAR_TYPE_STRING:
7671 {
7672 DBGCVAR Var;
7673 int rc = dbgcSymbolGet(pDbgc, pVar->u.pszString, DBGCVAR_TYPE_NUMBER, &Var);
7674 if (VBOX_SUCCESS(rc))
7675 {
7676 *pVar = Var;
7677 return rc;
7678 }
7679 break;
7680 }
7681 default:
7682 break;
7683 }
7684 break;
7685
7686 /*
7687 * Strings can easily be made from symbols (and of course strings).
7688 * We could consider reformatting the addresses and numbers into strings later...
7689 */
7690 case DBGCVAR_CAT_STRING:
7691 switch (pVar->enmType)
7692 {
7693 case DBGCVAR_TYPE_SYMBOL:
7694 pVar->enmType = DBGCVAR_TYPE_STRING;
7695 /* fallthru */
7696 case DBGCVAR_TYPE_STRING:
7697 return VINF_SUCCESS;
7698 default:
7699 break;
7700 }
7701 break;
7702
7703 /*
7704 * Symol is pretty much the same thing as a string (at least until we actually implement it).
7705 */
7706 case DBGCVAR_CAT_SYMBOL:
7707 switch (pVar->enmType)
7708 {
7709 case DBGCVAR_TYPE_STRING:
7710 pVar->enmType = DBGCVAR_TYPE_SYMBOL;
7711 /* fallthru */
7712 case DBGCVAR_TYPE_SYMBOL:
7713 return VINF_SUCCESS;
7714 default:
7715 break;
7716 }
7717 break;
7718
7719 /*
7720 * Anything else is illegal.
7721 */
7722 default:
7723 AssertMsgFailed(("enmCategory=%d\n", pVar->enmType));
7724 break;
7725 }
7726
7727 return VERR_PARSE_NO_ARGUMENT_MATCH;
7728}
7729
7730
7731/**
7732 * Matches a set of variables with a description set.
7733 *
7734 * This is typically used for routine arguments before a call. The effects in
7735 * addition to the validation, is that some variables might be propagated to
7736 * other types in order to match the description. The following transformations
7737 * are supported:
7738 * - String reinterpreted as a symbol and resolved to a number or pointer.
7739 * - Number to a pointer.
7740 * - Pointer to a number.
7741 * @returns 0 on success with paVars.
7742 * @returns VBox error code for match errors.
7743 */
7744static int dbgcEvalSubMatchVars(PDBGC pDbgc, unsigned cVarsMin, unsigned cVarsMax,
7745 PCDBGCVARDESC paVarDescs, unsigned cVarDescs,
7746 PDBGCVAR paVars, unsigned cVars)
7747{
7748 /*
7749 * Just do basic min / max checks first.
7750 */
7751 if (cVars < cVarsMin)
7752 return VERR_PARSE_TOO_FEW_ARGUMENTS;
7753 if (cVars > cVarsMax)
7754 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7755
7756 /*
7757 * Match the descriptors and actual variables.
7758 */
7759 PCDBGCVARDESC pPrevDesc = NULL;
7760 unsigned cCurDesc = 0;
7761 unsigned iVar = 0;
7762 unsigned iVarDesc = 0;
7763 while (iVar < cVars)
7764 {
7765 /* walk the descriptors */
7766 if (iVarDesc >= cVarDescs)
7767 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7768 if ( ( paVarDescs[iVarDesc].fFlags & DBGCVD_FLAGS_DEP_PREV
7769 && &paVarDescs[iVarDesc - 1] != pPrevDesc)
7770 || cCurDesc >= paVarDescs[iVarDesc].cTimesMax)
7771 {
7772 iVarDesc++;
7773 if (iVarDesc >= cVarDescs)
7774 return VERR_PARSE_TOO_MANY_ARGUMENTS;
7775 cCurDesc = 0;
7776 }
7777
7778 /*
7779 * Skip thru optional arguments until we find something which matches
7780 * or can easily be promoted to what the descriptor want.
7781 */
7782 for (;;)
7783 {
7784 int rc = dbgcEvalSubMatchVar(pDbgc, &paVars[iVar], &paVarDescs[iVarDesc]);
7785 if (VBOX_SUCCESS(rc))
7786 {
7787 paVars[iVar].pDesc = &paVarDescs[iVarDesc];
7788 cCurDesc++;
7789 break;
7790 }
7791
7792 /* can we advance? */
7793 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
7794 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
7795 if (++iVarDesc >= cVarDescs)
7796 return VERR_PARSE_ARGUMENT_TYPE_MISMATCH;
7797 cCurDesc = 0;
7798 }
7799
7800 /* next var */
7801 iVar++;
7802 }
7803
7804 /*
7805 * Check that the rest of the descriptors are optional.
7806 */
7807 while (iVarDesc < cVarDescs)
7808 {
7809 if (paVarDescs[iVarDesc].cTimesMin > cCurDesc)
7810 return VERR_PARSE_TOO_FEW_ARGUMENTS;
7811 cCurDesc = 0;
7812
7813 /* next */
7814 iVarDesc++;
7815 }
7816
7817 return 0;
7818}
7819
7820
7821/**
7822 * Evaluates one argument with respect to unary operators.
7823 *
7824 * @returns 0 on success. pResult contains the result.
7825 * @returns VBox error code on parse or other evaluation error.
7826 *
7827 * @param pDbgc Debugger console instance data.
7828 * @param pszExpr The expression string.
7829 * @param pResult Where to store the result of the expression evaluation.
7830 */
7831static int dbgcEvalSubUnary(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
7832{
7833 Log2(("dbgcEvalSubUnary: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7834
7835 /*
7836 * The state of the expression is now such that it will start by zero or more
7837 * unary operators and being followed by an expression of some kind.
7838 * The expression is either plain or in parenthesis.
7839 *
7840 * Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
7841 * ASSUME: unary operators are all of equal precedence.
7842 */
7843 int rc = 0;
7844 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, pszExpr, false, ' ');
7845 if (pOp)
7846 {
7847 /* binary operators means syntax error. */
7848 if (pOp->fBinary)
7849 return VERR_PARSE_UNEXPECTED_OPERATOR;
7850
7851 /*
7852 * If the next expression (the one following the unary operator) is in a
7853 * parenthesis a full eval is needed. If not the unary eval will suffice.
7854 */
7855 /* calc and strip next expr. */
7856 char *pszExpr2 = pszExpr + pOp->cchName;
7857 while (isblank(*pszExpr2))
7858 pszExpr2++;
7859
7860 if (!*pszExpr2)
7861 rc = VERR_PARSE_EMPTY_ARGUMENT;
7862 else
7863 {
7864 DBGCVAR Arg;
7865 if (*pszExpr2 == '(')
7866 rc = dbgcEvalSub(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
7867 else
7868 rc = dbgcEvalSubUnary(pDbgc, pszExpr2, cchExpr - (pszExpr2 - pszExpr), &Arg);
7869 if (VBOX_SUCCESS(rc))
7870 rc = pOp->pfnHandlerUnary(pDbgc, &Arg, pResult);
7871 }
7872 }
7873 else
7874 {
7875 /*
7876 * Didn't find any operators, so it we have to check if this can be an
7877 * function call before assuming numeric or string expression.
7878 *
7879 * (ASSUMPTIONS:)
7880 * A function name only contains alphanumerical chars and it can not start
7881 * with a numerical character.
7882 * Immediately following the name is a parenthesis which must over
7883 * the remaining part of the expression.
7884 */
7885 bool fExternal = *pszExpr == '.';
7886 char *pszFun = fExternal ? pszExpr + 1 : pszExpr;
7887 char *pszFunEnd = NULL;
7888 if (pszExpr[cchExpr - 1] == ')' && isalpha(*pszFun))
7889 {
7890 pszFunEnd = pszExpr + 1;
7891 while (*pszFunEnd != '(' && isalnum(*pszFunEnd))
7892 pszFunEnd++;
7893 if (*pszFunEnd != '(')
7894 pszFunEnd = NULL;
7895 }
7896
7897 if (pszFunEnd)
7898 {
7899 /*
7900 * Ok, it's a function call.
7901 */
7902 if (fExternal)
7903 pszExpr++, cchExpr--;
7904 PCDBGCCMD pFun = dbgcRoutineLookup(pDbgc, pszExpr, pszFunEnd - pszExpr, fExternal);
7905 if (!pFun)
7906 return VERR_PARSE_FUNCTION_NOT_FOUND;
7907 if (!pFun->pResultDesc)
7908 return VERR_PARSE_NOT_A_FUNCTION;
7909
7910 /*
7911 * Parse the expression in parenthesis.
7912 */
7913 cchExpr -= pszFunEnd - pszExpr;
7914 pszExpr = pszFunEnd;
7915 /** @todo implement multiple arguments. */
7916 DBGCVAR Arg;
7917 rc = dbgcEvalSub(pDbgc, pszExpr, cchExpr, &Arg);
7918 if (!rc)
7919 {
7920 rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
7921 if (!rc)
7922 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, &Arg, 1, pResult);
7923 }
7924 else if (rc == VERR_PARSE_EMPTY_ARGUMENT && pFun->cArgsMin == 0)
7925 rc = pFun->pfnHandler(pFun, &pDbgc->CmdHlp, pDbgc->pVM, NULL, 0, pResult);
7926 }
7927 else
7928 {
7929 /*
7930 * Didn't find any operators, so it must be a plain expression.
7931 * This might be numeric or a string expression.
7932 */
7933 char ch = pszExpr[0];
7934 char ch2 = pszExpr[1];
7935 if (ch == '0' && (ch2 == 'x' || ch2 == 'X'))
7936 rc = dbgcEvalSubNum(pszExpr + 2, 16, pResult);
7937 else if (ch == '0' && (ch2 == 'i' || ch2 == 'i'))
7938 rc = dbgcEvalSubNum(pszExpr + 2, 10, pResult);
7939 else if (ch == '0' && (ch2 == 't' || ch2 == 'T'))
7940 rc = dbgcEvalSubNum(pszExpr + 2, 8, pResult);
7941 else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
7942 rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
7943 else
7944 {
7945 /*
7946 * Hexadecimal number or a string?
7947 */
7948 char *psz = pszExpr;
7949 while (isxdigit(*psz))
7950 psz++;
7951 if (!*psz)
7952 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7953 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
7954 {
7955 *psz = '\0';
7956 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7957 }
7958 else
7959 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7960 }
7961 }
7962 }
7963
7964 return rc;
7965}
7966
7967
7968/**
7969 * Evaluates one argument.
7970 *
7971 * @returns 0 on success. pResult contains the result.
7972 * @returns VBox error code on parse or other evaluation error.
7973 *
7974 * @param pDbgc Debugger console instance data.
7975 * @param pszExpr The expression string.
7976 * @param pResult Where to store the result of the expression evaluation.
7977 */
7978static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
7979{
7980 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7981 /*
7982 * First we need to remove blanks in both ends.
7983 * ASSUMES: There is no quoting unless the entire expression is a string.
7984 */
7985
7986 /* stripping. */
7987 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
7988 pszExpr[--cchExpr] = '\0';
7989 while (isblank(*pszExpr))
7990 pszExpr++, cchExpr--;
7991 if (!*pszExpr)
7992 return VERR_PARSE_EMPTY_ARGUMENT;
7993
7994 /* it there is any kind of quoting in the expression, it's string meat. */
7995 if (strpbrk(pszExpr, "\"'`"))
7996 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7997
7998 /*
7999 * Check if there are any parenthesis which needs removing.
8000 */
8001 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
8002 {
8003 do
8004 {
8005 unsigned cPar = 1;
8006 char *psz = pszExpr + 1;
8007 char ch;
8008 while ((ch = *psz) != '\0')
8009 {
8010 if (ch == '(')
8011 cPar++;
8012 else if (ch == ')')
8013 {
8014 if (cPar <= 0)
8015 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8016 cPar--;
8017 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
8018 break;
8019 }
8020 /* next */
8021 psz++;
8022 }
8023 if (ch)
8024 break;
8025
8026 /* remove the parenthesis. */
8027 pszExpr++;
8028 cchExpr -= 2;
8029 pszExpr[cchExpr] = '\0';
8030
8031 /* strip blanks. */
8032 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
8033 pszExpr[--cchExpr] = '\0';
8034 while (isblank(*pszExpr))
8035 pszExpr++, cchExpr--;
8036 if (!*pszExpr)
8037 return VERR_PARSE_EMPTY_ARGUMENT;
8038 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
8039 }
8040
8041 /* tabs to spaces. */
8042 char *psz = pszExpr;
8043 while ((psz = strchr(psz, '\t')) != NULL)
8044 *psz = ' ';
8045
8046 /*
8047 * Now, we need to look for the binary operator with the lowest precedence.
8048 *
8049 * If there are no operators we're left with a simple expression which we
8050 * evaluate with respect to unary operators
8051 */
8052 char *pszOpSplit = NULL;
8053 PCDBGCOP pOpSplit = NULL;
8054 unsigned cBinaryOps = 0;
8055 unsigned cPar = 0;
8056 char ch;
8057 char chPrev = ' ';
8058 bool fBinary = false;
8059 psz = pszExpr;
8060
8061 while ((ch = *psz) != '\0')
8062 {
8063 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
8064 /*
8065 * Parenthesis.
8066 */
8067 if (ch == '(')
8068 {
8069 cPar++;
8070 fBinary = false;
8071 }
8072 else if (ch == ')')
8073 {
8074 if (cPar <= 0)
8075 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8076 cPar--;
8077 fBinary = true;
8078 }
8079 /*
8080 * Potential operator.
8081 */
8082 else if (cPar == 0 && !isblank(ch))
8083 {
8084 PCDBGCOP pOp = dbgcIsOpChar(ch)
8085 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
8086 : NULL;
8087 if (pOp)
8088 {
8089 /* If not the right kind of operator we've got a syntax error. */
8090 if (pOp->fBinary != fBinary)
8091 return VERR_PARSE_UNEXPECTED_OPERATOR;
8092
8093 /*
8094 * Update the parse state and skip the operator.
8095 */
8096 if (!pOpSplit)
8097 {
8098 pOpSplit = pOp;
8099 pszOpSplit = psz;
8100 cBinaryOps = fBinary;
8101 }
8102 else if (fBinary)
8103 {
8104 cBinaryOps++;
8105 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
8106 {
8107 pOpSplit = pOp;
8108 pszOpSplit = psz;
8109 }
8110 }
8111
8112 psz += pOp->cchName - 1;
8113 fBinary = false;
8114 }
8115 else
8116 fBinary = true;
8117 }
8118
8119 /* next */
8120 psz++;
8121 chPrev = ch;
8122 } /* parse loop. */
8123
8124
8125 /*
8126 * Either we found an operator to divide the expression by
8127 * or we didn't find any. In the first case it's divide and
8128 * conquer. In the latter it's a single expression which
8129 * needs dealing with its unary operators if any.
8130 */
8131 int rc;
8132 if ( cBinaryOps
8133 && pOpSplit->fBinary)
8134 {
8135 /* process 1st sub expression. */
8136 *pszOpSplit = '\0';
8137 DBGCVAR Arg1;
8138 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
8139 if (VBOX_SUCCESS(rc))
8140 {
8141 /* process 2nd sub expression. */
8142 char *psz2 = pszOpSplit + pOpSplit->cchName;
8143 DBGCVAR Arg2;
8144 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
8145 if (VBOX_SUCCESS(rc))
8146 /* apply the operator. */
8147 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
8148 }
8149 }
8150 else if (cBinaryOps)
8151 {
8152 /* process sub expression. */
8153 pszOpSplit += pOpSplit->cchName;
8154 DBGCVAR Arg;
8155 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
8156 if (VBOX_SUCCESS(rc))
8157 /* apply the operator. */
8158 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
8159 }
8160 else
8161 /* plain expression or using unary operators perhaps with paratheses. */
8162 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
8163
8164 return rc;
8165}
8166
8167
8168/**
8169 * Parses the arguments of one command.
8170 *
8171 * @returns 0 on success.
8172 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
8173 * @param pDbgc Debugger console instance data.
8174 * @param pCmd Pointer to the command descriptor.
8175 * @param pszArg Pointer to the arguments to parse.
8176 * @param paArgs Where to store the parsed arguments.
8177 * @param cArgs Size of the paArgs array.
8178 * @param pcArgs Where to store the number of arguments.
8179 * In the event of an error this is used to store the index of the offending argument.
8180 */
8181static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
8182{
8183 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
8184 /*
8185 * Check if we have any argument and if the command takes any.
8186 */
8187 *pcArgs = 0;
8188 /* strip leading blanks. */
8189 while (*pszArgs && isblank(*pszArgs))
8190 pszArgs++;
8191 if (!*pszArgs)
8192 {
8193 if (!pCmd->cArgsMin)
8194 return 0;
8195 return VERR_PARSE_TOO_FEW_ARGUMENTS;
8196 }
8197 /** @todo fixme - foo() doesn't work. */
8198 if (!pCmd->cArgsMax)
8199 return VERR_PARSE_TOO_MANY_ARGUMENTS;
8200
8201 /*
8202 * This is a hack, it's "temporary" and should go away "when" the parser is
8203 * modified to match arguments while parsing.
8204 */
8205 if ( pCmd->cArgsMax == 1
8206 && pCmd->cArgsMin == 1
8207 && pCmd->cArgDescs == 1
8208 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
8209 && cArgs >= 1)
8210 {
8211 *pcArgs = 1;
8212 RTStrStripR(pszArgs);
8213 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
8214 }
8215
8216
8217 /*
8218 * The parse loop.
8219 */
8220 PDBGCVAR pArg0 = &paArgs[0];
8221 PDBGCVAR pArg = pArg0;
8222 *pcArgs = 0;
8223 do
8224 {
8225 /*
8226 * Can we have another argument?
8227 */
8228 if (*pcArgs >= pCmd->cArgsMax)
8229 return VERR_PARSE_TOO_MANY_ARGUMENTS;
8230 if (pArg >= &paArgs[cArgs])
8231 return VERR_PARSE_ARGUMENT_OVERFLOW;
8232
8233 /*
8234 * Find the end of the argument.
8235 */
8236 int cPar = 0;
8237 char chQuote = '\0';
8238 char *pszEnd = NULL;
8239 char *psz = pszArgs;
8240 char ch;
8241 bool fBinary = false;
8242 for (;;)
8243 {
8244 /*
8245 * Check for the end.
8246 */
8247 if ((ch = *psz) == '\0')
8248 {
8249 if (chQuote)
8250 return VERR_PARSE_UNBALANCED_QUOTE;
8251 if (cPar)
8252 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8253 pszEnd = psz;
8254 break;
8255 }
8256 /*
8257 * When quoted we ignore everything but the quotation char.
8258 * We use the REXX way of escaping the quotation char, i.e. double occurence.
8259 */
8260 else if (ch == '\'' || ch == '"' || ch == '`')
8261 {
8262 if (chQuote)
8263 {
8264 /* end quote? */
8265 if (ch == chQuote)
8266 {
8267 if (psz[1] == ch)
8268 psz++; /* skip the escaped quote char */
8269 else
8270 chQuote = '\0'; /* end of quoted string. */
8271 }
8272 }
8273 else
8274 chQuote = ch; /* open new quote */
8275 }
8276 /*
8277 * Parenthesis can of course be nested.
8278 */
8279 else if (ch == '(')
8280 {
8281 cPar++;
8282 fBinary = false;
8283 }
8284 else if (ch == ')')
8285 {
8286 if (!cPar)
8287 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8288 cPar--;
8289 fBinary = true;
8290 }
8291 else if (!chQuote && !cPar)
8292 {
8293 /*
8294 * Encountering blanks may mean the end of it all. A binary operator
8295 * will force continued parsing.
8296 */
8297 if (isblank(*psz))
8298 {
8299 pszEnd = psz++; /* just in case. */
8300 while (isblank(*psz))
8301 psz++;
8302 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
8303 if (!pOp || pOp->fBinary != fBinary)
8304 break; /* the end. */
8305 psz += pOp->cchName;
8306 while (isblank(*psz)) /* skip blanks so we don't get here again */
8307 psz++;
8308 fBinary = false;
8309 continue;
8310 }
8311
8312 /*
8313 * Look for operators without a space up front.
8314 */
8315 if (dbgcIsOpChar(*psz))
8316 {
8317 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
8318 if (pOp)
8319 {
8320 if (pOp->fBinary != fBinary)
8321 break; /* the end. */
8322 psz += pOp->cchName;
8323 while (isblank(*psz)) /* skip blanks so we don't get here again */
8324 psz++;
8325 fBinary = false;
8326 continue;
8327 }
8328 fBinary = true;
8329 }
8330 }
8331
8332 /* next char */
8333 psz++;
8334 }
8335 *pszEnd = '\0';
8336 /* (psz = next char to process) */
8337
8338 /*
8339 * Parse and evaluate the argument.
8340 */
8341 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
8342 if (VBOX_FAILURE(rc))
8343 return rc;
8344
8345 /*
8346 * Next.
8347 */
8348 pArg++;
8349 (*pcArgs)++;
8350 pszArgs = psz;
8351 while (*pszArgs && isblank(*pszArgs))
8352 pszArgs++;
8353 } while (*pszArgs);
8354
8355 /*
8356 * Match the arguments.
8357 */
8358 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
8359}
8360
8361
8362/**
8363 * Process one command.
8364 *
8365 * @returns VBox status code. Any error indicates the termination of the console session.
8366 * @param pDbgc Debugger console instance data.
8367 * @param pszCmd Pointer to the command.
8368 * @param cchCmd Length of the command.
8369 */
8370static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
8371{
8372 char *pszCmdInput = pszCmd;
8373
8374 /*
8375 * Skip blanks.
8376 */
8377 while (isblank(*pszCmd))
8378 pszCmd++, cchCmd--;
8379
8380 /* external command? */
8381 bool fExternal = *pszCmd == '.';
8382 if (fExternal)
8383 pszCmd++, cchCmd--;
8384
8385 /*
8386 * Find arguments.
8387 */
8388 char *pszArgs = pszCmd;
8389 while (isalnum(*pszArgs))
8390 pszArgs++;
8391 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
8392 {
8393 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
8394 return 0;
8395 }
8396
8397 /*
8398 * Find the command.
8399 */
8400 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
8401 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
8402 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
8403
8404 /*
8405 * Parse arguments (if any).
8406 */
8407 unsigned cArgs;
8408 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
8409
8410 /*
8411 * Execute the command.
8412 */
8413 if (!rc)
8414 {
8415 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
8416 }
8417 else
8418 {
8419 /* report parse / eval error. */
8420 switch (rc)
8421 {
8422 case VERR_PARSE_TOO_FEW_ARGUMENTS:
8423 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8424 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
8425 break;
8426 case VERR_PARSE_TOO_MANY_ARGUMENTS:
8427 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8428 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
8429 break;
8430 case VERR_PARSE_ARGUMENT_OVERFLOW:
8431 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8432 "Syntax error: Too many arguments.\n");
8433 break;
8434 case VERR_PARSE_UNBALANCED_QUOTE:
8435 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8436 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
8437 break;
8438 case VERR_PARSE_UNBALANCED_PARENTHESIS:
8439 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8440 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
8441 break;
8442 case VERR_PARSE_EMPTY_ARGUMENT:
8443 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8444 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
8445 break;
8446 case VERR_PARSE_UNEXPECTED_OPERATOR:
8447 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8448 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
8449 break;
8450 case VERR_PARSE_INVALID_NUMBER:
8451 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8452 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
8453 break;
8454 case VERR_PARSE_NUMBER_TOO_BIG:
8455 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8456 "Error: Numeric overflow (argument %d).\n", cArgs);
8457 break;
8458 case VERR_PARSE_INVALID_OPERATION:
8459 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8460 "Error: Invalid operation attempted (argument %d).\n", cArgs);
8461 break;
8462 case VERR_PARSE_FUNCTION_NOT_FOUND:
8463 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8464 "Error: Function not found (argument %d).\n", cArgs);
8465 break;
8466 case VERR_PARSE_NOT_A_FUNCTION:
8467 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8468 "Error: The function specified is not a function (argument %d).\n", cArgs);
8469 break;
8470 case VERR_PARSE_NO_MEMORY:
8471 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8472 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
8473 break;
8474 case VERR_PARSE_INCORRECT_ARG_TYPE:
8475 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8476 "Error: Incorrect argument type (argument %d?).\n", cArgs);
8477 break;
8478 case VERR_PARSE_VARIABLE_NOT_FOUND:
8479 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8480 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
8481 break;
8482 case VERR_PARSE_CONVERSION_FAILED:
8483 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8484 "Error: A conversion between two types failed (argument %d).\n", cArgs);
8485 break;
8486 case VERR_PARSE_NOT_IMPLEMENTED:
8487 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8488 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
8489 break;
8490 case VERR_PARSE_BAD_RESULT_TYPE:
8491 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8492 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
8493 break;
8494 case VERR_PARSE_WRITEONLY_SYMBOL:
8495 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8496 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
8497 break;
8498
8499 default:
8500 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8501 "Error: Unknown error %d!\n", rc);
8502 return rc;
8503 }
8504
8505 /*
8506 * Parse errors are non fatal.
8507 */
8508 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
8509 rc = 0;
8510 }
8511
8512 return rc;
8513}
8514
8515
8516/**
8517 * Process all commands current in the buffer.
8518 *
8519 * @returns VBox status code. Any error indicates the termination of the console session.
8520 * @param pDbgc Debugger console instance data.
8521 */
8522static int dbgcProcessCommands(PDBGC pDbgc)
8523{
8524 int rc = 0;
8525 while (pDbgc->cInputLines)
8526 {
8527 /*
8528 * Empty the log buffer if we're hooking the log.
8529 */
8530 if (pDbgc->fLog)
8531 {
8532 rc = dbgcProcessLog(pDbgc);
8533 if (VBOX_FAILURE(rc))
8534 break;
8535 }
8536
8537 if (pDbgc->iRead == pDbgc->iWrite)
8538 {
8539 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
8540 pDbgc->cInputLines = 0;
8541 return 0;
8542 }
8543
8544 /*
8545 * Copy the command to the parse buffer.
8546 */
8547 char ch;
8548 char *psz = &pDbgc->achInput[pDbgc->iRead];
8549 char *pszTrg = &pDbgc->achScratch[0];
8550 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
8551 {
8552 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
8553 psz = &pDbgc->achInput[0];
8554
8555 if (psz == &pDbgc->achInput[pDbgc->iWrite])
8556 {
8557 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
8558 pDbgc->cInputLines = 0;
8559 return 0;
8560 }
8561
8562 pszTrg++;
8563 }
8564 *pszTrg = '\0';
8565
8566 /*
8567 * Advance the buffer.
8568 */
8569 pDbgc->iRead = psz - &pDbgc->achInput[0];
8570 if (ch == '\n')
8571 pDbgc->cInputLines--;
8572
8573 /*
8574 * Parse and execute this command.
8575 */
8576 pDbgc->pszScratch = psz;
8577 pDbgc->iArg = 0;
8578 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
8579 if (rc)
8580 break;
8581 }
8582
8583 return rc;
8584}
8585
8586
8587/**
8588 * Reads input, parses it and executes commands on '\n'.
8589 *
8590 * @returns VBox status.
8591 * @param pDbgc Debugger console instance data.
8592 */
8593static int dbgcProcessInput(PDBGC pDbgc)
8594{
8595 /*
8596 * We know there's input ready, so let's read it first.
8597 */
8598 int rc = dbgcInputRead(pDbgc);
8599 if (VBOX_FAILURE(rc))
8600 return rc;
8601
8602 /*
8603 * Now execute any ready commands.
8604 */
8605 if (pDbgc->cInputLines)
8606 {
8607 /** @todo this fReady stuff is broken. */
8608 pDbgc->fReady = false;
8609 rc = dbgcProcessCommands(pDbgc);
8610 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
8611 pDbgc->fReady = true;
8612 if ( VBOX_SUCCESS(rc)
8613 && pDbgc->iRead == pDbgc->iWrite
8614 && pDbgc->fReady)
8615 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
8616 }
8617
8618 return rc;
8619}
8620
8621
8622/**
8623 * Gets the event context identifier string.
8624 * @returns Read only string.
8625 * @param enmCtx The context.
8626 */
8627static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
8628{
8629 switch (enmCtx)
8630 {
8631 case DBGFEVENTCTX_RAW: return "raw";
8632 case DBGFEVENTCTX_REM: return "rem";
8633 case DBGFEVENTCTX_HWACCL: return "hwaccl";
8634 case DBGFEVENTCTX_HYPER: return "hyper";
8635 case DBGFEVENTCTX_OTHER: return "other";
8636
8637 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
8638 default:
8639 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
8640 return "!Unknown Event Ctx!";
8641 }
8642}
8643
8644
8645/**
8646 * Processes debugger events.
8647 *
8648 * @returns VBox status.
8649 * @param pDbgc DBGC Instance data.
8650 * @param pEvent Pointer to event data.
8651 */
8652static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
8653{
8654 /*
8655 * Flush log first.
8656 */
8657 if (pDbgc->fLog)
8658 {
8659 int rc = dbgcProcessLog(pDbgc);
8660 if (VBOX_FAILURE(rc))
8661 return rc;
8662 }
8663
8664 /*
8665 * Process the event.
8666 */
8667 pDbgc->pszScratch = &pDbgc->achInput[0];
8668 pDbgc->iArg = 0;
8669 bool fPrintPrompt = true;
8670 int rc = VINF_SUCCESS;
8671 switch (pEvent->enmType)
8672 {
8673 /*
8674 * The first part is events we have initiated with commands.
8675 */
8676 case DBGFEVENT_HALT_DONE:
8677 {
8678 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
8679 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
8680 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
8681 if (VBOX_SUCCESS(rc))
8682 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8683 break;
8684 }
8685
8686
8687 /*
8688 * The second part is events which can occur at any time.
8689 */
8690 case DBGFEVENT_FATAL_ERROR:
8691 {
8692 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
8693 dbgcGetEventCtx(pEvent->enmCtx));
8694 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
8695 if (VBOX_SUCCESS(rc))
8696 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8697 break;
8698 }
8699
8700 case DBGFEVENT_BREAKPOINT:
8701 case DBGFEVENT_BREAKPOINT_HYPER:
8702 {
8703 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
8704 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
8705
8706 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
8707 switch (rc)
8708 {
8709 case VERR_DBGC_BP_NOT_FOUND:
8710 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
8711 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8712 break;
8713
8714 case VINF_DBGC_BP_NO_COMMAND:
8715 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
8716 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8717 break;
8718
8719 case VINF_BUFFER_OVERFLOW:
8720 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
8721 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8722 break;
8723
8724 default:
8725 break;
8726 }
8727 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
8728 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8729 else
8730 pDbgc->fRegCtxGuest = fRegCtxGuest;
8731 break;
8732 }
8733
8734 case DBGFEVENT_STEPPED:
8735 case DBGFEVENT_STEPPED_HYPER:
8736 {
8737 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
8738
8739 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
8740 if (VBOX_SUCCESS(rc))
8741 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8742 break;
8743 }
8744
8745 case DBGFEVENT_ASSERTION_HYPER:
8746 {
8747 pDbgc->fRegCtxGuest = false;
8748
8749 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8750 "\ndbgf event: Hypervisor Assertion! (%s)\n"
8751 "%s"
8752 "%s"
8753 "\n",
8754 dbgcGetEventCtx(pEvent->enmCtx),
8755 pEvent->u.Assert.pszMsg1,
8756 pEvent->u.Assert.pszMsg2);
8757 if (VBOX_SUCCESS(rc))
8758 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8759 break;
8760 }
8761
8762 case DBGFEVENT_DEV_STOP:
8763 {
8764 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8765 "\n"
8766 "dbgf event: DBGFSTOP (%s)\n"
8767 "File: %s\n"
8768 "Line: %d\n"
8769 "Function: %s\n",
8770 dbgcGetEventCtx(pEvent->enmCtx),
8771 pEvent->u.Src.pszFile,
8772 pEvent->u.Src.uLine,
8773 pEvent->u.Src.pszFunction);
8774 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
8775 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8776 "Message: %s\n",
8777 pEvent->u.Src.pszMessage);
8778 if (VBOX_SUCCESS(rc))
8779 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8780 break;
8781 }
8782
8783
8784 case DBGFEVENT_INVALID_COMMAND:
8785 {
8786 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
8787 fPrintPrompt = !pDbgc->fReady;
8788 break;
8789 }
8790
8791 case DBGFEVENT_TERMINATING:
8792 {
8793 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
8794 rc = VERR_GENERAL_FAILURE;
8795 break;
8796 }
8797
8798
8799 default:
8800 {
8801 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
8802 fPrintPrompt = !pDbgc->fReady;
8803 break;
8804 }
8805 }
8806
8807 /*
8808 * Prompt, anyone?
8809 */
8810 if (fPrintPrompt && VBOX_SUCCESS(rc))
8811 {
8812 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
8813 }
8814
8815 return rc;
8816}
8817
8818
8819
8820
8821
8822/**
8823 * Make a console instance.
8824 *
8825 * This will not return until either an 'exit' command is issued or a error code
8826 * indicating connection loss is encountered.
8827 *
8828 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
8829 * @returns The VBox status code causing the console termination.
8830 *
8831 * @param pVM VM Handle.
8832 * @param pBack Pointer to the backend structure. This must contain
8833 * a full set of function pointers to service the console.
8834 * @param fFlags Reserved, must be zero.
8835 * @remark A forced termination of the console is easiest done by forcing the
8836 * callbacks to return fatal failures.
8837 */
8838DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
8839{
8840 /*
8841 * Validate input.
8842 */
8843 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
8844 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
8845 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
8846
8847 /*
8848 * Allocate and initialize instance data
8849 */
8850 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
8851 if (!pDbgc)
8852 return VERR_NO_MEMORY;
8853
8854 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;
8855 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;
8856 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;
8857 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
8858 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;
8859 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;
8860 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;
8861 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;
8862 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;
8863 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
8864 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
8865 pDbgc->pBack = pBack;
8866 pDbgc->pszScratch = &pDbgc->achScratch[0];
8867 pDbgc->fRegTerse = true;
8868 pDbgc->fRegCtxGuest = true;
8869 pDbgc->fLog = false;
8870 pDbgc->iRead = 0;
8871 pDbgc->iWrite = 0;
8872 pDbgc->fReady = true;
8873 pDbgc->fInputOverflow = false;
8874 pDbgc->cInputLines = 0;
8875
8876 dbgcInitOpCharBitMap();
8877
8878 /*
8879 * Print welcome message.
8880 */
8881 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8882 "Welcome to the VirtualBox Debugger!\n");
8883 if (VBOX_FAILURE(rc))
8884 goto l_failure;
8885
8886 /*
8887 * Attach to the VM.
8888 */
8889 rc = DBGFR3Attach(pVM);
8890 if (VBOX_FAILURE(rc))
8891 {
8892 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
8893 goto l_failure;
8894 }
8895 pDbgc->pVM = pVM;
8896
8897 /*
8898 * Print commandline and auto select result.
8899 */
8900 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8901 "Current VM is %08x\n" /** @todo get and print the VM name! */
8902 "VBoxDbg> ",
8903 pDbgc->pVM);
8904 if (VBOX_FAILURE(rc))
8905 goto l_failure;
8906
8907 /*
8908 * Main Debugger Loop.
8909 *
8910 * This loop will either block on waiting for input or on waiting on
8911 * debug events. If we're forwarding the log we cannot wait for long
8912 * before we must flush the log.
8913 */
8914 for (rc = 0;;)
8915 {
8916 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
8917 {
8918 /*
8919 * Wait for a debug event.
8920 */
8921 PCDBGFEVENT pEvent;
8922 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
8923 if (VBOX_SUCCESS(rc))
8924 {
8925 rc = dbgcProcessEvent(pDbgc, pEvent);
8926 if (VBOX_FAILURE(rc))
8927 break;
8928 }
8929 else if (rc != VERR_TIMEOUT)
8930 break;
8931
8932 /*
8933 * Check for input.
8934 */
8935 if (pBack->pfnInput(pDbgc->pBack, 0))
8936 {
8937 rc = dbgcProcessInput(pDbgc);
8938 if (VBOX_FAILURE(rc))
8939 break;
8940 }
8941 }
8942 else
8943 {
8944 /*
8945 * Wait for input. If Logging is enabled we'll only wait very briefly.
8946 */
8947 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
8948 {
8949 rc = dbgcProcessInput(pDbgc);
8950 if (VBOX_FAILURE(rc))
8951 break;
8952 }
8953 }
8954
8955 /*
8956 * Forward log output.
8957 */
8958 if (pDbgc->fLog)
8959 {
8960 rc = dbgcProcessLog(pDbgc);
8961 if (VBOX_FAILURE(rc))
8962 break;
8963 }
8964 }
8965
8966
8967l_failure:
8968 /*
8969 * Cleanup console debugger session.
8970 */
8971 /* Disable log hook. */
8972 if (pDbgc->fLog)
8973 {
8974
8975 }
8976
8977 /* Detach from the VM. */
8978 if (pDbgc->pVM)
8979 DBGFR3Detach(pDbgc->pVM);
8980
8981 /* finally, free the instance memory. */
8982 RTMemFree(pDbgc);
8983
8984 return rc;
8985}
8986
8987
8988
8989/**
8990 * Register one or more external commands.
8991 *
8992 * @returns VBox status.
8993 * @param paCommands Pointer to an array of command descriptors.
8994 * The commands must be unique. It's not possible
8995 * to register the same commands more than once.
8996 * @param cCommands Number of commands.
8997 */
8998DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
8999{
9000 /*
9001 * Lock the list.
9002 */
9003 DBGCEXTCMDS_LOCK_WR();
9004 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
9005 while (pCur)
9006 {
9007 if (paCommands == pCur->paCmds)
9008 {
9009 DBGCEXTCMDS_UNLOCK_WR();
9010 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
9011 return VWRN_DBGC_ALREADY_REGISTERED;
9012 }
9013 pCur = pCur->pNext;
9014 }
9015
9016 /*
9017 * Allocate new chunk.
9018 */
9019 int rc = 0;
9020 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
9021 if (pCur)
9022 {
9023 pCur->cCmds = cCommands;
9024 pCur->paCmds = paCommands;
9025 pCur->pNext = g_pExtCmdsHead;
9026 g_pExtCmdsHead = pCur;
9027 }
9028 else
9029 rc = VERR_NO_MEMORY;
9030 DBGCEXTCMDS_UNLOCK_WR();
9031
9032 return rc;
9033}
9034
9035
9036/**
9037 * Deregister one or more external commands previously registered by
9038 * DBGCRegisterCommands().
9039 *
9040 * @returns VBox status.
9041 * @param paCommands Pointer to an array of command descriptors
9042 * as given to DBGCRegisterCommands().
9043 * @param cCommands Number of commands.
9044 */
9045DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
9046{
9047 /*
9048 * Lock the list.
9049 */
9050 DBGCEXTCMDS_LOCK_WR();
9051 PDBGCEXTCMDS pPrev = NULL;
9052 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
9053 while (pCur)
9054 {
9055 if (paCommands == pCur->paCmds)
9056 {
9057 if (pPrev)
9058 pPrev->pNext = pCur->pNext;
9059 else
9060 g_pExtCmdsHead = pCur->pNext;
9061 DBGCEXTCMDS_UNLOCK_WR();
9062
9063 RTMemFree(pCur);
9064 return VINF_SUCCESS;
9065 }
9066 pPrev = pCur;
9067 pCur = pCur->pNext;
9068 }
9069 DBGCEXTCMDS_UNLOCK_WR();
9070
9071 NOREF(cCommands);
9072 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
9073}
9074
Note: See TracBrowser for help on using the repository browser.

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