VirtualBox

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

Last change on this file since 2676 was 2115, checked in by vboxsync, 17 years ago

SELMToFlatEx change

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

© 2023 Oracle
ContactPrivacy policyTerms of Use