VirtualBox

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

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

Debugger: Updated the file headers.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 82.4 KB
Line 
1/* $Id: DBGCCommands.cpp 31530 2010-08-10 12:24:45Z 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 * Print formatted string.
877 *
878 * @param pHlp Pointer to this structure.
879 * @param pszFormat The format string.
880 * @param ... Arguments.
881 */
882static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
883{
884 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
885 va_list args;
886 va_start(args, pszFormat);
887 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
888 va_end(args);
889}
890
891
892/**
893 * Print formatted string.
894 *
895 * @param pHlp Pointer to this structure.
896 * @param pszFormat The format string.
897 * @param args Argument list.
898 */
899static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
900{
901 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
902 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
903}
904
905
906/**
907 * The 'info' command.
908 *
909 * @returns VBox status.
910 * @param pCmd Pointer to the command descriptor (as registered).
911 * @param pCmdHlp Pointer to command helper functions.
912 * @param pVM Pointer to the current VM (if any).
913 * @param paArgs Pointer to (readonly) array of arguments.
914 * @param cArgs Number of arguments in the array.
915 */
916static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
917{
918 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
919
920 /*
921 * Validate input.
922 */
923 if ( cArgs < 1
924 || cArgs > 2
925 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
926 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
927 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
928 if (!pVM)
929 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
930
931 /*
932 * Dump it.
933 */
934 struct
935 {
936 DBGFINFOHLP Hlp;
937 DBGCCMDHLP *pCmdHlp; /* XXX gcc warns when using PDBGCCMDHLP here */
938 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
939 int rc = VMR3ReqCallWait(pVM, pDbgc->idCpu,
940 (PFNRT)DBGFR3Info, 4, pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
941 if (RT_FAILURE(rc))
942 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
943
944 NOREF(pCmd); NOREF(pResult);
945 return 0;
946}
947
948
949/**
950 * The 'log' command.
951 *
952 * @returns VBox status.
953 * @param pCmd Pointer to the command descriptor (as registered).
954 * @param pCmdHlp Pointer to command helper functions.
955 * @param pVM Pointer to the current VM (if any).
956 * @param paArgs Pointer to (readonly) array of arguments.
957 * @param cArgs Number of arguments in the array.
958 */
959static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
960{
961 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
962 if (RT_SUCCESS(rc))
963 return VINF_SUCCESS;
964 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
965 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
966}
967
968
969/**
970 * The 'logdest' command.
971 *
972 * @returns VBox status.
973 * @param pCmd Pointer to the command descriptor (as registered).
974 * @param pCmdHlp Pointer to command helper functions.
975 * @param pVM Pointer to the current VM (if any).
976 * @param paArgs Pointer to (readonly) array of arguments.
977 * @param cArgs Number of arguments in the array.
978 */
979static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
980{
981 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
982 if (RT_SUCCESS(rc))
983 return VINF_SUCCESS;
984 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
985 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
986}
987
988
989/**
990 * The 'logflags' command.
991 *
992 * @returns VBox status.
993 * @param pCmd Pointer to the command descriptor (as registered).
994 * @param pCmdHlp Pointer to command helper functions.
995 * @param pVM Pointer to the current VM (if any).
996 * @param paArgs Pointer to (readonly) array of arguments.
997 * @param cArgs Number of arguments in the array.
998 */
999static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1000{
1001 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
1002 if (RT_SUCCESS(rc))
1003 return VINF_SUCCESS;
1004 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
1005 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
1006}
1007
1008
1009/**
1010 * The 'format' command.
1011 *
1012 * @returns VBox status.
1013 * @param pCmd Pointer to the command descriptor (as registered).
1014 * @param pCmdHlp Pointer to command helper functions.
1015 * @param pVM Pointer to the current VM (if any).
1016 * @param paArgs Pointer to (readonly) array of arguments.
1017 * @param cArgs Number of arguments in the array.
1018 */
1019static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1020{
1021 LogFlow(("dbgcCmdFormat\n"));
1022 static const char *apszRangeDesc[] =
1023 {
1024 "none", "bytes", "elements"
1025 };
1026 int rc;
1027
1028 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1029 {
1030 switch (paArgs[iArg].enmType)
1031 {
1032 case DBGCVAR_TYPE_UNKNOWN:
1033 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1034 "Unknown variable type!\n");
1035 break;
1036 case DBGCVAR_TYPE_GC_FLAT:
1037 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1038 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1039 "Guest flat address: %%%08x range %lld %s\n",
1040 paArgs[iArg].u.GCFlat,
1041 paArgs[iArg].u64Range,
1042 apszRangeDesc[paArgs[iArg].enmRangeType]);
1043 else
1044 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1045 "Guest flat address: %%%08x\n",
1046 paArgs[iArg].u.GCFlat);
1047 break;
1048 case DBGCVAR_TYPE_GC_FAR:
1049 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1050 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1051 "Guest far address: %04x:%08x range %lld %s\n",
1052 paArgs[iArg].u.GCFar.sel,
1053 paArgs[iArg].u.GCFar.off,
1054 paArgs[iArg].u64Range,
1055 apszRangeDesc[paArgs[iArg].enmRangeType]);
1056 else
1057 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1058 "Guest far address: %04x:%08x\n",
1059 paArgs[iArg].u.GCFar.sel,
1060 paArgs[iArg].u.GCFar.off);
1061 break;
1062 case DBGCVAR_TYPE_GC_PHYS:
1063 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1064 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1065 "Guest physical address: %%%%%08x range %lld %s\n",
1066 paArgs[iArg].u.GCPhys,
1067 paArgs[iArg].u64Range,
1068 apszRangeDesc[paArgs[iArg].enmRangeType]);
1069 else
1070 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1071 "Guest physical address: %%%%%08x\n",
1072 paArgs[iArg].u.GCPhys);
1073 break;
1074 case DBGCVAR_TYPE_HC_FLAT:
1075 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1076 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1077 "Host flat address: %%%08x range %lld %s\n",
1078 paArgs[iArg].u.pvHCFlat,
1079 paArgs[iArg].u64Range,
1080 apszRangeDesc[paArgs[iArg].enmRangeType]);
1081 else
1082 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1083 "Host flat address: %%%08x\n",
1084 paArgs[iArg].u.pvHCFlat);
1085 break;
1086 case DBGCVAR_TYPE_HC_FAR:
1087 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1088 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1089 "Host far address: %04x:%08x range %lld %s\n",
1090 paArgs[iArg].u.HCFar.sel,
1091 paArgs[iArg].u.HCFar.off,
1092 paArgs[iArg].u64Range,
1093 apszRangeDesc[paArgs[iArg].enmRangeType]);
1094 else
1095 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1096 "Host far address: %04x:%08x\n",
1097 paArgs[iArg].u.HCFar.sel,
1098 paArgs[iArg].u.HCFar.off);
1099 break;
1100 case DBGCVAR_TYPE_HC_PHYS:
1101 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1102 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1103 "Host physical address: %RHp range %lld %s\n",
1104 paArgs[iArg].u.HCPhys,
1105 paArgs[iArg].u64Range,
1106 apszRangeDesc[paArgs[iArg].enmRangeType]);
1107 else
1108 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1109 "Host physical address: %RHp\n",
1110 paArgs[iArg].u.HCPhys);
1111 break;
1112
1113 case DBGCVAR_TYPE_STRING:
1114 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1115 "String, %lld bytes long: %s\n",
1116 paArgs[iArg].u64Range,
1117 paArgs[iArg].u.pszString);
1118 break;
1119
1120 case DBGCVAR_TYPE_NUMBER:
1121 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1122 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1123 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1124 paArgs[iArg].u.u64Number,
1125 paArgs[iArg].u.u64Number,
1126 paArgs[iArg].u.u64Number,
1127 paArgs[iArg].u64Range,
1128 apszRangeDesc[paArgs[iArg].enmRangeType]);
1129 else
1130 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1131 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1132 paArgs[iArg].u.u64Number,
1133 paArgs[iArg].u.u64Number,
1134 paArgs[iArg].u.u64Number);
1135 break;
1136
1137 default:
1138 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1139 "Invalid argument type %d\n",
1140 paArgs[iArg].enmType);
1141 break;
1142 }
1143 } /* arg loop */
1144
1145 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1146 return 0;
1147}
1148
1149
1150/**
1151 * The 'loadimage' command.
1152 *
1153 * @returns VBox status.
1154 * @param pCmd Pointer to the command descriptor (as registered).
1155 * @param pCmdHlp Pointer to command helper functions.
1156 * @param pVM Pointer to the current VM (if any).
1157 * @param paArgs Pointer to (readonly) array of arguments.
1158 * @param cArgs Number of arguments in the array.
1159 */
1160static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1161{
1162 /*
1163 * Validate the parsing and make sense of the input.
1164 * This is a mess as usual because we don't trust the parser yet.
1165 */
1166 AssertReturn( cArgs >= 2
1167 && cArgs <= 3
1168 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1169 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1170 VERR_PARSE_INCORRECT_ARG_TYPE);
1171
1172 const char *pszFilename = paArgs[0].u.pszString;
1173
1174 DBGFADDRESS ModAddress;
1175 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1176 if (RT_FAILURE(rc))
1177 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1178
1179 const char *pszModName = NULL;
1180 if (cArgs >= 3)
1181 {
1182 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1183 pszModName = paArgs[2].u.pszString;
1184 }
1185
1186 /*
1187 * Try create a module for it.
1188 */
1189 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1190 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1191 if (RT_FAILURE(rc))
1192 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1193 pszFilename, pszModName, &paArgs[1]);
1194
1195 NOREF(pCmd); NOREF(pResult);
1196 return VINF_SUCCESS;
1197}
1198
1199
1200/**
1201 * The 'loadmap' command.
1202 *
1203 * @returns VBox status.
1204 * @param pCmd Pointer to the command descriptor (as registered).
1205 * @param pCmdHlp Pointer to command helper functions.
1206 * @param pVM Pointer to the current VM (if any).
1207 * @param paArgs Pointer to (readonly) array of arguments.
1208 * @param cArgs Number of arguments in the array.
1209 */
1210static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1211{
1212 /*
1213 * Validate the parsing and make sense of the input.
1214 * This is a mess as usual because we don't trust the parser yet.
1215 */
1216 AssertReturn( cArgs >= 2
1217 && cArgs <= 5
1218 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1219 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1220 VERR_PARSE_INCORRECT_ARG_TYPE);
1221
1222 const char *pszFilename = paArgs[0].u.pszString;
1223
1224 DBGFADDRESS ModAddress;
1225 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1226 if (RT_FAILURE(rc))
1227 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1228
1229 const char *pszModName = NULL;
1230 if (cArgs >= 3)
1231 {
1232 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1233 pszModName = paArgs[2].u.pszString;
1234 }
1235
1236 RTGCUINTPTR uSubtrahend = 0;
1237 if (cArgs >= 4)
1238 {
1239 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1240 uSubtrahend = paArgs[3].u.u64Number;
1241 }
1242
1243 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1244 if (cArgs >= 5)
1245 {
1246 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1247 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1248 if ( iModSeg != paArgs[4].u.u64Number
1249 || iModSeg > RTDBGSEGIDX_LAST)
1250 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1251 }
1252
1253 /*
1254 * Try create a module for it.
1255 */
1256 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1257 rc = DBGFR3AsLoadMap(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1258 if (RT_FAILURE(rc))
1259 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1260 pszFilename, pszModName, &paArgs[1]);
1261
1262 NOREF(pCmd); NOREF(pResult);
1263 return VINF_SUCCESS;
1264}
1265
1266
1267/**
1268 * The 'loadseg' command.
1269 *
1270 * @returns VBox status.
1271 * @param pCmd Pointer to the command descriptor (as registered).
1272 * @param pCmdHlp Pointer to command helper functions.
1273 * @param pVM Pointer to the current VM (if any).
1274 * @param paArgs Pointer to (readonly) array of arguments.
1275 * @param cArgs Number of arguments in the array.
1276 */
1277static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1278{
1279 /*
1280 * Validate the parsing and make sense of the input.
1281 * This is a mess as usual because we don't trust the parser yet.
1282 */
1283 AssertReturn( cArgs >= 3
1284 && cArgs <= 4
1285 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1286 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1287 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1288 VERR_PARSE_INCORRECT_ARG_TYPE);
1289
1290 const char *pszFilename = paArgs[0].u.pszString;
1291
1292 DBGFADDRESS ModAddress;
1293 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1294 if (RT_FAILURE(rc))
1295 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1296
1297 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1298 if ( iModSeg != paArgs[2].u.u64Number
1299 || iModSeg > RTDBGSEGIDX_LAST)
1300 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1301
1302 const char *pszModName = NULL;
1303 if (cArgs >= 4)
1304 {
1305 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1306 pszModName = paArgs[3].u.pszString;
1307 }
1308
1309 /*
1310 * Call the debug info manager about this loading.
1311 */
1312 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1313 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, iModSeg, 0 /*fFlags*/);
1314 if (RT_FAILURE(rc))
1315 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1316 pszFilename, pszModName, &paArgs[1]);
1317
1318 NOREF(pCmd); NOREF(pResult);
1319 return VINF_SUCCESS;
1320}
1321
1322
1323/**
1324 * The 'loadsyms' command.
1325 *
1326 * @returns VBox status.
1327 * @param pCmd Pointer to the command descriptor (as registered).
1328 * @param pCmdHlp Pointer to command helper functions.
1329 * @param pVM Pointer to the current VM (if any).
1330 * @param paArgs Pointer to (readonly) array of arguments.
1331 * @param cArgs Number of arguments in the array.
1332 */
1333static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1334{
1335 /*
1336 * Validate the parsing and make sense of the input.
1337 * This is a mess as usual because we don't trust the parser yet.
1338 */
1339 if ( cArgs < 1
1340 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1341 {
1342 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
1343 return VERR_PARSE_INCORRECT_ARG_TYPE;
1344 }
1345 DBGCVAR AddrVar;
1346 RTGCUINTPTR Delta = 0;
1347 const char *pszModule = NULL;
1348 RTGCUINTPTR ModuleAddress = 0;
1349 unsigned cbModule = 0;
1350 if (cArgs > 1)
1351 {
1352 unsigned iArg = 1;
1353 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
1354 {
1355 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
1356 iArg++;
1357 }
1358 if (iArg < cArgs)
1359 {
1360 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
1361 {
1362 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
1363 return VERR_PARSE_INCORRECT_ARG_TYPE;
1364 }
1365 pszModule = paArgs[iArg].u.pszString;
1366 iArg++;
1367 if (iArg < cArgs)
1368 {
1369 if (!DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
1370 {
1371 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
1372 return VERR_PARSE_INCORRECT_ARG_TYPE;
1373 }
1374 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
1375 if (RT_FAILURE(rc))
1376 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
1377 ModuleAddress = paArgs[iArg].u.GCFlat;
1378 iArg++;
1379 if (iArg < cArgs)
1380 {
1381 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
1382 {
1383 AssertMsgFailed(("Parse error, module argument required to be an integer!\n"));
1384 return VERR_PARSE_INCORRECT_ARG_TYPE;
1385 }
1386 cbModule = (unsigned)paArgs[iArg].u.u64Number;
1387 iArg++;
1388 if (iArg < cArgs)
1389 {
1390 AssertMsgFailed(("Parse error, too many arguments!\n"));
1391 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1392 }
1393 }
1394 }
1395 }
1396 }
1397
1398 /*
1399 * Call the debug info manager about this loading...
1400 */
1401 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
1402 if (RT_FAILURE(rc))
1403 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %RGv, '%s', %RGv, 0)\n",
1404 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
1405
1406 NOREF(pCmd); NOREF(pResult);
1407 return VINF_SUCCESS;
1408}
1409
1410
1411/**
1412 * The 'set' command.
1413 *
1414 * @returns VBox status.
1415 * @param pCmd Pointer to the command descriptor (as registered).
1416 * @param pCmdHlp Pointer to command helper functions.
1417 * @param pVM Pointer to the current VM (if any).
1418 * @param paArgs Pointer to (readonly) array of arguments.
1419 * @param cArgs Number of arguments in the array.
1420 */
1421static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1422{
1423 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1424
1425 /* parse sanity check. */
1426 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1427 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1428 return VERR_PARSE_INCORRECT_ARG_TYPE;
1429
1430
1431 /*
1432 * A variable must start with an alpha chars and only contain alpha numerical chars.
1433 */
1434 const char *pszVar = paArgs[0].u.pszString;
1435 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1436 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1437 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
1438
1439 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1440 *pszVar++;
1441 if (*pszVar)
1442 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1443 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
1444
1445
1446 /*
1447 * Calc variable size.
1448 */
1449 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1450 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1451 cbVar += 1 + (size_t)paArgs[1].u64Range;
1452
1453 /*
1454 * Look for existing one.
1455 */
1456 pszVar = paArgs[0].u.pszString;
1457 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1458 {
1459 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1460 {
1461 /*
1462 * Update existing variable.
1463 */
1464 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1465 if (!pv)
1466 return VERR_PARSE_NO_MEMORY;
1467 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1468
1469 pVar->Var = paArgs[1];
1470 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1471 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1472 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1473 return 0;
1474 }
1475 }
1476
1477 /*
1478 * Allocate another.
1479 */
1480 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1481
1482 pVar->Var = paArgs[1];
1483 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1484 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1485 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1486
1487 /* need to reallocate the pointer array too? */
1488 if (!(pDbgc->cVars % 0x20))
1489 {
1490 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1491 if (!pv)
1492 {
1493 RTMemFree(pVar);
1494 return VERR_PARSE_NO_MEMORY;
1495 }
1496 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1497 }
1498 pDbgc->papVars[pDbgc->cVars++] = pVar;
1499
1500 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
1501 return 0;
1502}
1503
1504
1505/**
1506 * The 'unset' command.
1507 *
1508 * @returns VBox status.
1509 * @param pCmd Pointer to the command descriptor (as registered).
1510 * @param pCmdHlp Pointer to command helper functions.
1511 * @param pVM Pointer to the current VM (if any).
1512 * @param paArgs Pointer to (readonly) array of arguments.
1513 * @param cArgs Number of arguments in the array.
1514 */
1515static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1516{
1517 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1518
1519 /*
1520 * Don't trust the parser.
1521 */
1522 for (unsigned i = 0; i < cArgs; i++)
1523 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
1524 {
1525 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
1526 return VERR_PARSE_INCORRECT_ARG_TYPE;
1527 }
1528
1529 /*
1530 * Iterate the variables and unset them.
1531 */
1532 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1533 {
1534 const char *pszVar = paArgs[iArg].u.pszString;
1535
1536 /*
1537 * Look up the variable.
1538 */
1539 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1540 {
1541 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1542 {
1543 /*
1544 * Shuffle the array removing this entry.
1545 */
1546 void *pvFree = pDbgc->papVars[iVar];
1547 if (iVar + 1 < pDbgc->cVars)
1548 memmove(&pDbgc->papVars[iVar],
1549 &pDbgc->papVars[iVar + 1],
1550 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1551 pDbgc->papVars[--pDbgc->cVars] = NULL;
1552
1553 RTMemFree(pvFree);
1554 }
1555 } /* lookup */
1556 } /* arg loop */
1557
1558 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1559 return 0;
1560}
1561
1562
1563/**
1564 * The 'loadvars' command.
1565 *
1566 * @returns VBox status.
1567 * @param pCmd Pointer to the command descriptor (as registered).
1568 * @param pCmdHlp Pointer to command helper functions.
1569 * @param pVM Pointer to the current VM (if any).
1570 * @param paArgs Pointer to (readonly) array of arguments.
1571 * @param cArgs Number of arguments in the array.
1572 */
1573static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1574{
1575 /*
1576 * Don't trust the parser.
1577 */
1578 if ( cArgs != 1
1579 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1580 {
1581 AssertMsgFailed(("Expected one string exactly!\n"));
1582 return VERR_PARSE_INCORRECT_ARG_TYPE;
1583 }
1584
1585 /*
1586 * Iterate the variables and unset them.
1587 */
1588 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1589 if (pFile)
1590 {
1591 char szLine[4096];
1592 while (fgets(szLine, sizeof(szLine), pFile))
1593 {
1594 /* Strip it. */
1595 char *psz = szLine;
1596 while (RT_C_IS_BLANK(*psz))
1597 psz++;
1598 int i = (int)strlen(psz) - 1;
1599 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1600 psz[i--] ='\0';
1601 /* Execute it if not comment or empty line. */
1602 if ( *psz != '\0'
1603 && *psz != '#'
1604 && *psz != ';')
1605 {
1606 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
1607 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1608 }
1609 }
1610 fclose(pFile);
1611 }
1612 else
1613 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1614
1615 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1616 return 0;
1617}
1618
1619
1620/**
1621 * The 'showvars' command.
1622 *
1623 * @returns VBox status.
1624 * @param pCmd Pointer to the command descriptor (as registered).
1625 * @param pCmdHlp Pointer to command helper functions.
1626 * @param pVM Pointer to the current VM (if any).
1627 * @param paArgs Pointer to (readonly) array of arguments.
1628 * @param cArgs Number of arguments in the array.
1629 */
1630static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1631{
1632 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1633
1634 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1635 {
1636 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
1637 if (!rc)
1638 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
1639 if (rc)
1640 return rc;
1641 }
1642
1643 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1644 return 0;
1645}
1646
1647
1648/**
1649 * Extracts the plugin name from a plugin specifier that may or may not include
1650 * path and/or suffix.
1651 *
1652 * @returns VBox status code.
1653 *
1654 * @param pszDst Where to return the name. At least DBGCPLUGIN_MAX_NAME
1655 * worth of buffer space.
1656 * @param pszPlugIn The plugin specifier to parse.
1657 */
1658static int dbgcPlugInExtractName(char *pszDst, const char *pszPlugIn)
1659{
1660 /*
1661 * Parse out the name stopping at the extension.
1662 */
1663 const char *pszName = RTPathFilename(pszPlugIn);
1664 if (!pszName || !*pszName)
1665 return VERR_INVALID_NAME;
1666 if (!RTStrNICmp(pszName, DBGC_PLUG_IN_PREFIX, sizeof(DBGC_PLUG_IN_PREFIX) - 1))
1667 {
1668 pszName += sizeof(DBGC_PLUG_IN_PREFIX) - 1;
1669 if (!*pszName)
1670 return VERR_INVALID_NAME;
1671 }
1672
1673 int ch;
1674 size_t cchName = 0;
1675 while ( (ch = pszName[cchName]) != '\0'
1676 && ch != '.')
1677 {
1678 if ( !RT_C_IS_ALPHA(ch)
1679 && ( !RT_C_IS_DIGIT(ch)
1680 || cchName == 0))
1681 return VERR_INVALID_NAME;
1682 cchName++;
1683 }
1684
1685 if (cchName >= DBGCPLUGIN_MAX_NAME)
1686 return VERR_OUT_OF_RANGE;
1687
1688 /*
1689 * We're very picky about the extension if there is no path.
1690 */
1691 if ( ch == '.'
1692 && !RTPathHavePath(pszPlugIn)
1693 && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
1694 return VERR_INVALID_NAME;
1695
1696 /*
1697 * Copy it.
1698 */
1699 memcpy(pszDst, pszName, cchName);
1700 pszDst[cchName] = '\0';
1701 return VINF_SUCCESS;
1702}
1703
1704
1705/**
1706 * Locate a plug-in in list.
1707 *
1708 * @returns Pointer to the plug-in tracking structure.
1709 * @param pDbgc Pointer to the DBGC instance data.
1710 * @param pszName The name of the plug-in we're looking for.
1711 * @param ppPrev Where to optionally return the pointer to the
1712 * previous list member.
1713 */
1714static PDBGCPLUGIN dbgcPlugInLocate(PDBGC pDbgc, const char *pszName, PDBGCPLUGIN *ppPrev)
1715{
1716 PDBGCPLUGIN pPrev = NULL;
1717 PDBGCPLUGIN pCur = pDbgc->pPlugInHead;
1718 while (pCur)
1719 {
1720 if (!RTStrICmp(pCur->szName, pszName))
1721 {
1722 if (ppPrev)
1723 *ppPrev = pPrev;
1724 return pCur;
1725 }
1726
1727 /* advance */
1728 pPrev = pCur;
1729 pCur = pCur->pNext;
1730 }
1731 return NULL;
1732}
1733
1734
1735/**
1736 * Try load the specified plug-in module.
1737 *
1738 * @returns VINF_SUCCESS on success, path error or loader error on failure.
1739 *
1740 * @param pPlugIn The plugin tracing record.
1741 * @param pszModule Module name.
1742 */
1743static int dbgcPlugInTryLoad(PDBGCPLUGIN pPlugIn, const char *pszModule)
1744{
1745 /*
1746 * Load it and try resolve the entry point.
1747 */
1748 int rc = RTLdrLoad(pszModule, &pPlugIn->hLdrMod);
1749 if (RT_SUCCESS(rc))
1750 {
1751 rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGC_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
1752 if (RT_SUCCESS(rc))
1753 return VINF_SUCCESS;
1754 LogRel(("DBGC: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGC_PLUG_IN_ENTRYPOINT, rc));
1755
1756 RTLdrClose(pPlugIn->hLdrMod);
1757 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1758 }
1759 return rc;
1760}
1761
1762
1763/**
1764 * RTPathTraverseList callback.
1765 *
1766 * @returns See FNRTPATHTRAVERSER.
1767 *
1768 * @param pchPath See FNRTPATHTRAVERSER.
1769 * @param cchPath See FNRTPATHTRAVERSER.
1770 * @param pvUser1 The plug-in specifier.
1771 * @param pvUser2 The plug-in tracking record.
1772 */
1773static DECLCALLBACK(int) dbgcPlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
1774{
1775 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)pvUser2;
1776 const char *pszPlugIn = (const char *)pvUser1;
1777
1778 /*
1779 * Join the path and the specified plug-in module name, first with the
1780 * prefix and then without it.
1781 */
1782 size_t cchModule = cchPath + 1 + strlen(pszPlugIn) + sizeof(DBGC_PLUG_IN_PREFIX) + 8;
1783 char *pszModule = (char *)alloca(cchModule);
1784 AssertReturn(pszModule, VERR_TRY_AGAIN);
1785 memcpy(pszModule, pchPath, cchPath);
1786 pszModule[cchPath] = '\0';
1787
1788 int rc = RTPathAppend(pszModule, cchModule, DBGC_PLUG_IN_PREFIX);
1789 AssertRCReturn(rc, VERR_TRY_AGAIN);
1790 strcat(pszModule, pszPlugIn);
1791 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1792 if (RT_SUCCESS(rc))
1793 return VINF_SUCCESS;
1794
1795 pszModule[cchPath] = '\0';
1796 rc = RTPathAppend(pszModule, cchModule, pszPlugIn);
1797 AssertRCReturn(rc, VERR_TRY_AGAIN);
1798 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1799 if (RT_SUCCESS(rc))
1800 return VINF_SUCCESS;
1801
1802 return VERR_TRY_AGAIN;
1803}
1804
1805
1806/**
1807 * Loads a plug-in.
1808 *
1809 * @returns VBox status code. If pCmd is specified, it's the return from
1810 * DBGCCmdHlpFail.
1811 * @param pDbgc The DBGC instance data.
1812 * @param pszName The plug-in name.
1813 * @param pszPlugIn The plug-in module name.
1814 * @param pCmd The command pointer if invoked by the user, NULL
1815 * if invoked from elsewhere.
1816 */
1817static int dbgcPlugInLoad(PDBGC pDbgc, const char *pszName, const char *pszPlugIn, PCDBGCCMD pCmd)
1818{
1819 PDBGCCMDHLP pCmdHlp = &pDbgc->CmdHlp;
1820
1821 /*
1822 * Try load it. If specified with a path, we're assuming the user
1823 * wants to load a plug-in from some specific location. Otherwise
1824 * search for it.
1825 */
1826 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)RTMemAllocZ(sizeof(*pPlugIn));
1827 if (!pPlugIn)
1828 return pCmd
1829 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "out of memory\n")
1830 : VERR_NO_MEMORY;
1831 strcpy(pPlugIn->szName, pszName);
1832
1833 int rc;
1834 if (RTPathHavePath(pszPlugIn))
1835 rc = dbgcPlugInTryLoad(pPlugIn, pszPlugIn);
1836 else
1837 {
1838 /* 1. The private architecture directory. */
1839 char szPath[4*_1K];
1840 rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
1841 if (RT_SUCCESS(rc))
1842 rc = RTPathTraverseList(szPath, '\0', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1843 if (RT_FAILURE(rc))
1844 {
1845 /* 2. The DBGC PLUGIN_PATH variable. */
1846 DBGCVAR PathVar;
1847 int rc2 = DBGCCmdHlpEval(pCmdHlp, &PathVar, "$PLUGIN_PATH");
1848 if ( RT_SUCCESS(rc2)
1849 && PathVar.enmType == DBGCVAR_TYPE_STRING)
1850 rc = RTPathTraverseList(PathVar.u.pszString, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1851 if (RT_FAILURE_NP(rc))
1852 {
1853 /* 3. The DBGC_PLUGIN_PATH environment variable. */
1854 rc2 = RTEnvGetEx(RTENV_DEFAULT, "DBGC_PLUGIN_PATH", szPath, sizeof(szPath), NULL);
1855 if (RT_SUCCESS(rc2))
1856 rc = RTPathTraverseList(szPath, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1857 }
1858 }
1859 }
1860 if (RT_FAILURE(rc))
1861 {
1862 RTMemFree(pPlugIn);
1863 return pCmd
1864 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "could not find/load '%s'\n", pszPlugIn)
1865 : rc;
1866 }
1867
1868 /*
1869 * Try initialize it.
1870 */
1871 rc = pPlugIn->pfnEntry(DBGCPLUGINOP_INIT, pDbgc->pVM, VBOX_VERSION);
1872 if (RT_FAILURE(rc))
1873 {
1874 RTLdrClose(pPlugIn->hLdrMod);
1875 RTMemFree(pPlugIn);
1876 return pCmd
1877 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "initialization of plug-in '%s' failed with rc=%Rrc\n", pszPlugIn, rc)
1878 : rc;
1879 }
1880
1881 /*
1882 * Link it and we're good.
1883 */
1884 pPlugIn->pNext = pDbgc->pPlugInHead;
1885 pDbgc->pPlugInHead = pPlugIn;
1886 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s'.\n", pPlugIn->szName);
1887 return VINF_SUCCESS;
1888}
1889
1890
1891
1892
1893/**
1894 * Automatically load plug-ins from the architecture private directory of
1895 * VirtualBox.
1896 *
1897 * This is called during console init.
1898 *
1899 * @param pDbgc The DBGC instance data.
1900 */
1901void dbgcPlugInAutoLoad(PDBGC pDbgc)
1902{
1903 /*
1904 * Open the architecture specific directory with a filter on our prefix
1905 * and names including a dot.
1906 */
1907 const char *pszSuff = RTLdrGetSuff();
1908 size_t cchSuff = strlen(pszSuff);
1909
1910 char szPath[RTPATH_MAX];
1911 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
1912 AssertRCReturnVoid(rc);
1913 size_t offDir = strlen(szPath);
1914
1915 rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGC_PLUG_IN_PREFIX "*");
1916 AssertRCReturnVoid(rc);
1917 strcat(szPath, pszSuff);
1918
1919 PRTDIR pDir;
1920 rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT);
1921 if (RT_SUCCESS(rc))
1922 {
1923 /*
1924 * Now read it and try load each of the plug-in modules.
1925 */
1926 RTDIRENTRY DirEntry;
1927 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1928 {
1929 szPath[offDir] = '\0';
1930 rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
1931 if (RT_SUCCESS(rc))
1932 {
1933 char szName[DBGCPLUGIN_MAX_NAME];
1934 rc = dbgcPlugInExtractName(szName, DirEntry.szName);
1935 if (RT_SUCCESS(rc))
1936 dbgcPlugInLoad(pDbgc, szName, szPath, NULL /*pCmd*/);
1937 }
1938 }
1939
1940 RTDirClose(pDir);
1941 }
1942}
1943
1944
1945/**
1946 * The 'loadplugin' command.
1947 *
1948 * @returns VBox status.
1949 * @param pCmd Pointer to the command descriptor (as registered).
1950 * @param pCmdHlp Pointer to command helper functions.
1951 * @param pVM Pointer to the current VM (if any).
1952 * @param paArgs Pointer to (readonly) array of arguments.
1953 * @param cArgs Number of arguments in the array.
1954 */
1955static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1956{
1957 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1958
1959 /*
1960 * Loop thru the plugin names.
1961 */
1962 for (unsigned i = 0; i < cArgs; i++)
1963 {
1964 const char *pszPlugIn = paArgs[i].u.pszString;
1965
1966 /* Extract the plug-in name. */
1967 char szName[DBGCPLUGIN_MAX_NAME];
1968 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1969 if (RT_FAILURE(rc))
1970 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1971
1972 /* Loaded? */
1973 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, NULL);
1974 if (pPlugIn)
1975 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is already loaded\n", szName);
1976
1977 /* Load it. */
1978 rc = dbgcPlugInLoad(pDbgc, szName, pszPlugIn, pCmd);
1979 if (RT_FAILURE(rc))
1980 return rc;
1981 }
1982
1983 return VINF_SUCCESS;
1984}
1985
1986
1987/**
1988 * Unload all plug-ins.
1989 *
1990 * @param pDbgc The DBGC instance data.
1991 */
1992void dbgcPlugInUnloadAll(PDBGC pDbgc)
1993{
1994 while (pDbgc->pPlugInHead)
1995 {
1996 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
1997 pDbgc->pPlugInHead = pPlugIn->pNext;
1998
1999 if ( pDbgc->pVM /* prevents trouble during destruction. */
2000 && pDbgc->pVM->enmVMState < VMSTATE_DESTROYING)
2001 {
2002 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
2003 RTLdrClose(pPlugIn->hLdrMod);
2004 }
2005 pPlugIn->hLdrMod = NIL_RTLDRMOD;
2006
2007 RTMemFree(pPlugIn);
2008 }
2009}
2010
2011
2012/**
2013 * The 'unload' command.
2014 *
2015 * @returns VBox status.
2016 * @param pCmd Pointer to the command descriptor (as registered).
2017 * @param pCmdHlp Pointer to command helper functions.
2018 * @param pVM Pointer to the current VM (if any).
2019 * @param paArgs Pointer to (readonly) array of arguments.
2020 * @param cArgs Number of arguments in the array.
2021 */
2022static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2023{
2024 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2025
2026 /*
2027 * Loop thru the plugin names.
2028 */
2029 for (unsigned i = 0; i < cArgs; i++)
2030 {
2031 const char *pszPlugIn = paArgs[i].u.pszString;
2032
2033 /* Extract the plug-in name. */
2034 char szName[DBGCPLUGIN_MAX_NAME];
2035 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
2036 if (RT_FAILURE(rc))
2037 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
2038
2039 /* Loaded? */
2040 PDBGCPLUGIN pPrevPlugIn;
2041 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, &pPrevPlugIn);
2042 if (!pPlugIn)
2043 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is not\n", szName);
2044
2045 /*
2046 * Terminate and unload it.
2047 */
2048 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
2049 RTLdrClose(pPlugIn->hLdrMod);
2050 pPlugIn->hLdrMod = NIL_RTLDRMOD;
2051
2052 if (pPrevPlugIn)
2053 pPrevPlugIn->pNext = pPlugIn->pNext;
2054 else
2055 pDbgc->pPlugInHead = pPlugIn->pNext;
2056 RTMemFree(pPlugIn->pNext);
2057 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", szName);
2058 }
2059
2060 return VINF_SUCCESS;
2061}
2062
2063
2064/**
2065 * The 'showplugins' command.
2066 *
2067 * @returns VBox status.
2068 * @param pCmd Pointer to the command descriptor (as registered).
2069 * @param pCmdHlp Pointer to command helper functions.
2070 * @param pVM Pointer to the current VM (if any).
2071 * @param paArgs Pointer to (readonly) array of arguments.
2072 * @param cArgs Number of arguments in the array.
2073 */
2074static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2075{
2076 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2077 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
2078 if (!pPlugIn)
2079 return DBGCCmdHlpPrintf(pCmdHlp, "No plug-ins loaded\n");
2080
2081 DBGCCmdHlpPrintf(pCmdHlp, "Plug-ins: %s", pPlugIn->szName);
2082 for (;;)
2083 {
2084 pPlugIn = pPlugIn->pNext;
2085 if (!pPlugIn)
2086 break;
2087 DBGCCmdHlpPrintf(pCmdHlp, ", %s", pPlugIn->szName);
2088 }
2089 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
2090}
2091
2092
2093
2094/**
2095 * The 'harakiri' command.
2096 *
2097 * @returns VBox status.
2098 * @param pCmd Pointer to the command descriptor (as registered).
2099 * @param pCmdHlp Pointer to command helper functions.
2100 * @param pVM Pointer to the current VM (if any).
2101 * @param paArgs Pointer to (readonly) array of arguments.
2102 * @param cArgs Number of arguments in the array.
2103 */
2104static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
2105{
2106 Log(("dbgcCmdHarakiri\n"));
2107 for (;;)
2108 exit(126);
2109 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
2110}
2111
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