VirtualBox

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

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

The debugger is back in the OSE.

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