VirtualBox

source: vbox/trunk/src/VBox/Debugger/DBGCCommands.cpp@ 32006

Last change on this file since 32006 was 32006, checked in by vboxsync, 14 years ago

VMM/DBGFCoreWrite: skeleton.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 83.3 KB
Line 
1/* $Id: DBGCCommands.cpp 32006 2010-08-26 16:14:33Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Native Commands.
4 */
5
6/*
7 * Copyright (C) 2006-2010 Oracle Corporation
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 (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18/*******************************************************************************
19* Header Files *
20*******************************************************************************/
21#define LOG_GROUP LOG_GROUP_DBGC
22#include <VBox/dbg.h>
23#include <VBox/dbgf.h>
24#include <VBox/vm.h>
25#include <VBox/vmm.h>
26#include <VBox/mm.h>
27#include <VBox/pgm.h>
28#include <VBox/selm.h>
29#include <VBox/dis.h>
30#include <VBox/param.h>
31#include <VBox/err.h>
32#include <VBox/log.h>
33#include <VBox/version.h>
34
35#include <iprt/alloca.h>
36#include <iprt/assert.h>
37#include <iprt/ctype.h>
38#include <iprt/dir.h>
39#include <iprt/env.h>
40#include <iprt/ldr.h>
41#include <iprt/mem.h>
42#include <iprt/path.h>
43#include <iprt/string.h>
44
45#include <stdlib.h>
46#include <stdio.h>
47
48#include "DBGCInternal.h"
49
50
51/*******************************************************************************
52* Internal Functions *
53*******************************************************************************/
54static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
55static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
56static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
57static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
58static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
59static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
60static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
61static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
62static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
63static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
64static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
65static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
66static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
67static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
68static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
69static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
70static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
71static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
72static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
73static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
74static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
75static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
76static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
77static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
78static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
79
80
81/*******************************************************************************
82* Global Variables *
83*******************************************************************************/
84/** One argument of any kind. */
85static const DBGCVARDESC g_aArgAny[] =
86{
87 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
88 { 0, 1, DBGCVAR_CAT_ANY, 0, "var", "Any type of argument." },
89};
90
91/** Multiple string arguments (min 1). */
92static const DBGCVARDESC g_aArgMultiStr[] =
93{
94 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
95 { 1, ~0, DBGCVAR_CAT_STRING, 0, "strings", "One or more strings." },
96};
97
98/** Filename string. */
99static const DBGCVARDESC g_aArgFilename[] =
100{
101 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
102 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },
103};
104
105
106/** 'cpu' arguments. */
107static const DBGCVARDESC g_aArgCpu[] =
108{
109 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
110 { 0, 1, DBGCVAR_CAT_NUMBER_NO_RANGE, 0, "idCpu", "CPU ID" },
111};
112
113
114/** 'help' arguments. */
115static const DBGCVARDESC g_aArgHelp[] =
116{
117 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
118 { 0, ~0, DBGCVAR_CAT_STRING, 0, "cmd/op", "Zero or more command or operator names." },
119};
120
121
122/** 'info' arguments. */
123static const DBGCVARDESC g_aArgInfo[] =
124{
125 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
126 { 1, 1, DBGCVAR_CAT_STRING, 0, "info", "The name of the info to display." },
127 { 0, 1, DBGCVAR_CAT_STRING, 0, "args", "String arguments to the handler." },
128};
129
130
131/** loadimage arguments. */
132static const DBGCVARDESC g_aArgLoadImage[] =
133{
134 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
135 { 1, 1, DBGCVAR_CAT_STRING, 0, "filename", "Filename string." },
136 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The module address." },
137 { 0, 1, DBGCVAR_CAT_STRING, 0, "name", "The module name. (optional)" },
138};
139
140
141/** loadmap arguments. */
142static const DBGCVARDESC g_aArgLoadMap[] =
143{
144 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
145 { 1, 1, DBGCVAR_CAT_STRING, 0, "filename", "Filename string." },
146 { 1, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "address", "The module address." },
147 { 0, 1, DBGCVAR_CAT_STRING, DBGCVD_FLAGS_DEP_PREV, "name", "The module name. Empty string means default. (optional)" },
148 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "subtrahend", "Value to subtract from the addresses in the map file to rebase it correctly to address. (optional)" },
149 { 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "seg", "The module segment number (0-based). (optional)" },
150};
151
152
153/** loadseg arguments. */
154static const DBGCVARDESC g_aArgLoadSeg[] =
155{
156 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
157 { 1, 1, DBGCVAR_CAT_STRING, 0, "filename", "Filename string." },
158 { 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "The module address." },
159 { 1, 1, DBGCVAR_CAT_NUMBER, 0, "seg", "The module segment number (0-based)." },
160 { 0, 1, DBGCVAR_CAT_STRING, DBGCVD_FLAGS_DEP_PREV, "name", "The module name. Empty string means default. (optional)" },
161};
162
163
164/** loadsyms arguments. */
165static const DBGCVARDESC g_aArgLoadSyms[] =
166{
167 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
168 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },
169 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "delta", "Delta to add to the loaded symbols. (optional)" },
170 { 0, 1, DBGCVAR_CAT_STRING, 0, "module name", "Module name. (optional)" },
171 { 0, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "module address", "Module address. (optional)" },
172 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "module size", "The module size. (optional)" },
173};
174
175
176/** log arguments. */
177static const DBGCVARDESC g_aArgLog[] =
178{
179 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
180 { 1, 1, DBGCVAR_CAT_STRING, 0, "groups", "Group modifier string (quote it!)." }
181};
182
183
184/** logdest arguments. */
185static const DBGCVARDESC g_aArgLogDest[] =
186{
187 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
188 { 1, 1, DBGCVAR_CAT_STRING, 0, "dests", "Destination modifier string (quote it!)." }
189};
190
191
192/** logflags arguments. */
193static const DBGCVARDESC g_aArgLogFlags[] =
194{
195 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
196 { 1, 1, DBGCVAR_CAT_STRING, 0, "flags", "Flag modifier string (quote it!)." }
197};
198
199
200/** loadplugin, unloadplugin. */
201static const DBGCVARDESC g_aArgPlugIn[] =
202{
203 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
204 { 1, ~0U, DBGCVAR_CAT_STRING, 0, "plugin", "Plug-in name or filename." },
205};
206
207
208/** 'set' arguments */
209static const DBGCVARDESC g_aArgSet[] =
210{
211 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
212 { 1, 1, DBGCVAR_CAT_STRING, 0, "var", "Variable name." },
213 { 1, 1, DBGCVAR_CAT_ANY, 0, "value", "Value to assign to the variable." },
214};
215
216
217/** writecore arguments. */
218static const DBGCVARDESC g_aArgWriteCore[] =
219{
220 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
221 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },
222};
223
224
225
226/** Command descriptors for the basic commands. */
227const DBGCCMD g_aCmds[] =
228{
229 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc,fFlags,pfnHandler pszSyntax, ....pszDescription */
230 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
231 { "cpu", 0, 1, &g_aArgCpu[0], RT_ELEMENTS(g_aArgCpu), NULL, 0, dbgcCmdCpu, "[idCpu]", "If no argument, display the current CPU, else change to the specified CPU." },
232 { "echo", 1, ~0, &g_aArgMultiStr[0], RT_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." },
233 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
234 { "format", 1, 1, &g_aArgAny[0], RT_ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },
235 { "detect", 0, 0, NULL, 0, NULL, 0, dbgcCmdDetect, "", "Detects or re-detects the guest os and starts the OS specific digger." },
236 { "harakiri", 0, 0, NULL, 0, NULL, 0, dbgcCmdHarakiri, "", "Kills debugger process." },
237 { "help", 0, ~0, &g_aArgHelp[0], RT_ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'info help'." },
238 { "info", 1, 2, &g_aArgInfo[0], RT_ELEMENTS(g_aArgInfo), NULL, 0, dbgcCmdInfo, "<info> [args]", "Display info register in the DBGF. For a list of info items try 'info help'." },
239 { "loadimage", 2, 3, &g_aArgLoadImage[0], RT_ELEMENTS(g_aArgLoadImage),NULL, 0, dbgcCmdLoadImage, "<filename> <address> [name]",
240 "Loads the symbols of an executable image at the specified address. "
241 /*"Optionally giving the module a name other than the file name stem."*/ }, /** @todo implement line breaks */
242 { "loadmap", 2, 5, &g_aArgLoadMap[0], RT_ELEMENTS(g_aArgLoadMap), NULL, 0, dbgcCmdLoadMap, "<filename> <address> [name] [subtrahend] [seg]",
243 "Loads the symbols from a map file, usually at a specified address. "
244 /*"Optionally giving the module a name other than the file name stem "
245 "and a subtrahend to subtract from the addresses."*/ },
246 { "loadplugin", 1, 1, &g_aArgPlugIn[0], RT_ELEMENTS(g_aArgPlugIn), NULL, 0, dbgcCmdLoadPlugIn,"<plugin1> [plugin2..N]", "Loads one or more plugins" },
247 { "loadseg", 3, 4, &g_aArgLoadSeg[0], RT_ELEMENTS(g_aArgLoadSeg), NULL, 0, dbgcCmdLoadSeg, "<filename> <address> <seg> [name]",
248 "Loads the symbols of a segment in the executable image at the specified address. "
249 /*"Optionally giving the module a name other than the file name stem."*/ },
250 { "loadsyms", 1, 5, &g_aArgLoadSyms[0], RT_ELEMENTS(g_aArgLoadSyms),NULL, 0, dbgcCmdLoadSyms, "<filename> [delta] [module] [module address]", "Loads symbols from a text file. Optionally giving a delta and a module." },
251 { "loadvars", 1, 1, &g_aArgFilename[0], RT_ELEMENTS(g_aArgFilename),NULL, 0, dbgcCmdLoadVars, "<filename>", "Load variables from file. One per line, same as the args to the set command." },
252 { "log", 1, 1, &g_aArgLog[0], RT_ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },
253 { "logdest", 1, 1, &g_aArgLogDest[0], RT_ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },
254 { "logflags", 1, 1, &g_aArgLogFlags[0], RT_ELEMENTS(g_aArgLogFlags),NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },
255 { "quit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
256 { "runscript", 1, 1, &g_aArgFilename[0], RT_ELEMENTS(g_aArgFilename),NULL, 0, dbgcCmdRunScript, "<filename>", "Runs the command listed in the script. Lines starting with '#' "
257 "(after removing blanks) are comment. blank lines are ignored. Stops on failure." },
258 { "set", 2, 2, &g_aArgSet[0], RT_ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },
259 { "showplugins",0, 0, NULL, 0, NULL, 0, dbgcCmdShowPlugIns,"", "List loaded plugins." },
260 { "showvars", 0, 0, NULL, 0, NULL, 0, dbgcCmdShowVars, "", "List all the defined variables." },
261 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." },
262 { "unloadplugin", 1, ~0, &g_aArgPlugIn[0], RT_ELEMENTS(g_aArgPlugIn), NULL, 0, dbgcCmdUnloadPlugIn, "<plugin1> [plugin2..N]", "Unloads one or more plugins." },
263 { "unset", 1, ~0, &g_aArgMultiStr[0], RT_ELEMENTS(g_aArgMultiStr),NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
264 { "writecore", 1, 1, &g_aArgWriteCore[0], RT_ELEMENTS(g_aArgWriteCore), NULL, 0, dbgcCmdWriteCore, "<filename>", "Write core to file." },
265};
266
267/** The number of native commands. */
268const unsigned g_cCmds = RT_ELEMENTS(g_aCmds);
269
270
271/**
272 * Pointer to head of the list of external commands.
273 */
274static PDBGCEXTCMDS g_pExtCmdsHead; /** @todo rw protect g_pExtCmdsHead! */
275/** Locks the g_pExtCmdsHead list for reading. */
276#define DBGCEXTCMDS_LOCK_RD() do { } while (0)
277/** Locks the g_pExtCmdsHead list for writing. */
278#define DBGCEXTCMDS_LOCK_WR() do { } while (0)
279/** UnLocks the g_pExtCmdsHead list after reading. */
280#define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)
281/** UnLocks the g_pExtCmdsHead list after writing. */
282#define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)
283
284
285
286
287/**
288 * Finds a routine.
289 *
290 * @returns Pointer to the command descriptor.
291 * If the request was for an external command, the caller is responsible for
292 * unlocking the external command list.
293 * @returns NULL if not found.
294 * @param pDbgc The debug console instance.
295 * @param pachName Pointer to the routine string (not terminated).
296 * @param cchName Length of the routine name.
297 * @param fExternal Whether or not the routine is external.
298 */
299PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
300{
301 if (!fExternal)
302 {
303 /* emulation first, so commands can be overloaded (info ++). */
304 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
305 unsigned cLeft = pDbgc->cEmulationCmds;
306 while (cLeft-- > 0)
307 {
308 if ( !strncmp(pachName, pCmd->pszCmd, cchName)
309 && !pCmd->pszCmd[cchName])
310 return pCmd;
311 pCmd++;
312 }
313
314 for (unsigned iCmd = 0; iCmd < RT_ELEMENTS(g_aCmds); iCmd++)
315 {
316 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
317 && !g_aCmds[iCmd].pszCmd[cchName])
318 return &g_aCmds[iCmd];
319 }
320 }
321 else
322 {
323 DBGCEXTCMDS_LOCK_RD();
324 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
325 {
326 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
327 {
328 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
329 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])
330 return &pExtCmds->paCmds[iCmd];
331 }
332 }
333 DBGCEXTCMDS_UNLOCK_RD();
334 }
335
336 NOREF(pDbgc);
337 return NULL;
338}
339
340
341/**
342 * Register one or more external commands.
343 *
344 * @returns VBox status.
345 * @param paCommands Pointer to an array of command descriptors.
346 * The commands must be unique. It's not possible
347 * to register the same commands more than once.
348 * @param cCommands Number of commands.
349 */
350DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
351{
352 /*
353 * Lock the list.
354 */
355 DBGCEXTCMDS_LOCK_WR();
356 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
357 while (pCur)
358 {
359 if (paCommands == pCur->paCmds)
360 {
361 DBGCEXTCMDS_UNLOCK_WR();
362 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
363 return VWRN_DBGC_ALREADY_REGISTERED;
364 }
365 pCur = pCur->pNext;
366 }
367
368 /*
369 * Allocate new chunk.
370 */
371 int rc = 0;
372 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
373 if (pCur)
374 {
375 pCur->cCmds = cCommands;
376 pCur->paCmds = paCommands;
377 pCur->pNext = g_pExtCmdsHead;
378 g_pExtCmdsHead = pCur;
379 }
380 else
381 rc = VERR_NO_MEMORY;
382 DBGCEXTCMDS_UNLOCK_WR();
383
384 return rc;
385}
386
387
388/**
389 * Deregister one or more external commands previously registered by
390 * DBGCRegisterCommands().
391 *
392 * @returns VBox status.
393 * @param paCommands Pointer to an array of command descriptors
394 * as given to DBGCRegisterCommands().
395 * @param cCommands Number of commands.
396 */
397DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
398{
399 /*
400 * Lock the list.
401 */
402 DBGCEXTCMDS_LOCK_WR();
403 PDBGCEXTCMDS pPrev = NULL;
404 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
405 while (pCur)
406 {
407 if (paCommands == pCur->paCmds)
408 {
409 if (pPrev)
410 pPrev->pNext = pCur->pNext;
411 else
412 g_pExtCmdsHead = pCur->pNext;
413 DBGCEXTCMDS_UNLOCK_WR();
414
415 RTMemFree(pCur);
416 return VINF_SUCCESS;
417 }
418 pPrev = pCur;
419 pCur = pCur->pNext;
420 }
421 DBGCEXTCMDS_UNLOCK_WR();
422
423 NOREF(cCommands);
424 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
425}
426
427
428
429
430/**
431 * Prints full command help.
432 */
433static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal)
434{
435 int rc;
436
437 /* the command */
438 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
439 "%s%-*s %-30s %s",
440 fExternal ? "." : "",
441 fExternal ? 10 : 11,
442 pCmd->pszCmd,
443 pCmd->pszSyntax,
444 pCmd->pszDescription);
445 if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax)
446 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n");
447 else if (pCmd->cArgsMin == pCmd->cArgsMax)
448 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin);
449 else if (pCmd->cArgsMax == ~0U)
450 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin);
451 else
452 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax);
453
454 /* argument descriptions. */
455 for (unsigned i = 0; i < pCmd->cArgDescs; i++)
456 {
457 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
458 " %-12s %s",
459 pCmd->paArgDescs[i].pszName,
460 pCmd->paArgDescs[i].pszDescription);
461 if (!pCmd->paArgDescs[i].cTimesMin)
462 {
463 if (pCmd->paArgDescs[i].cTimesMax == ~0U)
464 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n");
465 else
466 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax);
467 }
468 else
469 {
470 if (pCmd->paArgDescs[i].cTimesMax == ~0U)
471 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin);
472 else
473 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
474 }
475 }
476 return rc;
477}
478
479
480/**
481 * The 'help' command.
482 *
483 * @returns VBox status.
484 * @param pCmd Pointer to the command descriptor (as registered).
485 * @param pCmdHlp Pointer to command helper functions.
486 * @param pVM Pointer to the current VM (if any).
487 * @param paArgs Pointer to (readonly) array of arguments.
488 * @param cArgs Number of arguments in the array.
489 */
490static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
491{
492 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
493 int rc = VINF_SUCCESS;
494 unsigned i;
495
496 if (!cArgs)
497 {
498 /*
499 * All the stuff.
500 */
501 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
502 "VirtualBox Debugger\n"
503 "-------------------\n"
504 "\n"
505 "Commands and Functions:\n");
506 for (i = 0; i < RT_ELEMENTS(g_aCmds); i++)
507 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
508 "%-11s %-30s %s\n",
509 g_aCmds[i].pszCmd,
510 g_aCmds[i].pszSyntax,
511 g_aCmds[i].pszDescription);
512 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
513 "\n"
514 "Emulation: %s\n", pDbgc->pszEmulation);
515 PCDBGCCMD pCmd2 = pDbgc->paEmulationCmds;
516 for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd2++)
517 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
518 "%-11s %-30s %s\n",
519 pCmd2->pszCmd,
520 pCmd2->pszSyntax,
521 pCmd2->pszDescription);
522
523 if (g_pExtCmdsHead)
524 {
525 DBGCEXTCMDS_LOCK_RD();
526 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
527 "\n"
528 "External Commands and Functions:\n");
529 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
530 for (i = 0; i < pExtCmd->cCmds; i++)
531 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
532 ".%-10s %-30s %s\n",
533 pExtCmd->paCmds[i].pszCmd,
534 pExtCmd->paCmds[i].pszSyntax,
535 pExtCmd->paCmds[i].pszDescription);
536 DBGCEXTCMDS_UNLOCK_RD();
537 }
538
539 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
540 "\n"
541 "Operators:\n");
542 unsigned iPrecedence = 0;
543 unsigned cLeft = g_cOps;
544 while (cLeft > 0)
545 {
546 for (i = 0; i < g_cOps; i++)
547 if (g_aOps[i].iPrecedence == iPrecedence)
548 {
549 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
550 "%-10s %s %s\n",
551 g_aOps[i].szName,
552 g_aOps[i].fBinary ? "Binary" : "Unary ",
553 g_aOps[i].pszDescription);
554 cLeft--;
555 }
556 iPrecedence++;
557 }
558 }
559 else
560 {
561 /*
562 * Search for the arguments (strings).
563 */
564 for (unsigned iArg = 0; iArg < cArgs; iArg++)
565 {
566 Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);
567 const char *pszPattern = paArgs[iArg].u.pszString;
568 bool fFound = false;
569
570 /* lookup in the emulation command list first */
571 for (i = 0; i < pDbgc->cEmulationCmds; i++)
572 if (RTStrSimplePatternMatch(pszPattern, pDbgc->paEmulationCmds[i].pszCmd))
573 {
574 rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);
575 fFound = true;
576 }
577
578 /* lookup in the command list (even when found in the emulation) */
579 for (i = 0; i < RT_ELEMENTS(g_aCmds); i++)
580 if (RTStrSimplePatternMatch(pszPattern, g_aCmds[i].pszCmd))
581 {
582 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);
583 fFound = true;
584 }
585
586 /* external commands */
587 if ( !fFound
588 && g_pExtCmdsHead
589 && ( *pszPattern == '.'
590 || *pszPattern == '?'
591 || *pszPattern == '*'))
592 {
593 DBGCEXTCMDS_LOCK_RD();
594 const char *pszPattern2 = pszPattern + (*pszPattern == '.' || *pszPattern == '?');
595 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
596 for (i = 0; i < pExtCmd->cCmds; i++)
597 if (RTStrSimplePatternMatch(pszPattern2, pExtCmd->paCmds[i].pszCmd))
598 {
599 rc = dbgcPrintHelp(pCmdHlp, &pExtCmd->paCmds[i], true);
600 fFound = true;
601 }
602 DBGCEXTCMDS_UNLOCK_RD();
603 }
604
605 /* operators */
606 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
607 {
608 for (i = 0; i < g_cOps; i++)
609 if (RTStrSimplePatternMatch(pszPattern, g_aOps[i].szName))
610 {
611 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
612 "%-10s %s %s\n",
613 g_aOps[i].szName,
614 g_aOps[i].fBinary ? "Binary" : "Unary ",
615 g_aOps[i].pszDescription);
616 fFound = true;
617 }
618 }
619
620 /* found? */
621 if (!fFound)
622 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
623 "error: '%s' was not found!\n",
624 paArgs[iArg].u.pszString);
625 } /* foreach argument */
626 }
627
628 NOREF(pCmd);
629 NOREF(pVM);
630 NOREF(pResult);
631 return rc;
632}
633
634
635/**
636 * The 'quit', 'exit' and 'bye' commands.
637 *
638 * @returns VBox status.
639 * @param pCmd Pointer to the command descriptor (as registered).
640 * @param pCmdHlp Pointer to command helper functions.
641 * @param pVM Pointer to the current VM (if any).
642 * @param paArgs Pointer to (readonly) array of arguments.
643 * @param cArgs Number of arguments in the array.
644 */
645static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
646{
647 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
648 NOREF(pCmd);
649 NOREF(pVM);
650 NOREF(paArgs);
651 NOREF(cArgs);
652 NOREF(pResult);
653 return VERR_DBGC_QUIT;
654}
655
656
657/**
658 * The 'stop' command.
659 *
660 * @returns VBox status.
661 * @param pCmd Pointer to the command descriptor (as registered).
662 * @param pCmdHlp Pointer to command helper functions.
663 * @param pVM Pointer to the current VM (if any).
664 * @param paArgs Pointer to (readonly) array of arguments.
665 * @param cArgs Number of arguments in the array.
666 */
667static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
668{
669 /*
670 * Check if the VM is halted or not before trying to halt it.
671 */
672 int rc;
673 if (DBGFR3IsHalted(pVM))
674 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
675 else
676 {
677 rc = DBGFR3Halt(pVM);
678 if (RT_SUCCESS(rc))
679 rc = VWRN_DBGC_CMD_PENDING;
680 else
681 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
682 }
683
684 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
685 return rc;
686}
687
688
689/**
690 * The 'echo' command.
691 *
692 * @returns VBox status.
693 * @param pCmd Pointer to the command descriptor (as registered).
694 * @param pCmdHlp Pointer to command helper functions.
695 * @param pVM Pointer to the current VM (if any).
696 * @param paArgs Pointer to (readonly) array of arguments.
697 * @param cArgs Number of arguments in the array.
698 */
699static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
700{
701 /*
702 * Loop thru the arguments and print them with one space between.
703 */
704 int rc = 0;
705 for (unsigned i = 0; i < cArgs; i++)
706 {
707 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
708 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
709 else
710 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
711 if (RT_FAILURE(rc))
712 return rc;
713 }
714 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
715 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
716}
717
718
719/**
720 * The 'runscript' command.
721 *
722 * @returns VBox status.
723 * @param pCmd Pointer to the command descriptor (as registered).
724 * @param pCmdHlp Pointer to command helper functions.
725 * @param pVM Pointer to the current VM (if any).
726 * @param paArgs Pointer to (readonly) array of arguments.
727 * @param cArgs Number of arguments in the array.
728 */
729static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
730{
731 /* check that the parser did what it's supposed to do. */
732 if ( cArgs != 1
733 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
734 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
735
736 /*
737 * Try open the script.
738 */
739 const char *pszFilename = paArgs[0].u.pszString;
740 FILE *pFile = fopen(pszFilename, "r");
741 if (!pFile)
742 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
743
744 /*
745 * Execute it line by line.
746 */
747 int rc = 0;
748 unsigned iLine = 0;
749 char szLine[8192];
750 while (fgets(szLine, sizeof(szLine), pFile))
751 {
752 /* check that the line isn't too long. */
753 char *pszEnd = strchr(szLine, '\0');
754 if (pszEnd == &szLine[sizeof(szLine) - 1])
755 {
756 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
757 break;
758 }
759 iLine++;
760
761 /* strip leading blanks and check for comment / blank line. */
762 char *psz = RTStrStripL(szLine);
763 if ( *psz == '\0'
764 || *psz == '\n'
765 || *psz == '#')
766 continue;
767
768 /* strip trailing blanks and check for empty line (\r case). */
769 while ( pszEnd > psz
770 && RT_C_IS_SPACE(pszEnd[-1])) /* RT_C_IS_SPACE includes \n and \r normally. */
771 *--pszEnd = '\0';
772
773 /** @todo check for Control-C / Cancel at this point... */
774
775 /*
776 * Execute the command.
777 *
778 * This is a bit wasteful with scratch space btw., can fix it later.
779 * The whole return code crap should be fixed too, so that it's possible
780 * to know whether a command succeeded (RT_SUCCESS()) or failed, and
781 * more importantly why it failed.
782 */
783 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
784 if (RT_FAILURE(rc))
785 {
786 if (rc == VERR_BUFFER_OVERFLOW)
787 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
788 break;
789 }
790 if (rc == VWRN_DBGC_CMD_PENDING)
791 {
792 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
793 break;
794 }
795 }
796
797 fclose(pFile);
798
799 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
800 return rc;
801}
802
803
804/**
805 * The 'detect' command.
806 *
807 * @returns VBox status.
808 * @param pCmd Pointer to the command descriptor (as registered).
809 * @param pCmdHlp Pointer to command helper functions.
810 * @param pVM Pointer to the current VM (if any).
811 * @param paArgs Pointer to (readonly) array of arguments.
812 * @param cArgs Number of arguments in the array.
813 */
814static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
815{
816 /* check that the parser did what it's supposed to do. */
817 if (cArgs != 0)
818 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
819
820 /*
821 * Perform the detection.
822 */
823 char szName[64];
824 int rc = DBGFR3OSDetect(pVM, szName, sizeof(szName));
825 if (RT_FAILURE(rc))
826 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().");
827 if (rc == VINF_SUCCESS)
828 {
829 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Guest OS: %s\n", szName);
830 char szVersion[512];
831 int rc2 = DBGFR3OSQueryNameAndVersion(pVM, NULL, 0, szVersion, sizeof(szVersion));
832 if (RT_SUCCESS(rc2))
833 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Version : %s\n", szVersion);
834 }
835 else
836 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Unable to figure out which guest OS it is, sorry.\n");
837 NOREF(pCmd); NOREF(pResult); NOREF(paArgs);
838 return rc;
839}
840
841
842/**
843 * The 'cpu' command.
844 *
845 * @returns VBox status.
846 * @param pCmd Pointer to the command descriptor (as registered).
847 * @param pCmdHlp Pointer to command helper functions.
848 * @param pVM Pointer to the current VM (if any).
849 * @param paArgs Pointer to (readonly) array of arguments.
850 * @param cArgs Number of arguments in the array.
851 */
852static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
853{
854 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
855
856 /* check that the parser did what it's supposed to do. */
857 if ( cArgs != 0
858 && ( cArgs != 1
859 || paArgs[0].enmType != DBGCVAR_TYPE_NUMBER))
860 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
861 if (!pVM)
862 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
863
864 int rc;
865 if (!cArgs)
866 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Current CPU ID: %u\n", pDbgc->idCpu);
867 else
868 {
869 if (paArgs[0].u.u64Number >= pVM->cCpus)
870 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: idCpu %u is out of range! Highest ID is %u.\n",
871 paArgs[0].u.u64Number, pVM->cCpus);
872 else
873 {
874 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Changed CPU from %u to %u.\n",
875 pDbgc->idCpu, (VMCPUID)paArgs[0].u.u64Number);
876 pDbgc->idCpu = (VMCPUID)paArgs[0].u.u64Number;
877 }
878 }
879 return rc;
880}
881
882
883/**
884 * The 'info' command.
885 *
886 * @returns VBox status.
887 * @param pCmd Pointer to the command descriptor (as registered).
888 * @param pCmdHlp Pointer to command helper functions.
889 * @param pVM Pointer to the current VM (if any).
890 * @param paArgs Pointer to (readonly) array of arguments.
891 * @param cArgs Number of arguments in the array.
892 */
893static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
894{
895 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
896
897 /*
898 * Validate input.
899 */
900 if ( cArgs < 1
901 || cArgs > 2
902 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
903 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
904 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
905 if (!pVM)
906 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
907
908 /*
909 * Dump it.
910 */
911 int rc = VMR3ReqCallWait(pVM, pDbgc->idCpu, (PFNRT)DBGFR3Info, 4,
912 pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL,
913 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
914 if (RT_FAILURE(rc))
915 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
916
917 NOREF(pCmd); NOREF(pResult);
918 return 0;
919}
920
921
922/**
923 * The 'log' command.
924 *
925 * @returns VBox status.
926 * @param pCmd Pointer to the command descriptor (as registered).
927 * @param pCmdHlp Pointer to command helper functions.
928 * @param pVM Pointer to the current VM (if any).
929 * @param paArgs Pointer to (readonly) array of arguments.
930 * @param cArgs Number of arguments in the array.
931 */
932static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
933{
934 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
935 if (RT_SUCCESS(rc))
936 return VINF_SUCCESS;
937 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
938 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
939}
940
941
942/**
943 * The 'logdest' command.
944 *
945 * @returns VBox status.
946 * @param pCmd Pointer to the command descriptor (as registered).
947 * @param pCmdHlp Pointer to command helper functions.
948 * @param pVM Pointer to the current VM (if any).
949 * @param paArgs Pointer to (readonly) array of arguments.
950 * @param cArgs Number of arguments in the array.
951 */
952static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
953{
954 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
955 if (RT_SUCCESS(rc))
956 return VINF_SUCCESS;
957 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
958 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
959}
960
961
962/**
963 * The 'logflags' command.
964 *
965 * @returns VBox status.
966 * @param pCmd Pointer to the command descriptor (as registered).
967 * @param pCmdHlp Pointer to command helper functions.
968 * @param pVM Pointer to the current VM (if any).
969 * @param paArgs Pointer to (readonly) array of arguments.
970 * @param cArgs Number of arguments in the array.
971 */
972static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
973{
974 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
975 if (RT_SUCCESS(rc))
976 return VINF_SUCCESS;
977 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
978 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
979}
980
981
982/**
983 * The 'format' command.
984 *
985 * @returns VBox status.
986 * @param pCmd Pointer to the command descriptor (as registered).
987 * @param pCmdHlp Pointer to command helper functions.
988 * @param pVM Pointer to the current VM (if any).
989 * @param paArgs Pointer to (readonly) array of arguments.
990 * @param cArgs Number of arguments in the array.
991 */
992static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
993{
994 LogFlow(("dbgcCmdFormat\n"));
995 static const char *apszRangeDesc[] =
996 {
997 "none", "bytes", "elements"
998 };
999 int rc;
1000
1001 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1002 {
1003 switch (paArgs[iArg].enmType)
1004 {
1005 case DBGCVAR_TYPE_UNKNOWN:
1006 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1007 "Unknown variable type!\n");
1008 break;
1009 case DBGCVAR_TYPE_GC_FLAT:
1010 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1011 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1012 "Guest flat address: %%%08x range %lld %s\n",
1013 paArgs[iArg].u.GCFlat,
1014 paArgs[iArg].u64Range,
1015 apszRangeDesc[paArgs[iArg].enmRangeType]);
1016 else
1017 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1018 "Guest flat address: %%%08x\n",
1019 paArgs[iArg].u.GCFlat);
1020 break;
1021 case DBGCVAR_TYPE_GC_FAR:
1022 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1023 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1024 "Guest far address: %04x:%08x range %lld %s\n",
1025 paArgs[iArg].u.GCFar.sel,
1026 paArgs[iArg].u.GCFar.off,
1027 paArgs[iArg].u64Range,
1028 apszRangeDesc[paArgs[iArg].enmRangeType]);
1029 else
1030 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1031 "Guest far address: %04x:%08x\n",
1032 paArgs[iArg].u.GCFar.sel,
1033 paArgs[iArg].u.GCFar.off);
1034 break;
1035 case DBGCVAR_TYPE_GC_PHYS:
1036 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1037 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1038 "Guest physical address: %%%%%08x range %lld %s\n",
1039 paArgs[iArg].u.GCPhys,
1040 paArgs[iArg].u64Range,
1041 apszRangeDesc[paArgs[iArg].enmRangeType]);
1042 else
1043 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1044 "Guest physical address: %%%%%08x\n",
1045 paArgs[iArg].u.GCPhys);
1046 break;
1047 case DBGCVAR_TYPE_HC_FLAT:
1048 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1049 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1050 "Host flat address: %%%08x range %lld %s\n",
1051 paArgs[iArg].u.pvHCFlat,
1052 paArgs[iArg].u64Range,
1053 apszRangeDesc[paArgs[iArg].enmRangeType]);
1054 else
1055 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1056 "Host flat address: %%%08x\n",
1057 paArgs[iArg].u.pvHCFlat);
1058 break;
1059 case DBGCVAR_TYPE_HC_FAR:
1060 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1061 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1062 "Host far address: %04x:%08x range %lld %s\n",
1063 paArgs[iArg].u.HCFar.sel,
1064 paArgs[iArg].u.HCFar.off,
1065 paArgs[iArg].u64Range,
1066 apszRangeDesc[paArgs[iArg].enmRangeType]);
1067 else
1068 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1069 "Host far address: %04x:%08x\n",
1070 paArgs[iArg].u.HCFar.sel,
1071 paArgs[iArg].u.HCFar.off);
1072 break;
1073 case DBGCVAR_TYPE_HC_PHYS:
1074 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1075 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1076 "Host physical address: %RHp range %lld %s\n",
1077 paArgs[iArg].u.HCPhys,
1078 paArgs[iArg].u64Range,
1079 apszRangeDesc[paArgs[iArg].enmRangeType]);
1080 else
1081 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1082 "Host physical address: %RHp\n",
1083 paArgs[iArg].u.HCPhys);
1084 break;
1085
1086 case DBGCVAR_TYPE_STRING:
1087 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1088 "String, %lld bytes long: %s\n",
1089 paArgs[iArg].u64Range,
1090 paArgs[iArg].u.pszString);
1091 break;
1092
1093 case DBGCVAR_TYPE_NUMBER:
1094 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1095 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1096 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1097 paArgs[iArg].u.u64Number,
1098 paArgs[iArg].u.u64Number,
1099 paArgs[iArg].u.u64Number,
1100 paArgs[iArg].u64Range,
1101 apszRangeDesc[paArgs[iArg].enmRangeType]);
1102 else
1103 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1104 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1105 paArgs[iArg].u.u64Number,
1106 paArgs[iArg].u.u64Number,
1107 paArgs[iArg].u.u64Number);
1108 break;
1109
1110 default:
1111 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1112 "Invalid argument type %d\n",
1113 paArgs[iArg].enmType);
1114 break;
1115 }
1116 } /* arg loop */
1117
1118 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1119 return 0;
1120}
1121
1122
1123/**
1124 * The 'loadimage' command.
1125 *
1126 * @returns VBox status.
1127 * @param pCmd Pointer to the command descriptor (as registered).
1128 * @param pCmdHlp Pointer to command helper functions.
1129 * @param pVM Pointer to the current VM (if any).
1130 * @param paArgs Pointer to (readonly) array of arguments.
1131 * @param cArgs Number of arguments in the array.
1132 */
1133static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1134{
1135 /*
1136 * Validate the parsing and make sense of the input.
1137 * This is a mess as usual because we don't trust the parser yet.
1138 */
1139 AssertReturn( cArgs >= 2
1140 && cArgs <= 3
1141 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1142 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1143 VERR_PARSE_INCORRECT_ARG_TYPE);
1144
1145 const char *pszFilename = paArgs[0].u.pszString;
1146
1147 DBGFADDRESS ModAddress;
1148 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1149 if (RT_FAILURE(rc))
1150 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1151
1152 const char *pszModName = NULL;
1153 if (cArgs >= 3)
1154 {
1155 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1156 pszModName = paArgs[2].u.pszString;
1157 }
1158
1159 /*
1160 * Try create a module for it.
1161 */
1162 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1163 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1164 if (RT_FAILURE(rc))
1165 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1166 pszFilename, pszModName, &paArgs[1]);
1167
1168 NOREF(pCmd); NOREF(pResult);
1169 return VINF_SUCCESS;
1170}
1171
1172
1173/**
1174 * The 'loadmap' command.
1175 *
1176 * @returns VBox status.
1177 * @param pCmd Pointer to the command descriptor (as registered).
1178 * @param pCmdHlp Pointer to command helper functions.
1179 * @param pVM Pointer to the current VM (if any).
1180 * @param paArgs Pointer to (readonly) array of arguments.
1181 * @param cArgs Number of arguments in the array.
1182 */
1183static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1184{
1185 /*
1186 * Validate the parsing and make sense of the input.
1187 * This is a mess as usual because we don't trust the parser yet.
1188 */
1189 AssertReturn( cArgs >= 2
1190 && cArgs <= 5
1191 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1192 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1193 VERR_PARSE_INCORRECT_ARG_TYPE);
1194
1195 const char *pszFilename = paArgs[0].u.pszString;
1196
1197 DBGFADDRESS ModAddress;
1198 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1199 if (RT_FAILURE(rc))
1200 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1201
1202 const char *pszModName = NULL;
1203 if (cArgs >= 3)
1204 {
1205 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1206 pszModName = paArgs[2].u.pszString;
1207 }
1208
1209 RTGCUINTPTR uSubtrahend = 0;
1210 if (cArgs >= 4)
1211 {
1212 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1213 uSubtrahend = paArgs[3].u.u64Number;
1214 }
1215
1216 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1217 if (cArgs >= 5)
1218 {
1219 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1220 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1221 if ( iModSeg != paArgs[4].u.u64Number
1222 || iModSeg > RTDBGSEGIDX_LAST)
1223 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1224 }
1225
1226 /*
1227 * Try create a module for it.
1228 */
1229 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1230 rc = DBGFR3AsLoadMap(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1231 if (RT_FAILURE(rc))
1232 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1233 pszFilename, pszModName, &paArgs[1]);
1234
1235 NOREF(pCmd); NOREF(pResult);
1236 return VINF_SUCCESS;
1237}
1238
1239
1240/**
1241 * The 'loadseg' 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) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1251{
1252 /*
1253 * Validate the parsing and make sense of the input.
1254 * This is a mess as usual because we don't trust the parser yet.
1255 */
1256 AssertReturn( cArgs >= 3
1257 && cArgs <= 4
1258 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1259 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1260 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1261 VERR_PARSE_INCORRECT_ARG_TYPE);
1262
1263 const char *pszFilename = paArgs[0].u.pszString;
1264
1265 DBGFADDRESS ModAddress;
1266 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1267 if (RT_FAILURE(rc))
1268 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1269
1270 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1271 if ( iModSeg != paArgs[2].u.u64Number
1272 || iModSeg > RTDBGSEGIDX_LAST)
1273 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1274
1275 const char *pszModName = NULL;
1276 if (cArgs >= 4)
1277 {
1278 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1279 pszModName = paArgs[3].u.pszString;
1280 }
1281
1282 /*
1283 * Call the debug info manager about this loading.
1284 */
1285 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1286 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, iModSeg, 0 /*fFlags*/);
1287 if (RT_FAILURE(rc))
1288 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1289 pszFilename, pszModName, &paArgs[1]);
1290
1291 NOREF(pCmd); NOREF(pResult);
1292 return VINF_SUCCESS;
1293}
1294
1295
1296/**
1297 * The 'loadsyms' command.
1298 *
1299 * @returns VBox status.
1300 * @param pCmd Pointer to the command descriptor (as registered).
1301 * @param pCmdHlp Pointer to command helper functions.
1302 * @param pVM Pointer to the current VM (if any).
1303 * @param paArgs Pointer to (readonly) array of arguments.
1304 * @param cArgs Number of arguments in the array.
1305 */
1306static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1307{
1308 /*
1309 * Validate the parsing and make sense of the input.
1310 * This is a mess as usual because we don't trust the parser yet.
1311 */
1312 if ( cArgs < 1
1313 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1314 {
1315 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
1316 return VERR_PARSE_INCORRECT_ARG_TYPE;
1317 }
1318 DBGCVAR AddrVar;
1319 RTGCUINTPTR Delta = 0;
1320 const char *pszModule = NULL;
1321 RTGCUINTPTR ModuleAddress = 0;
1322 unsigned cbModule = 0;
1323 if (cArgs > 1)
1324 {
1325 unsigned iArg = 1;
1326 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
1327 {
1328 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
1329 iArg++;
1330 }
1331 if (iArg < cArgs)
1332 {
1333 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
1334 {
1335 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
1336 return VERR_PARSE_INCORRECT_ARG_TYPE;
1337 }
1338 pszModule = paArgs[iArg].u.pszString;
1339 iArg++;
1340 if (iArg < cArgs)
1341 {
1342 if (!DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
1343 {
1344 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
1345 return VERR_PARSE_INCORRECT_ARG_TYPE;
1346 }
1347 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
1348 if (RT_FAILURE(rc))
1349 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
1350 ModuleAddress = paArgs[iArg].u.GCFlat;
1351 iArg++;
1352 if (iArg < cArgs)
1353 {
1354 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
1355 {
1356 AssertMsgFailed(("Parse error, module argument required to be an integer!\n"));
1357 return VERR_PARSE_INCORRECT_ARG_TYPE;
1358 }
1359 cbModule = (unsigned)paArgs[iArg].u.u64Number;
1360 iArg++;
1361 if (iArg < cArgs)
1362 {
1363 AssertMsgFailed(("Parse error, too many arguments!\n"));
1364 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1365 }
1366 }
1367 }
1368 }
1369 }
1370
1371 /*
1372 * Call the debug info manager about this loading...
1373 */
1374 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
1375 if (RT_FAILURE(rc))
1376 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %RGv, '%s', %RGv, 0)\n",
1377 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
1378
1379 NOREF(pCmd); NOREF(pResult);
1380 return VINF_SUCCESS;
1381}
1382
1383
1384/**
1385 * The 'set' command.
1386 *
1387 * @returns VBox status.
1388 * @param pCmd Pointer to the command descriptor (as registered).
1389 * @param pCmdHlp Pointer to command helper functions.
1390 * @param pVM Pointer to the current VM (if any).
1391 * @param paArgs Pointer to (readonly) array of arguments.
1392 * @param cArgs Number of arguments in the array.
1393 */
1394static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1395{
1396 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1397
1398 /* parse sanity check. */
1399 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1400 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1401 return VERR_PARSE_INCORRECT_ARG_TYPE;
1402
1403
1404 /*
1405 * A variable must start with an alpha chars and only contain alpha numerical chars.
1406 */
1407 const char *pszVar = paArgs[0].u.pszString;
1408 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1409 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1410 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
1411
1412 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1413 *pszVar++;
1414 if (*pszVar)
1415 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1416 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
1417
1418
1419 /*
1420 * Calc variable size.
1421 */
1422 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1423 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1424 cbVar += 1 + (size_t)paArgs[1].u64Range;
1425
1426 /*
1427 * Look for existing one.
1428 */
1429 pszVar = paArgs[0].u.pszString;
1430 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1431 {
1432 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1433 {
1434 /*
1435 * Update existing variable.
1436 */
1437 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1438 if (!pv)
1439 return VERR_PARSE_NO_MEMORY;
1440 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1441
1442 pVar->Var = paArgs[1];
1443 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1444 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1445 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1446 return 0;
1447 }
1448 }
1449
1450 /*
1451 * Allocate another.
1452 */
1453 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1454
1455 pVar->Var = paArgs[1];
1456 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1457 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1458 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1459
1460 /* need to reallocate the pointer array too? */
1461 if (!(pDbgc->cVars % 0x20))
1462 {
1463 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1464 if (!pv)
1465 {
1466 RTMemFree(pVar);
1467 return VERR_PARSE_NO_MEMORY;
1468 }
1469 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1470 }
1471 pDbgc->papVars[pDbgc->cVars++] = pVar;
1472
1473 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
1474 return 0;
1475}
1476
1477
1478/**
1479 * The 'unset' command.
1480 *
1481 * @returns VBox status.
1482 * @param pCmd Pointer to the command descriptor (as registered).
1483 * @param pCmdHlp Pointer to command helper functions.
1484 * @param pVM Pointer to the current VM (if any).
1485 * @param paArgs Pointer to (readonly) array of arguments.
1486 * @param cArgs Number of arguments in the array.
1487 */
1488static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1489{
1490 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1491
1492 /*
1493 * Don't trust the parser.
1494 */
1495 for (unsigned i = 0; i < cArgs; i++)
1496 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
1497 {
1498 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
1499 return VERR_PARSE_INCORRECT_ARG_TYPE;
1500 }
1501
1502 /*
1503 * Iterate the variables and unset them.
1504 */
1505 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1506 {
1507 const char *pszVar = paArgs[iArg].u.pszString;
1508
1509 /*
1510 * Look up the variable.
1511 */
1512 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1513 {
1514 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1515 {
1516 /*
1517 * Shuffle the array removing this entry.
1518 */
1519 void *pvFree = pDbgc->papVars[iVar];
1520 if (iVar + 1 < pDbgc->cVars)
1521 memmove(&pDbgc->papVars[iVar],
1522 &pDbgc->papVars[iVar + 1],
1523 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1524 pDbgc->papVars[--pDbgc->cVars] = NULL;
1525
1526 RTMemFree(pvFree);
1527 }
1528 } /* lookup */
1529 } /* arg loop */
1530
1531 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1532 return 0;
1533}
1534
1535
1536/**
1537 * The 'loadvars' command.
1538 *
1539 * @returns VBox status.
1540 * @param pCmd Pointer to the command descriptor (as registered).
1541 * @param pCmdHlp Pointer to command helper functions.
1542 * @param pVM Pointer to the current VM (if any).
1543 * @param paArgs Pointer to (readonly) array of arguments.
1544 * @param cArgs Number of arguments in the array.
1545 */
1546static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1547{
1548 /*
1549 * Don't trust the parser.
1550 */
1551 if ( cArgs != 1
1552 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1553 {
1554 AssertMsgFailed(("Expected one string exactly!\n"));
1555 return VERR_PARSE_INCORRECT_ARG_TYPE;
1556 }
1557
1558 /*
1559 * Iterate the variables and unset them.
1560 */
1561 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1562 if (pFile)
1563 {
1564 char szLine[4096];
1565 while (fgets(szLine, sizeof(szLine), pFile))
1566 {
1567 /* Strip it. */
1568 char *psz = szLine;
1569 while (RT_C_IS_BLANK(*psz))
1570 psz++;
1571 int i = (int)strlen(psz) - 1;
1572 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1573 psz[i--] ='\0';
1574 /* Execute it if not comment or empty line. */
1575 if ( *psz != '\0'
1576 && *psz != '#'
1577 && *psz != ';')
1578 {
1579 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
1580 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1581 }
1582 }
1583 fclose(pFile);
1584 }
1585 else
1586 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1587
1588 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1589 return 0;
1590}
1591
1592
1593/**
1594 * The 'showvars' command.
1595 *
1596 * @returns VBox status.
1597 * @param pCmd Pointer to the command descriptor (as registered).
1598 * @param pCmdHlp Pointer to command helper functions.
1599 * @param pVM Pointer to the current VM (if any).
1600 * @param paArgs Pointer to (readonly) array of arguments.
1601 * @param cArgs Number of arguments in the array.
1602 */
1603static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1604{
1605 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1606
1607 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1608 {
1609 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
1610 if (!rc)
1611 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
1612 if (rc)
1613 return rc;
1614 }
1615
1616 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1617 return 0;
1618}
1619
1620
1621/**
1622 * Extracts the plugin name from a plugin specifier that may or may not include
1623 * path and/or suffix.
1624 *
1625 * @returns VBox status code.
1626 *
1627 * @param pszDst Where to return the name. At least DBGCPLUGIN_MAX_NAME
1628 * worth of buffer space.
1629 * @param pszPlugIn The plugin specifier to parse.
1630 */
1631static int dbgcPlugInExtractName(char *pszDst, const char *pszPlugIn)
1632{
1633 /*
1634 * Parse out the name stopping at the extension.
1635 */
1636 const char *pszName = RTPathFilename(pszPlugIn);
1637 if (!pszName || !*pszName)
1638 return VERR_INVALID_NAME;
1639 if (!RTStrNICmp(pszName, DBGC_PLUG_IN_PREFIX, sizeof(DBGC_PLUG_IN_PREFIX) - 1))
1640 {
1641 pszName += sizeof(DBGC_PLUG_IN_PREFIX) - 1;
1642 if (!*pszName)
1643 return VERR_INVALID_NAME;
1644 }
1645
1646 int ch;
1647 size_t cchName = 0;
1648 while ( (ch = pszName[cchName]) != '\0'
1649 && ch != '.')
1650 {
1651 if ( !RT_C_IS_ALPHA(ch)
1652 && ( !RT_C_IS_DIGIT(ch)
1653 || cchName == 0))
1654 return VERR_INVALID_NAME;
1655 cchName++;
1656 }
1657
1658 if (cchName >= DBGCPLUGIN_MAX_NAME)
1659 return VERR_OUT_OF_RANGE;
1660
1661 /*
1662 * We're very picky about the extension if there is no path.
1663 */
1664 if ( ch == '.'
1665 && !RTPathHavePath(pszPlugIn)
1666 && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
1667 return VERR_INVALID_NAME;
1668
1669 /*
1670 * Copy it.
1671 */
1672 memcpy(pszDst, pszName, cchName);
1673 pszDst[cchName] = '\0';
1674 return VINF_SUCCESS;
1675}
1676
1677
1678/**
1679 * Locate a plug-in in list.
1680 *
1681 * @returns Pointer to the plug-in tracking structure.
1682 * @param pDbgc Pointer to the DBGC instance data.
1683 * @param pszName The name of the plug-in we're looking for.
1684 * @param ppPrev Where to optionally return the pointer to the
1685 * previous list member.
1686 */
1687static PDBGCPLUGIN dbgcPlugInLocate(PDBGC pDbgc, const char *pszName, PDBGCPLUGIN *ppPrev)
1688{
1689 PDBGCPLUGIN pPrev = NULL;
1690 PDBGCPLUGIN pCur = pDbgc->pPlugInHead;
1691 while (pCur)
1692 {
1693 if (!RTStrICmp(pCur->szName, pszName))
1694 {
1695 if (ppPrev)
1696 *ppPrev = pPrev;
1697 return pCur;
1698 }
1699
1700 /* advance */
1701 pPrev = pCur;
1702 pCur = pCur->pNext;
1703 }
1704 return NULL;
1705}
1706
1707
1708/**
1709 * Try load the specified plug-in module.
1710 *
1711 * @returns VINF_SUCCESS on success, path error or loader error on failure.
1712 *
1713 * @param pPlugIn The plugin tracing record.
1714 * @param pszModule Module name.
1715 */
1716static int dbgcPlugInTryLoad(PDBGCPLUGIN pPlugIn, const char *pszModule)
1717{
1718 /*
1719 * Load it and try resolve the entry point.
1720 */
1721 int rc = RTLdrLoad(pszModule, &pPlugIn->hLdrMod);
1722 if (RT_SUCCESS(rc))
1723 {
1724 rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGC_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
1725 if (RT_SUCCESS(rc))
1726 return VINF_SUCCESS;
1727 LogRel(("DBGC: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGC_PLUG_IN_ENTRYPOINT, rc));
1728
1729 RTLdrClose(pPlugIn->hLdrMod);
1730 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1731 }
1732 return rc;
1733}
1734
1735
1736/**
1737 * RTPathTraverseList callback.
1738 *
1739 * @returns See FNRTPATHTRAVERSER.
1740 *
1741 * @param pchPath See FNRTPATHTRAVERSER.
1742 * @param cchPath See FNRTPATHTRAVERSER.
1743 * @param pvUser1 The plug-in specifier.
1744 * @param pvUser2 The plug-in tracking record.
1745 */
1746static DECLCALLBACK(int) dbgcPlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
1747{
1748 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)pvUser2;
1749 const char *pszPlugIn = (const char *)pvUser1;
1750
1751 /*
1752 * Join the path and the specified plug-in module name, first with the
1753 * prefix and then without it.
1754 */
1755 size_t cchModule = cchPath + 1 + strlen(pszPlugIn) + sizeof(DBGC_PLUG_IN_PREFIX) + 8;
1756 char *pszModule = (char *)alloca(cchModule);
1757 AssertReturn(pszModule, VERR_TRY_AGAIN);
1758 memcpy(pszModule, pchPath, cchPath);
1759 pszModule[cchPath] = '\0';
1760
1761 int rc = RTPathAppend(pszModule, cchModule, DBGC_PLUG_IN_PREFIX);
1762 AssertRCReturn(rc, VERR_TRY_AGAIN);
1763 strcat(pszModule, pszPlugIn);
1764 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1765 if (RT_SUCCESS(rc))
1766 return VINF_SUCCESS;
1767
1768 pszModule[cchPath] = '\0';
1769 rc = RTPathAppend(pszModule, cchModule, pszPlugIn);
1770 AssertRCReturn(rc, VERR_TRY_AGAIN);
1771 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1772 if (RT_SUCCESS(rc))
1773 return VINF_SUCCESS;
1774
1775 return VERR_TRY_AGAIN;
1776}
1777
1778
1779/**
1780 * Loads a plug-in.
1781 *
1782 * @returns VBox status code. If pCmd is specified, it's the return from
1783 * DBGCCmdHlpFail.
1784 * @param pDbgc The DBGC instance data.
1785 * @param pszName The plug-in name.
1786 * @param pszPlugIn The plug-in module name.
1787 * @param pCmd The command pointer if invoked by the user, NULL
1788 * if invoked from elsewhere.
1789 */
1790static int dbgcPlugInLoad(PDBGC pDbgc, const char *pszName, const char *pszPlugIn, PCDBGCCMD pCmd)
1791{
1792 PDBGCCMDHLP pCmdHlp = &pDbgc->CmdHlp;
1793
1794 /*
1795 * Try load it. If specified with a path, we're assuming the user
1796 * wants to load a plug-in from some specific location. Otherwise
1797 * search for it.
1798 */
1799 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)RTMemAllocZ(sizeof(*pPlugIn));
1800 if (!pPlugIn)
1801 return pCmd
1802 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "out of memory\n")
1803 : VERR_NO_MEMORY;
1804 strcpy(pPlugIn->szName, pszName);
1805
1806 int rc;
1807 if (RTPathHavePath(pszPlugIn))
1808 rc = dbgcPlugInTryLoad(pPlugIn, pszPlugIn);
1809 else
1810 {
1811 /* 1. The private architecture directory. */
1812 char szPath[4*_1K];
1813 rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
1814 if (RT_SUCCESS(rc))
1815 rc = RTPathTraverseList(szPath, '\0', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1816 if (RT_FAILURE(rc))
1817 {
1818 /* 2. The DBGC PLUGIN_PATH variable. */
1819 DBGCVAR PathVar;
1820 int rc2 = DBGCCmdHlpEval(pCmdHlp, &PathVar, "$PLUGIN_PATH");
1821 if ( RT_SUCCESS(rc2)
1822 && PathVar.enmType == DBGCVAR_TYPE_STRING)
1823 rc = RTPathTraverseList(PathVar.u.pszString, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1824 if (RT_FAILURE_NP(rc))
1825 {
1826 /* 3. The DBGC_PLUGIN_PATH environment variable. */
1827 rc2 = RTEnvGetEx(RTENV_DEFAULT, "DBGC_PLUGIN_PATH", szPath, sizeof(szPath), NULL);
1828 if (RT_SUCCESS(rc2))
1829 rc = RTPathTraverseList(szPath, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1830 }
1831 }
1832 }
1833 if (RT_FAILURE(rc))
1834 {
1835 RTMemFree(pPlugIn);
1836 return pCmd
1837 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "could not find/load '%s'\n", pszPlugIn)
1838 : rc;
1839 }
1840
1841 /*
1842 * Try initialize it.
1843 */
1844 rc = pPlugIn->pfnEntry(DBGCPLUGINOP_INIT, pDbgc->pVM, VBOX_VERSION);
1845 if (RT_FAILURE(rc))
1846 {
1847 RTLdrClose(pPlugIn->hLdrMod);
1848 RTMemFree(pPlugIn);
1849 return pCmd
1850 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "initialization of plug-in '%s' failed with rc=%Rrc\n", pszPlugIn, rc)
1851 : rc;
1852 }
1853
1854 /*
1855 * Link it and we're good.
1856 */
1857 pPlugIn->pNext = pDbgc->pPlugInHead;
1858 pDbgc->pPlugInHead = pPlugIn;
1859 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s'.\n", pPlugIn->szName);
1860 return VINF_SUCCESS;
1861}
1862
1863
1864
1865
1866/**
1867 * Automatically load plug-ins from the architecture private directory of
1868 * VirtualBox.
1869 *
1870 * This is called during console init.
1871 *
1872 * @param pDbgc The DBGC instance data.
1873 */
1874void dbgcPlugInAutoLoad(PDBGC pDbgc)
1875{
1876 /*
1877 * Open the architecture specific directory with a filter on our prefix
1878 * and names including a dot.
1879 */
1880 const char *pszSuff = RTLdrGetSuff();
1881 size_t cchSuff = strlen(pszSuff);
1882
1883 char szPath[RTPATH_MAX];
1884 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
1885 AssertRCReturnVoid(rc);
1886 size_t offDir = strlen(szPath);
1887
1888 rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGC_PLUG_IN_PREFIX "*");
1889 AssertRCReturnVoid(rc);
1890 strcat(szPath, pszSuff);
1891
1892 PRTDIR pDir;
1893 rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT);
1894 if (RT_SUCCESS(rc))
1895 {
1896 /*
1897 * Now read it and try load each of the plug-in modules.
1898 */
1899 RTDIRENTRY DirEntry;
1900 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1901 {
1902 szPath[offDir] = '\0';
1903 rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
1904 if (RT_SUCCESS(rc))
1905 {
1906 char szName[DBGCPLUGIN_MAX_NAME];
1907 rc = dbgcPlugInExtractName(szName, DirEntry.szName);
1908 if (RT_SUCCESS(rc))
1909 dbgcPlugInLoad(pDbgc, szName, szPath, NULL /*pCmd*/);
1910 }
1911 }
1912
1913 RTDirClose(pDir);
1914 }
1915}
1916
1917
1918/**
1919 * The 'loadplugin' command.
1920 *
1921 * @returns VBox status.
1922 * @param pCmd Pointer to the command descriptor (as registered).
1923 * @param pCmdHlp Pointer to command helper functions.
1924 * @param pVM Pointer to the current VM (if any).
1925 * @param paArgs Pointer to (readonly) array of arguments.
1926 * @param cArgs Number of arguments in the array.
1927 */
1928static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1929{
1930 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1931
1932 /*
1933 * Loop thru the plugin names.
1934 */
1935 for (unsigned i = 0; i < cArgs; i++)
1936 {
1937 const char *pszPlugIn = paArgs[i].u.pszString;
1938
1939 /* Extract the plug-in name. */
1940 char szName[DBGCPLUGIN_MAX_NAME];
1941 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1942 if (RT_FAILURE(rc))
1943 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1944
1945 /* Loaded? */
1946 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, NULL);
1947 if (pPlugIn)
1948 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is already loaded\n", szName);
1949
1950 /* Load it. */
1951 rc = dbgcPlugInLoad(pDbgc, szName, pszPlugIn, pCmd);
1952 if (RT_FAILURE(rc))
1953 return rc;
1954 }
1955
1956 return VINF_SUCCESS;
1957}
1958
1959
1960/**
1961 * Unload all plug-ins.
1962 *
1963 * @param pDbgc The DBGC instance data.
1964 */
1965void dbgcPlugInUnloadAll(PDBGC pDbgc)
1966{
1967 while (pDbgc->pPlugInHead)
1968 {
1969 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
1970 pDbgc->pPlugInHead = pPlugIn->pNext;
1971
1972 if ( pDbgc->pVM /* prevents trouble during destruction. */
1973 && pDbgc->pVM->enmVMState < VMSTATE_DESTROYING)
1974 {
1975 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
1976 RTLdrClose(pPlugIn->hLdrMod);
1977 }
1978 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1979
1980 RTMemFree(pPlugIn);
1981 }
1982}
1983
1984
1985/**
1986 * The 'unload' command.
1987 *
1988 * @returns VBox status.
1989 * @param pCmd Pointer to the command descriptor (as registered).
1990 * @param pCmdHlp Pointer to command helper functions.
1991 * @param pVM Pointer to the current VM (if any).
1992 * @param paArgs Pointer to (readonly) array of arguments.
1993 * @param cArgs Number of arguments in the array.
1994 */
1995static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1996{
1997 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1998
1999 /*
2000 * Loop thru the plugin names.
2001 */
2002 for (unsigned i = 0; i < cArgs; i++)
2003 {
2004 const char *pszPlugIn = paArgs[i].u.pszString;
2005
2006 /* Extract the plug-in name. */
2007 char szName[DBGCPLUGIN_MAX_NAME];
2008 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
2009 if (RT_FAILURE(rc))
2010 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
2011
2012 /* Loaded? */
2013 PDBGCPLUGIN pPrevPlugIn;
2014 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, &pPrevPlugIn);
2015 if (!pPlugIn)
2016 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is not\n", szName);
2017
2018 /*
2019 * Terminate and unload it.
2020 */
2021 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
2022 RTLdrClose(pPlugIn->hLdrMod);
2023 pPlugIn->hLdrMod = NIL_RTLDRMOD;
2024
2025 if (pPrevPlugIn)
2026 pPrevPlugIn->pNext = pPlugIn->pNext;
2027 else
2028 pDbgc->pPlugInHead = pPlugIn->pNext;
2029 RTMemFree(pPlugIn->pNext);
2030 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", szName);
2031 }
2032
2033 return VINF_SUCCESS;
2034}
2035
2036
2037/**
2038 * The 'showplugins' command.
2039 *
2040 * @returns VBox status.
2041 * @param pCmd Pointer to the command descriptor (as registered).
2042 * @param pCmdHlp Pointer to command helper functions.
2043 * @param pVM Pointer to the current VM (if any).
2044 * @param paArgs Pointer to (readonly) array of arguments.
2045 * @param cArgs Number of arguments in the array.
2046 */
2047static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2048{
2049 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2050 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
2051 if (!pPlugIn)
2052 return DBGCCmdHlpPrintf(pCmdHlp, "No plug-ins loaded\n");
2053
2054 DBGCCmdHlpPrintf(pCmdHlp, "Plug-ins: %s", pPlugIn->szName);
2055 for (;;)
2056 {
2057 pPlugIn = pPlugIn->pNext;
2058 if (!pPlugIn)
2059 break;
2060 DBGCCmdHlpPrintf(pCmdHlp, ", %s", pPlugIn->szName);
2061 }
2062 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
2063}
2064
2065
2066
2067/**
2068 * The 'harakiri' command.
2069 *
2070 * @returns VBox status.
2071 * @param pCmd Pointer to the command descriptor (as registered).
2072 * @param pCmdHlp Pointer to command helper functions.
2073 * @param pVM Pointer to the current VM (if any).
2074 * @param paArgs Pointer to (readonly) array of arguments.
2075 * @param cArgs Number of arguments in the array.
2076 */
2077static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2078{
2079 Log(("dbgcCmdHarakiri\n"));
2080 for (;;)
2081 exit(126);
2082 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
2083}
2084
2085
2086/**
2087 * The 'writecore' command.
2088 *
2089 * @returns VBox status.
2090 * @param pCmd Pointer to the command descriptor (as registered).
2091 * @param pCmdHlp Pointer to command helper functions.
2092 * @param pVM Pointer to the current VM (if any).
2093 * @param paArgs Pointer to (readonly) array of arguments.
2094 * @param cArgs Number of arguments in the array.
2095 */
2096static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2097{
2098 Log(("dbgcCmdWriteCore\n"));
2099
2100 /*
2101 * Validate input, lots of paranoia here.
2102 */
2103 if ( cArgs != 1
2104 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
2105 {
2106 AssertMsgFailed(("Expected one string exactly!\n"));
2107 return VERR_PARSE_INCORRECT_ARG_TYPE;
2108 }
2109
2110 const char *pszDumpPath = paArgs[0].u.pszString;
2111 if (!pszDumpPath)
2112 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
2113
2114 int rc = DBGFR3CoreWrite(pVM, 0, pszDumpPath);
2115 if (RT_FAILURE(rc))
2116 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
2117
2118 return VINF_SUCCESS;
2119}
2120
Note: See TracBrowser for help on using the repository browser.

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