VirtualBox

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

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

DBGF,PGM,DBGC: dumping page tables - hacking still in progress (sigh, this takes for ever).

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