VirtualBox

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

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

Debugged runscript. Found problem with using 0b as prefix for binary numbers, so I've disabled that stuff for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 333.2 KB
Line 
1/** $Id: DBGConsole.cpp 4253 2007-08-21 00:28:09Z 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", psz);
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 /// @todo 0b doesn't work as a binary prefix, we confuse it with 0bf8:0123 and stuff.
7942 //else if (ch == '0' && (ch2 == 'b' || ch2 == 'b'))
7943 // rc = dbgcEvalSubNum(pszExpr + 2, 2, pResult);
7944 else
7945 {
7946 /*
7947 * Hexadecimal number or a string?
7948 */
7949 char *psz = pszExpr;
7950 while (isxdigit(*psz))
7951 psz++;
7952 if (!*psz)
7953 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7954 else if ((*psz == 'h' || *psz == 'H') && !psz[1])
7955 {
7956 *psz = '\0';
7957 rc = dbgcEvalSubNum(pszExpr, 16, pResult);
7958 }
7959 else
7960 rc = dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7961 }
7962 }
7963 }
7964
7965 return rc;
7966}
7967
7968
7969/**
7970 * Evaluates one argument.
7971 *
7972 * @returns 0 on success. pResult contains the result.
7973 * @returns VBox error code on parse or other evaluation error.
7974 *
7975 * @param pDbgc Debugger console instance data.
7976 * @param pszExpr The expression string.
7977 * @param pResult Where to store the result of the expression evaluation.
7978 */
7979static int dbgcEvalSub(PDBGC pDbgc, char *pszExpr, size_t cchExpr, PDBGCVAR pResult)
7980{
7981 Log2(("dbgcEvalSub: cchExpr=%d pszExpr=%s\n", cchExpr, pszExpr));
7982 /*
7983 * First we need to remove blanks in both ends.
7984 * ASSUMES: There is no quoting unless the entire expression is a string.
7985 */
7986
7987 /* stripping. */
7988 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
7989 pszExpr[--cchExpr] = '\0';
7990 while (isblank(*pszExpr))
7991 pszExpr++, cchExpr--;
7992 if (!*pszExpr)
7993 return VERR_PARSE_EMPTY_ARGUMENT;
7994
7995 /* it there is any kind of quoting in the expression, it's string meat. */
7996 if (strpbrk(pszExpr, "\"'`"))
7997 return dbgcEvalSubString(pDbgc, pszExpr, cchExpr, pResult);
7998
7999 /*
8000 * Check if there are any parenthesis which needs removing.
8001 */
8002 if (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')')
8003 {
8004 do
8005 {
8006 unsigned cPar = 1;
8007 char *psz = pszExpr + 1;
8008 char ch;
8009 while ((ch = *psz) != '\0')
8010 {
8011 if (ch == '(')
8012 cPar++;
8013 else if (ch == ')')
8014 {
8015 if (cPar <= 0)
8016 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8017 cPar--;
8018 if (cPar == 0 && psz[1]) /* If not at end, there's nothing to do. */
8019 break;
8020 }
8021 /* next */
8022 psz++;
8023 }
8024 if (ch)
8025 break;
8026
8027 /* remove the parenthesis. */
8028 pszExpr++;
8029 cchExpr -= 2;
8030 pszExpr[cchExpr] = '\0';
8031
8032 /* strip blanks. */
8033 while (cchExpr > 0 && isblank(pszExpr[cchExpr - 1]))
8034 pszExpr[--cchExpr] = '\0';
8035 while (isblank(*pszExpr))
8036 pszExpr++, cchExpr--;
8037 if (!*pszExpr)
8038 return VERR_PARSE_EMPTY_ARGUMENT;
8039 } while (pszExpr[0] == '(' && pszExpr[cchExpr - 1] == ')');
8040 }
8041
8042 /* tabs to spaces. */
8043 char *psz = pszExpr;
8044 while ((psz = strchr(psz, '\t')) != NULL)
8045 *psz = ' ';
8046
8047 /*
8048 * Now, we need to look for the binary operator with the lowest precedence.
8049 *
8050 * If there are no operators we're left with a simple expression which we
8051 * evaluate with respect to unary operators
8052 */
8053 char *pszOpSplit = NULL;
8054 PCDBGCOP pOpSplit = NULL;
8055 unsigned cBinaryOps = 0;
8056 unsigned cPar = 0;
8057 char ch;
8058 char chPrev = ' ';
8059 bool fBinary = false;
8060 psz = pszExpr;
8061
8062 while ((ch = *psz) != '\0')
8063 {
8064 //Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
8065 /*
8066 * Parenthesis.
8067 */
8068 if (ch == '(')
8069 {
8070 cPar++;
8071 fBinary = false;
8072 }
8073 else if (ch == ')')
8074 {
8075 if (cPar <= 0)
8076 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8077 cPar--;
8078 fBinary = true;
8079 }
8080 /*
8081 * Potential operator.
8082 */
8083 else if (cPar == 0 && !isblank(ch))
8084 {
8085 PCDBGCOP pOp = dbgcIsOpChar(ch)
8086 ? dbgcOperatorLookup(pDbgc, psz, fBinary, chPrev)
8087 : NULL;
8088 if (pOp)
8089 {
8090 /* If not the right kind of operator we've got a syntax error. */
8091 if (pOp->fBinary != fBinary)
8092 return VERR_PARSE_UNEXPECTED_OPERATOR;
8093
8094 /*
8095 * Update the parse state and skip the operator.
8096 */
8097 if (!pOpSplit)
8098 {
8099 pOpSplit = pOp;
8100 pszOpSplit = psz;
8101 cBinaryOps = fBinary;
8102 }
8103 else if (fBinary)
8104 {
8105 cBinaryOps++;
8106 if (pOp->iPrecedence >= pOpSplit->iPrecedence)
8107 {
8108 pOpSplit = pOp;
8109 pszOpSplit = psz;
8110 }
8111 }
8112
8113 psz += pOp->cchName - 1;
8114 fBinary = false;
8115 }
8116 else
8117 fBinary = true;
8118 }
8119
8120 /* next */
8121 psz++;
8122 chPrev = ch;
8123 } /* parse loop. */
8124
8125
8126 /*
8127 * Either we found an operator to divide the expression by
8128 * or we didn't find any. In the first case it's divide and
8129 * conquer. In the latter it's a single expression which
8130 * needs dealing with its unary operators if any.
8131 */
8132 int rc;
8133 if ( cBinaryOps
8134 && pOpSplit->fBinary)
8135 {
8136 /* process 1st sub expression. */
8137 *pszOpSplit = '\0';
8138 DBGCVAR Arg1;
8139 rc = dbgcEvalSub(pDbgc, pszExpr, pszOpSplit - pszExpr, &Arg1);
8140 if (VBOX_SUCCESS(rc))
8141 {
8142 /* process 2nd sub expression. */
8143 char *psz2 = pszOpSplit + pOpSplit->cchName;
8144 DBGCVAR Arg2;
8145 rc = dbgcEvalSub(pDbgc, psz2, cchExpr - (psz2 - pszExpr), &Arg2);
8146 if (VBOX_SUCCESS(rc))
8147 /* apply the operator. */
8148 rc = pOpSplit->pfnHandlerBinary(pDbgc, &Arg1, &Arg2, pResult);
8149 }
8150 }
8151 else if (cBinaryOps)
8152 {
8153 /* process sub expression. */
8154 pszOpSplit += pOpSplit->cchName;
8155 DBGCVAR Arg;
8156 rc = dbgcEvalSub(pDbgc, pszOpSplit, cchExpr - (pszOpSplit - pszExpr), &Arg);
8157 if (VBOX_SUCCESS(rc))
8158 /* apply the operator. */
8159 rc = pOpSplit->pfnHandlerUnary(pDbgc, &Arg, pResult);
8160 }
8161 else
8162 /* plain expression or using unary operators perhaps with paratheses. */
8163 rc = dbgcEvalSubUnary(pDbgc, pszExpr, cchExpr, pResult);
8164
8165 return rc;
8166}
8167
8168
8169/**
8170 * Parses the arguments of one command.
8171 *
8172 * @returns 0 on success.
8173 * @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
8174 * @param pDbgc Debugger console instance data.
8175 * @param pCmd Pointer to the command descriptor.
8176 * @param pszArg Pointer to the arguments to parse.
8177 * @param paArgs Where to store the parsed arguments.
8178 * @param cArgs Size of the paArgs array.
8179 * @param pcArgs Where to store the number of arguments.
8180 * In the event of an error this is used to store the index of the offending argument.
8181 */
8182static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
8183{
8184 Log2(("dbgcProcessArguments: pCmd=%s pszArgs='%s'\n", pCmd->pszCmd, pszArgs));
8185 /*
8186 * Check if we have any argument and if the command takes any.
8187 */
8188 *pcArgs = 0;
8189 /* strip leading blanks. */
8190 while (*pszArgs && isblank(*pszArgs))
8191 pszArgs++;
8192 if (!*pszArgs)
8193 {
8194 if (!pCmd->cArgsMin)
8195 return 0;
8196 return VERR_PARSE_TOO_FEW_ARGUMENTS;
8197 }
8198 /** @todo fixme - foo() doesn't work. */
8199 if (!pCmd->cArgsMax)
8200 return VERR_PARSE_TOO_MANY_ARGUMENTS;
8201
8202 /*
8203 * This is a hack, it's "temporary" and should go away "when" the parser is
8204 * modified to match arguments while parsing.
8205 */
8206 if ( pCmd->cArgsMax == 1
8207 && pCmd->cArgsMin == 1
8208 && pCmd->cArgDescs == 1
8209 && pCmd->paArgDescs[0].enmCategory == DBGCVAR_CAT_STRING
8210 && cArgs >= 1)
8211 {
8212 *pcArgs = 1;
8213 RTStrStripR(pszArgs);
8214 return dbgcEvalSubString(pDbgc, pszArgs, strlen(pszArgs), &paArgs[0]);
8215 }
8216
8217
8218 /*
8219 * The parse loop.
8220 */
8221 PDBGCVAR pArg0 = &paArgs[0];
8222 PDBGCVAR pArg = pArg0;
8223 *pcArgs = 0;
8224 do
8225 {
8226 /*
8227 * Can we have another argument?
8228 */
8229 if (*pcArgs >= pCmd->cArgsMax)
8230 return VERR_PARSE_TOO_MANY_ARGUMENTS;
8231 if (pArg >= &paArgs[cArgs])
8232 return VERR_PARSE_ARGUMENT_OVERFLOW;
8233
8234 /*
8235 * Find the end of the argument.
8236 */
8237 int cPar = 0;
8238 char chQuote = '\0';
8239 char *pszEnd = NULL;
8240 char *psz = pszArgs;
8241 char ch;
8242 bool fBinary = false;
8243 for (;;)
8244 {
8245 /*
8246 * Check for the end.
8247 */
8248 if ((ch = *psz) == '\0')
8249 {
8250 if (chQuote)
8251 return VERR_PARSE_UNBALANCED_QUOTE;
8252 if (cPar)
8253 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8254 pszEnd = psz;
8255 break;
8256 }
8257 /*
8258 * When quoted we ignore everything but the quotation char.
8259 * We use the REXX way of escaping the quotation char, i.e. double occurence.
8260 */
8261 else if (ch == '\'' || ch == '"' || ch == '`')
8262 {
8263 if (chQuote)
8264 {
8265 /* end quote? */
8266 if (ch == chQuote)
8267 {
8268 if (psz[1] == ch)
8269 psz++; /* skip the escaped quote char */
8270 else
8271 chQuote = '\0'; /* end of quoted string. */
8272 }
8273 }
8274 else
8275 chQuote = ch; /* open new quote */
8276 }
8277 /*
8278 * Parenthesis can of course be nested.
8279 */
8280 else if (ch == '(')
8281 {
8282 cPar++;
8283 fBinary = false;
8284 }
8285 else if (ch == ')')
8286 {
8287 if (!cPar)
8288 return VERR_PARSE_UNBALANCED_PARENTHESIS;
8289 cPar--;
8290 fBinary = true;
8291 }
8292 else if (!chQuote && !cPar)
8293 {
8294 /*
8295 * Encountering blanks may mean the end of it all. A binary operator
8296 * will force continued parsing.
8297 */
8298 if (isblank(*psz))
8299 {
8300 pszEnd = psz++; /* just in case. */
8301 while (isblank(*psz))
8302 psz++;
8303 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
8304 if (!pOp || pOp->fBinary != fBinary)
8305 break; /* the end. */
8306 psz += pOp->cchName;
8307 while (isblank(*psz)) /* skip blanks so we don't get here again */
8308 psz++;
8309 fBinary = false;
8310 continue;
8311 }
8312
8313 /*
8314 * Look for operators without a space up front.
8315 */
8316 if (dbgcIsOpChar(*psz))
8317 {
8318 PCDBGCOP pOp = dbgcOperatorLookup(pDbgc, psz, fBinary, ' ');
8319 if (pOp)
8320 {
8321 if (pOp->fBinary != fBinary)
8322 {
8323 pszEnd = psz;
8324 /** @todo this is a parsing error really. */
8325 break; /* the end. */
8326 }
8327 psz += pOp->cchName;
8328 while (isblank(*psz)) /* skip blanks so we don't get here again */
8329 psz++;
8330 fBinary = false;
8331 continue;
8332 }
8333 }
8334 fBinary = true;
8335 }
8336
8337 /* next char */
8338 psz++;
8339 }
8340 *pszEnd = '\0';
8341 /* (psz = next char to process) */
8342
8343 /*
8344 * Parse and evaluate the argument.
8345 */
8346 int rc = dbgcEvalSub(pDbgc, pszArgs, strlen(pszArgs), pArg);
8347 if (VBOX_FAILURE(rc))
8348 return rc;
8349
8350 /*
8351 * Next.
8352 */
8353 pArg++;
8354 (*pcArgs)++;
8355 pszArgs = psz;
8356 while (*pszArgs && isblank(*pszArgs))
8357 pszArgs++;
8358 } while (*pszArgs);
8359
8360 /*
8361 * Match the arguments.
8362 */
8363 return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
8364}
8365
8366
8367/**
8368 * Process one command.
8369 *
8370 * @returns VBox status code. Any error indicates the termination of the console session.
8371 * @param pDbgc Debugger console instance data.
8372 * @param pszCmd Pointer to the command.
8373 * @param cchCmd Length of the command.
8374 */
8375static int dbgcProcessCommand(PDBGC pDbgc, char *pszCmd, size_t cchCmd)
8376{
8377 char *pszCmdInput = pszCmd;
8378
8379 /*
8380 * Skip blanks.
8381 */
8382 while (isblank(*pszCmd))
8383 pszCmd++, cchCmd--;
8384
8385 /* external command? */
8386 bool fExternal = *pszCmd == '.';
8387 if (fExternal)
8388 pszCmd++, cchCmd--;
8389
8390 /*
8391 * Find arguments.
8392 */
8393 char *pszArgs = pszCmd;
8394 while (isalnum(*pszArgs))
8395 pszArgs++;
8396 if (*pszArgs && (!isblank(*pszArgs) || pszArgs == pszCmd))
8397 {
8398 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Syntax error in command '%s'!\n", pszCmdInput);
8399 return 0;
8400 }
8401
8402 /*
8403 * Find the command.
8404 */
8405 PCDBGCCMD pCmd = dbgcRoutineLookup(pDbgc, pszCmd, pszArgs - pszCmd, fExternal);
8406 if (!pCmd || (pCmd->fFlags & DBGCCMD_FLAGS_FUNCTION))
8407 return pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "Unknown command '%s'!\n", pszCmdInput);
8408
8409 /*
8410 * Parse arguments (if any).
8411 */
8412 unsigned cArgs;
8413 int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
8414
8415 /*
8416 * Execute the command.
8417 */
8418 if (!rc)
8419 {
8420 rc = pCmd->pfnHandler(pCmd, &pDbgc->CmdHlp, pDbgc->pVM, &pDbgc->aArgs[0], cArgs, NULL);
8421 }
8422 else
8423 {
8424 /* report parse / eval error. */
8425 switch (rc)
8426 {
8427 case VERR_PARSE_TOO_FEW_ARGUMENTS:
8428 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8429 "Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
8430 break;
8431 case VERR_PARSE_TOO_MANY_ARGUMENTS:
8432 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8433 "Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
8434 break;
8435 case VERR_PARSE_ARGUMENT_OVERFLOW:
8436 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8437 "Syntax error: Too many arguments.\n");
8438 break;
8439 case VERR_PARSE_UNBALANCED_QUOTE:
8440 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8441 "Syntax error: Unbalanced quote (argument %d).\n", cArgs);
8442 break;
8443 case VERR_PARSE_UNBALANCED_PARENTHESIS:
8444 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8445 "Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
8446 break;
8447 case VERR_PARSE_EMPTY_ARGUMENT:
8448 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8449 "Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
8450 break;
8451 case VERR_PARSE_UNEXPECTED_OPERATOR:
8452 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8453 "Syntax error: Invalid operator usage (argument %d).\n", cArgs);
8454 break;
8455 case VERR_PARSE_INVALID_NUMBER:
8456 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8457 "Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
8458 break;
8459 case VERR_PARSE_NUMBER_TOO_BIG:
8460 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8461 "Error: Numeric overflow (argument %d).\n", cArgs);
8462 break;
8463 case VERR_PARSE_INVALID_OPERATION:
8464 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8465 "Error: Invalid operation attempted (argument %d).\n", cArgs);
8466 break;
8467 case VERR_PARSE_FUNCTION_NOT_FOUND:
8468 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8469 "Error: Function not found (argument %d).\n", cArgs);
8470 break;
8471 case VERR_PARSE_NOT_A_FUNCTION:
8472 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8473 "Error: The function specified is not a function (argument %d).\n", cArgs);
8474 break;
8475 case VERR_PARSE_NO_MEMORY:
8476 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8477 "Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
8478 break;
8479 case VERR_PARSE_INCORRECT_ARG_TYPE:
8480 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8481 "Error: Incorrect argument type (argument %d?).\n", cArgs);
8482 break;
8483 case VERR_PARSE_VARIABLE_NOT_FOUND:
8484 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8485 "Error: An undefined variable was referenced (argument %d).\n", cArgs);
8486 break;
8487 case VERR_PARSE_CONVERSION_FAILED:
8488 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8489 "Error: A conversion between two types failed (argument %d).\n", cArgs);
8490 break;
8491 case VERR_PARSE_NOT_IMPLEMENTED:
8492 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8493 "Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
8494 break;
8495 case VERR_PARSE_BAD_RESULT_TYPE:
8496 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8497 "Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
8498 break;
8499 case VERR_PARSE_WRITEONLY_SYMBOL:
8500 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8501 "Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
8502 break;
8503
8504 default:
8505 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8506 "Error: Unknown error %d!\n", rc);
8507 return rc;
8508 }
8509
8510 /*
8511 * Parse errors are non fatal.
8512 */
8513 if (rc >= VERR_PARSE_FIRST && rc < VERR_PARSE_LAST)
8514 rc = 0;
8515 }
8516
8517 return rc;
8518}
8519
8520
8521/**
8522 * Process all commands current in the buffer.
8523 *
8524 * @returns VBox status code. Any error indicates the termination of the console session.
8525 * @param pDbgc Debugger console instance data.
8526 */
8527static int dbgcProcessCommands(PDBGC pDbgc)
8528{
8529 int rc = 0;
8530 while (pDbgc->cInputLines)
8531 {
8532 /*
8533 * Empty the log buffer if we're hooking the log.
8534 */
8535 if (pDbgc->fLog)
8536 {
8537 rc = dbgcProcessLog(pDbgc);
8538 if (VBOX_FAILURE(rc))
8539 break;
8540 }
8541
8542 if (pDbgc->iRead == pDbgc->iWrite)
8543 {
8544 AssertMsgFailed(("The input buffer is empty while cInputLines=%d!\n", pDbgc->cInputLines));
8545 pDbgc->cInputLines = 0;
8546 return 0;
8547 }
8548
8549 /*
8550 * Copy the command to the parse buffer.
8551 */
8552 char ch;
8553 char *psz = &pDbgc->achInput[pDbgc->iRead];
8554 char *pszTrg = &pDbgc->achScratch[0];
8555 while ((*pszTrg = ch = *psz++) != ';' && ch != '\n' )
8556 {
8557 if (psz == &pDbgc->achInput[sizeof(pDbgc->achInput)])
8558 psz = &pDbgc->achInput[0];
8559
8560 if (psz == &pDbgc->achInput[pDbgc->iWrite])
8561 {
8562 AssertMsgFailed(("The buffer contains no commands while cInputLines=%d!\n", pDbgc->cInputLines));
8563 pDbgc->cInputLines = 0;
8564 return 0;
8565 }
8566
8567 pszTrg++;
8568 }
8569 *pszTrg = '\0';
8570
8571 /*
8572 * Advance the buffer.
8573 */
8574 pDbgc->iRead = psz - &pDbgc->achInput[0];
8575 if (ch == '\n')
8576 pDbgc->cInputLines--;
8577
8578 /*
8579 * Parse and execute this command.
8580 */
8581 pDbgc->pszScratch = psz;
8582 pDbgc->iArg = 0;
8583 rc = dbgcProcessCommand(pDbgc, &pDbgc->achScratch[0], psz - &pDbgc->achScratch[0] - 1);
8584 if (rc)
8585 break;
8586 }
8587
8588 return rc;
8589}
8590
8591
8592/**
8593 * Reads input, parses it and executes commands on '\n'.
8594 *
8595 * @returns VBox status.
8596 * @param pDbgc Debugger console instance data.
8597 */
8598static int dbgcProcessInput(PDBGC pDbgc)
8599{
8600 /*
8601 * We know there's input ready, so let's read it first.
8602 */
8603 int rc = dbgcInputRead(pDbgc);
8604 if (VBOX_FAILURE(rc))
8605 return rc;
8606
8607 /*
8608 * Now execute any ready commands.
8609 */
8610 if (pDbgc->cInputLines)
8611 {
8612 /** @todo this fReady stuff is broken. */
8613 pDbgc->fReady = false;
8614 rc = dbgcProcessCommands(pDbgc);
8615 if (VBOX_SUCCESS(rc) && rc != VWRN_DBGC_CMD_PENDING)
8616 pDbgc->fReady = true;
8617 if ( VBOX_SUCCESS(rc)
8618 && pDbgc->iRead == pDbgc->iWrite
8619 && pDbgc->fReady)
8620 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
8621 }
8622
8623 return rc;
8624}
8625
8626
8627/**
8628 * Gets the event context identifier string.
8629 * @returns Read only string.
8630 * @param enmCtx The context.
8631 */
8632static const char *dbgcGetEventCtx(DBGFEVENTCTX enmCtx)
8633{
8634 switch (enmCtx)
8635 {
8636 case DBGFEVENTCTX_RAW: return "raw";
8637 case DBGFEVENTCTX_REM: return "rem";
8638 case DBGFEVENTCTX_HWACCL: return "hwaccl";
8639 case DBGFEVENTCTX_HYPER: return "hyper";
8640 case DBGFEVENTCTX_OTHER: return "other";
8641
8642 case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
8643 default:
8644 AssertMsgFailed(("enmCtx=%d\n", enmCtx));
8645 return "!Unknown Event Ctx!";
8646 }
8647}
8648
8649
8650/**
8651 * Processes debugger events.
8652 *
8653 * @returns VBox status.
8654 * @param pDbgc DBGC Instance data.
8655 * @param pEvent Pointer to event data.
8656 */
8657static int dbgcProcessEvent(PDBGC pDbgc, PCDBGFEVENT pEvent)
8658{
8659 /*
8660 * Flush log first.
8661 */
8662 if (pDbgc->fLog)
8663 {
8664 int rc = dbgcProcessLog(pDbgc);
8665 if (VBOX_FAILURE(rc))
8666 return rc;
8667 }
8668
8669 /*
8670 * Process the event.
8671 */
8672 pDbgc->pszScratch = &pDbgc->achInput[0];
8673 pDbgc->iArg = 0;
8674 bool fPrintPrompt = true;
8675 int rc = VINF_SUCCESS;
8676 switch (pEvent->enmType)
8677 {
8678 /*
8679 * The first part is events we have initiated with commands.
8680 */
8681 case DBGFEVENT_HALT_DONE:
8682 {
8683 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: VM %p is halted! (%s)\n",
8684 pDbgc->pVM, dbgcGetEventCtx(pEvent->enmCtx));
8685 pDbgc->fRegCtxGuest = true; /* we're always in guest context when halted. */
8686 if (VBOX_SUCCESS(rc))
8687 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8688 break;
8689 }
8690
8691
8692 /*
8693 * The second part is events which can occur at any time.
8694 */
8695 case DBGFEVENT_FATAL_ERROR:
8696 {
8697 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbf event: Fatal error! (%s)\n",
8698 dbgcGetEventCtx(pEvent->enmCtx));
8699 pDbgc->fRegCtxGuest = false; /* fatal errors are always in hypervisor. */
8700 if (VBOX_SUCCESS(rc))
8701 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8702 break;
8703 }
8704
8705 case DBGFEVENT_BREAKPOINT:
8706 case DBGFEVENT_BREAKPOINT_HYPER:
8707 {
8708 bool fRegCtxGuest = pDbgc->fRegCtxGuest;
8709 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_BREAKPOINT;
8710
8711 rc = dbgcBpExec(pDbgc, pEvent->u.Bp.iBp);
8712 switch (rc)
8713 {
8714 case VERR_DBGC_BP_NOT_FOUND:
8715 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Unknown breakpoint %u! (%s)\n",
8716 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8717 break;
8718
8719 case VINF_DBGC_BP_NO_COMMAND:
8720 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! (%s)\n",
8721 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8722 break;
8723
8724 case VINF_BUFFER_OVERFLOW:
8725 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
8726 pEvent->u.Bp.iBp, dbgcGetEventCtx(pEvent->enmCtx));
8727 break;
8728
8729 default:
8730 break;
8731 }
8732 if (VBOX_SUCCESS(rc) && DBGFR3IsHalted(pDbgc->pVM))
8733 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8734 else
8735 pDbgc->fRegCtxGuest = fRegCtxGuest;
8736 break;
8737 }
8738
8739 case DBGFEVENT_STEPPED:
8740 case DBGFEVENT_STEPPED_HYPER:
8741 {
8742 pDbgc->fRegCtxGuest = pEvent->enmType == DBGFEVENT_STEPPED;
8743
8744 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
8745 if (VBOX_SUCCESS(rc))
8746 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8747 break;
8748 }
8749
8750 case DBGFEVENT_ASSERTION_HYPER:
8751 {
8752 pDbgc->fRegCtxGuest = false;
8753
8754 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8755 "\ndbgf event: Hypervisor Assertion! (%s)\n"
8756 "%s"
8757 "%s"
8758 "\n",
8759 dbgcGetEventCtx(pEvent->enmCtx),
8760 pEvent->u.Assert.pszMsg1,
8761 pEvent->u.Assert.pszMsg2);
8762 if (VBOX_SUCCESS(rc))
8763 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8764 break;
8765 }
8766
8767 case DBGFEVENT_DEV_STOP:
8768 {
8769 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8770 "\n"
8771 "dbgf event: DBGFSTOP (%s)\n"
8772 "File: %s\n"
8773 "Line: %d\n"
8774 "Function: %s\n",
8775 dbgcGetEventCtx(pEvent->enmCtx),
8776 pEvent->u.Src.pszFile,
8777 pEvent->u.Src.uLine,
8778 pEvent->u.Src.pszFunction);
8779 if (VBOX_SUCCESS(rc) && pEvent->u.Src.pszMessage && *pEvent->u.Src.pszMessage)
8780 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8781 "Message: %s\n",
8782 pEvent->u.Src.pszMessage);
8783 if (VBOX_SUCCESS(rc))
8784 rc = pDbgc->CmdHlp.pfnExec(&pDbgc->CmdHlp, "r");
8785 break;
8786 }
8787
8788
8789 case DBGFEVENT_INVALID_COMMAND:
8790 {
8791 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Invalid command event!\n");
8792 fPrintPrompt = !pDbgc->fReady;
8793 break;
8794 }
8795
8796 case DBGFEVENT_TERMINATING:
8797 {
8798 pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\nVM is terminating!\n");
8799 rc = VERR_GENERAL_FAILURE;
8800 break;
8801 }
8802
8803
8804 default:
8805 {
8806 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
8807 fPrintPrompt = !pDbgc->fReady;
8808 break;
8809 }
8810 }
8811
8812 /*
8813 * Prompt, anyone?
8814 */
8815 if (fPrintPrompt && VBOX_SUCCESS(rc))
8816 {
8817 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "VBoxDbg> ");
8818 }
8819
8820 return rc;
8821}
8822
8823
8824
8825
8826
8827/**
8828 * Make a console instance.
8829 *
8830 * This will not return until either an 'exit' command is issued or a error code
8831 * indicating connection loss is encountered.
8832 *
8833 * @returns VINF_SUCCESS if console termination caused by the 'exit' command.
8834 * @returns The VBox status code causing the console termination.
8835 *
8836 * @param pVM VM Handle.
8837 * @param pBack Pointer to the backend structure. This must contain
8838 * a full set of function pointers to service the console.
8839 * @param fFlags Reserved, must be zero.
8840 * @remark A forced termination of the console is easiest done by forcing the
8841 * callbacks to return fatal failures.
8842 */
8843DBGDECL(int) DBGCCreate(PVM pVM, PDBGCBACK pBack, unsigned fFlags)
8844{
8845 /*
8846 * Validate input.
8847 */
8848 AssertReturn(VALID_PTR(pVM), VERR_INVALID_PARAMETER);
8849 AssertReturn(VALID_PTR(pBack), VERR_INVALID_PARAMETER);
8850 AssertMsgReturn(!fFlags, ("%#x", fFlags), VERR_INVALID_PARAMETER);
8851
8852 /*
8853 * Allocate and initialize instance data
8854 */
8855 PDBGC pDbgc = (PDBGC)RTMemAllocZ(sizeof(*pDbgc));
8856 if (!pDbgc)
8857 return VERR_NO_MEMORY;
8858
8859 pDbgc->CmdHlp.pfnWrite = dbgcHlpWrite;
8860 pDbgc->CmdHlp.pfnPrintfV = dbgcHlpPrintfV;
8861 pDbgc->CmdHlp.pfnPrintf = dbgcHlpPrintf;
8862 pDbgc->CmdHlp.pfnVBoxErrorV = dbgcHlpVBoxErrorV;
8863 pDbgc->CmdHlp.pfnVBoxError = dbgcHlpVBoxError;
8864 pDbgc->CmdHlp.pfnMemRead = dbgcHlpMemRead;
8865 pDbgc->CmdHlp.pfnMemWrite = dbgcHlpMemWrite;
8866 pDbgc->CmdHlp.pfnEval = dbgcHlpEval;
8867 pDbgc->CmdHlp.pfnExec = dbgcHlpExec;
8868 pDbgc->CmdHlp.pfnVarToDbgfAddr = dbgcHlpVarToDbgfAddr;
8869 pDbgc->CmdHlp.pfnVarToBool = dbgcHlpVarToBool;
8870 pDbgc->pBack = pBack;
8871 pDbgc->pszScratch = &pDbgc->achScratch[0];
8872 pDbgc->fRegTerse = true;
8873 pDbgc->fRegCtxGuest = true;
8874 pDbgc->fLog = false;
8875 pDbgc->iRead = 0;
8876 pDbgc->iWrite = 0;
8877 pDbgc->fReady = true;
8878 pDbgc->fInputOverflow = false;
8879 pDbgc->cInputLines = 0;
8880
8881 dbgcInitOpCharBitMap();
8882
8883 /*
8884 * Print welcome message.
8885 */
8886 int rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8887 "Welcome to the VirtualBox Debugger!\n");
8888 if (VBOX_FAILURE(rc))
8889 goto l_failure;
8890
8891 /*
8892 * Attach to the VM.
8893 */
8894 rc = DBGFR3Attach(pVM);
8895 if (VBOX_FAILURE(rc))
8896 {
8897 rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
8898 goto l_failure;
8899 }
8900 pDbgc->pVM = pVM;
8901
8902 /*
8903 * Print commandline and auto select result.
8904 */
8905 rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL,
8906 "Current VM is %08x\n" /** @todo get and print the VM name! */
8907 "VBoxDbg> ",
8908 pDbgc->pVM);
8909 if (VBOX_FAILURE(rc))
8910 goto l_failure;
8911
8912 /*
8913 * Main Debugger Loop.
8914 *
8915 * This loop will either block on waiting for input or on waiting on
8916 * debug events. If we're forwarding the log we cannot wait for long
8917 * before we must flush the log.
8918 */
8919 for (rc = 0;;)
8920 {
8921 if (pDbgc->pVM && DBGFR3CanWait(pDbgc->pVM))
8922 {
8923 /*
8924 * Wait for a debug event.
8925 */
8926 PCDBGFEVENT pEvent;
8927 rc = DBGFR3EventWait(pDbgc->pVM, pDbgc->fLog ? 1 : 32, &pEvent);
8928 if (VBOX_SUCCESS(rc))
8929 {
8930 rc = dbgcProcessEvent(pDbgc, pEvent);
8931 if (VBOX_FAILURE(rc))
8932 break;
8933 }
8934 else if (rc != VERR_TIMEOUT)
8935 break;
8936
8937 /*
8938 * Check for input.
8939 */
8940 if (pBack->pfnInput(pDbgc->pBack, 0))
8941 {
8942 rc = dbgcProcessInput(pDbgc);
8943 if (VBOX_FAILURE(rc))
8944 break;
8945 }
8946 }
8947 else
8948 {
8949 /*
8950 * Wait for input. If Logging is enabled we'll only wait very briefly.
8951 */
8952 if (pBack->pfnInput(pDbgc->pBack, pDbgc->fLog ? 1 : 1000))
8953 {
8954 rc = dbgcProcessInput(pDbgc);
8955 if (VBOX_FAILURE(rc))
8956 break;
8957 }
8958 }
8959
8960 /*
8961 * Forward log output.
8962 */
8963 if (pDbgc->fLog)
8964 {
8965 rc = dbgcProcessLog(pDbgc);
8966 if (VBOX_FAILURE(rc))
8967 break;
8968 }
8969 }
8970
8971
8972l_failure:
8973 /*
8974 * Cleanup console debugger session.
8975 */
8976 /* Disable log hook. */
8977 if (pDbgc->fLog)
8978 {
8979
8980 }
8981
8982 /* Detach from the VM. */
8983 if (pDbgc->pVM)
8984 DBGFR3Detach(pDbgc->pVM);
8985
8986 /* finally, free the instance memory. */
8987 RTMemFree(pDbgc);
8988
8989 return rc;
8990}
8991
8992
8993
8994/**
8995 * Register one or more external commands.
8996 *
8997 * @returns VBox status.
8998 * @param paCommands Pointer to an array of command descriptors.
8999 * The commands must be unique. It's not possible
9000 * to register the same commands more than once.
9001 * @param cCommands Number of commands.
9002 */
9003DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
9004{
9005 /*
9006 * Lock the list.
9007 */
9008 DBGCEXTCMDS_LOCK_WR();
9009 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
9010 while (pCur)
9011 {
9012 if (paCommands == pCur->paCmds)
9013 {
9014 DBGCEXTCMDS_UNLOCK_WR();
9015 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
9016 return VWRN_DBGC_ALREADY_REGISTERED;
9017 }
9018 pCur = pCur->pNext;
9019 }
9020
9021 /*
9022 * Allocate new chunk.
9023 */
9024 int rc = 0;
9025 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
9026 if (pCur)
9027 {
9028 pCur->cCmds = cCommands;
9029 pCur->paCmds = paCommands;
9030 pCur->pNext = g_pExtCmdsHead;
9031 g_pExtCmdsHead = pCur;
9032 }
9033 else
9034 rc = VERR_NO_MEMORY;
9035 DBGCEXTCMDS_UNLOCK_WR();
9036
9037 return rc;
9038}
9039
9040
9041/**
9042 * Deregister one or more external commands previously registered by
9043 * DBGCRegisterCommands().
9044 *
9045 * @returns VBox status.
9046 * @param paCommands Pointer to an array of command descriptors
9047 * as given to DBGCRegisterCommands().
9048 * @param cCommands Number of commands.
9049 */
9050DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
9051{
9052 /*
9053 * Lock the list.
9054 */
9055 DBGCEXTCMDS_LOCK_WR();
9056 PDBGCEXTCMDS pPrev = NULL;
9057 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
9058 while (pCur)
9059 {
9060 if (paCommands == pCur->paCmds)
9061 {
9062 if (pPrev)
9063 pPrev->pNext = pCur->pNext;
9064 else
9065 g_pExtCmdsHead = pCur->pNext;
9066 DBGCEXTCMDS_UNLOCK_WR();
9067
9068 RTMemFree(pCur);
9069 return VINF_SUCCESS;
9070 }
9071 pPrev = pCur;
9072 pCur = pCur->pNext;
9073 }
9074 DBGCEXTCMDS_UNLOCK_WR();
9075
9076 NOREF(cCommands);
9077 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
9078}
9079
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