VirtualBox

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

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

Debugger Console: Clean up, split the command evaluation code out of DBGConsole.cpp and into DBGCEval.cpp.

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