VirtualBox

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

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

Split out the core structures, defines and stuff into DBGCInternal.h

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

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