VirtualBox

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

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

PCDBGCCMD & PFNDBGCCMD: Drop the return type & variable. Functions will be added separately from commands (superset of DBGCCMD).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.0 KB
Line 
1/* $Id: DBGCCommands.cpp 35696 2011-01-24 18:03:33Z 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);
50static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
51static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
52static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
53static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
54static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
55static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
56static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
57static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
58static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
59static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
60static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
61static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
62static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
63static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
64static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
65static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
66static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
67static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
68static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
69static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
70static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
71static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
72static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
73static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs);
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, fFlags, pfnHandler pszSyntax, ....pszDescription */
225 { "bye", 0, 0, NULL, 0, 0, dbgcCmdQuit, "", "Exits the debugger." },
226 { "cpu", 0, 1, &g_aArgCpu[0], RT_ELEMENTS(g_aArgCpu), 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), 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, 0, dbgcCmdQuit, "", "Exits the debugger." },
229 { "format", 1, 1, &g_aArgAny[0], RT_ELEMENTS(g_aArgAny), 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },
230 { "detect", 0, 0, NULL, 0, 0, dbgcCmdDetect, "", "Detects or re-detects the guest os and starts the OS specific digger." },
231 { "harakiri", 0, 0, NULL, 0, 0, dbgcCmdHarakiri, "", "Kills debugger process." },
232 { "help", 0, ~0, &g_aArgHelp[0], RT_ELEMENTS(g_aArgHelp), 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), 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), 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), 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), 0, dbgcCmdLoadPlugIn,"<plugin1> [plugin2..N]", "Loads one or more plugins" },
242 { "loadseg", 3, 4, &g_aArgLoadSeg[0], RT_ELEMENTS(g_aArgLoadSeg), 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), 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), 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), 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },
248 { "logdest", 1, 1, &g_aArgLogDest[0], RT_ELEMENTS(g_aArgLogDest), 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },
249 { "logflags", 1, 1, &g_aArgLogFlags[0], RT_ELEMENTS(g_aArgLogFlags), 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },
250 { "quit", 0, 0, NULL, 0, 0, dbgcCmdQuit, "", "Exits the debugger." },
251 { "runscript", 1, 1, &g_aArgFilename[0], RT_ELEMENTS(g_aArgFilename), 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), 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },
254 { "showplugins",0, 0, NULL, 0, 0, dbgcCmdShowPlugIns,"", "List loaded plugins." },
255 { "showvars", 0, 0, NULL, 0, 0, dbgcCmdShowVars, "", "List all the defined variables." },
256 { "stop", 0, 0, NULL, 0, 0, dbgcCmdStop, "", "Stop execution." },
257 { "unloadplugin", 1, ~0, &g_aArgPlugIn[0], RT_ELEMENTS(g_aArgPlugIn), 0, dbgcCmdUnloadPlugIn, "<plugin1> [plugin2..N]", "Unloads one or more plugins." },
258 { "unset", 1, ~0, &g_aArgMultiStr[0], RT_ELEMENTS(g_aArgMultiStr), 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
259 { "writecore", 1, 1, &g_aArgWriteCore[0], RT_ELEMENTS(g_aArgWriteCore), 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)
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 return rc;
626}
627
628
629/**
630 * The 'quit', 'exit' and 'bye' commands.
631 *
632 * @returns VBox status.
633 * @param pCmd Pointer to the command descriptor (as registered).
634 * @param pCmdHlp Pointer to command helper functions.
635 * @param pVM Pointer to the current VM (if any).
636 * @param paArgs Pointer to (readonly) array of arguments.
637 * @param cArgs Number of arguments in the array.
638 */
639static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
640{
641 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
642 NOREF(pCmd);
643 NOREF(pVM);
644 NOREF(paArgs);
645 NOREF(cArgs);
646 return VERR_DBGC_QUIT;
647}
648
649
650/**
651 * The 'stop' command.
652 *
653 * @returns VBox status.
654 * @param pCmd Pointer to the command descriptor (as registered).
655 * @param pCmdHlp Pointer to command helper functions.
656 * @param pVM Pointer to the current VM (if any).
657 * @param paArgs Pointer to (readonly) array of arguments.
658 * @param cArgs Number of arguments in the array.
659 */
660static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
661{
662 /*
663 * Check if the VM is halted or not before trying to halt it.
664 */
665 int rc;
666 if (DBGFR3IsHalted(pVM))
667 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
668 else
669 {
670 rc = DBGFR3Halt(pVM);
671 if (RT_SUCCESS(rc))
672 rc = VWRN_DBGC_CMD_PENDING;
673 else
674 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
675 }
676
677 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs);
678 return rc;
679}
680
681
682/**
683 * The 'echo' command.
684 *
685 * @returns VBox status.
686 * @param pCmd Pointer to the command descriptor (as registered).
687 * @param pCmdHlp Pointer to command helper functions.
688 * @param pVM Pointer to the current VM (if any).
689 * @param paArgs Pointer to (readonly) array of arguments.
690 * @param cArgs Number of arguments in the array.
691 */
692static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
693{
694 /*
695 * Loop thru the arguments and print them with one space between.
696 */
697 int rc = 0;
698 for (unsigned i = 0; i < cArgs; i++)
699 {
700 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
701 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
702 else
703 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
704 if (RT_FAILURE(rc))
705 return rc;
706 }
707 NOREF(pCmd); NOREF(pVM);
708 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
709}
710
711
712/**
713 * The 'runscript' command.
714 *
715 * @returns VBox status.
716 * @param pCmd Pointer to the command descriptor (as registered).
717 * @param pCmdHlp Pointer to command helper functions.
718 * @param pVM Pointer to the current VM (if any).
719 * @param paArgs Pointer to (readonly) array of arguments.
720 * @param cArgs Number of arguments in the array.
721 */
722static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
723{
724 /* check that the parser did what it's supposed to do. */
725 if ( cArgs != 1
726 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
727 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
728
729 /** @todo Load the script here, but someone else should do the actual
730 * evaluation and execution of it. */
731
732 /*
733 * Try open the script.
734 */
735 const char *pszFilename = paArgs[0].u.pszString;
736 FILE *pFile = fopen(pszFilename, "r");
737 if (!pFile)
738 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
739
740 /*
741 * Execute it line by line.
742 */
743 int rc = 0;
744 unsigned iLine = 0;
745 char szLine[8192];
746 while (fgets(szLine, sizeof(szLine), pFile))
747 {
748 /* check that the line isn't too long. */
749 char *pszEnd = strchr(szLine, '\0');
750 if (pszEnd == &szLine[sizeof(szLine) - 1])
751 {
752 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
753 break;
754 }
755 iLine++;
756
757 /* strip leading blanks and check for comment / blank line. */
758 char *psz = RTStrStripL(szLine);
759 if ( *psz == '\0'
760 || *psz == '\n'
761 || *psz == '#')
762 continue;
763
764 /* strip trailing blanks and check for empty line (\r case). */
765 while ( pszEnd > psz
766 && RT_C_IS_SPACE(pszEnd[-1])) /* RT_C_IS_SPACE includes \n and \r normally. */
767 *--pszEnd = '\0';
768
769 /** @todo check for Control-C / Cancel at this point... */
770
771 /*
772 * Execute the command.
773 *
774 * This is a bit wasteful with scratch space btw., can fix it later.
775 * The whole return code crap should be fixed too, so that it's possible
776 * to know whether a command succeeded (RT_SUCCESS()) or failed, and
777 * more importantly why it failed.
778 */
779 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
780 if (RT_FAILURE(rc))
781 {
782 if (rc == VERR_BUFFER_OVERFLOW)
783 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
784 break;
785 }
786 if (rc == VWRN_DBGC_CMD_PENDING)
787 {
788 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
789 break;
790 }
791 }
792
793 fclose(pFile);
794
795 NOREF(pCmd); NOREF(pVM);
796 return rc;
797}
798
799
800/**
801 * The 'detect' command.
802 *
803 * @returns VBox status.
804 * @param pCmd Pointer to the command descriptor (as registered).
805 * @param pCmdHlp Pointer to command helper functions.
806 * @param pVM Pointer to the current VM (if any).
807 * @param paArgs Pointer to (readonly) array of arguments.
808 * @param cArgs Number of arguments in the array.
809 */
810static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
811{
812 /* check that the parser did what it's supposed to do. */
813 if (cArgs != 0)
814 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
815
816 /*
817 * Perform the detection.
818 */
819 char szName[64];
820 int rc = DBGFR3OSDetect(pVM, szName, sizeof(szName));
821 if (RT_FAILURE(rc))
822 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().");
823 if (rc == VINF_SUCCESS)
824 {
825 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Guest OS: %s\n", szName);
826 char szVersion[512];
827 int rc2 = DBGFR3OSQueryNameAndVersion(pVM, NULL, 0, szVersion, sizeof(szVersion));
828 if (RT_SUCCESS(rc2))
829 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Version : %s\n", szVersion);
830 }
831 else
832 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Unable to figure out which guest OS it is, sorry.\n");
833 NOREF(pCmd); NOREF(paArgs);
834 return rc;
835}
836
837
838/**
839 * The 'cpu' command.
840 *
841 * @returns VBox status.
842 * @param pCmd Pointer to the command descriptor (as registered).
843 * @param pCmdHlp Pointer to command helper functions.
844 * @param pVM Pointer to the current VM (if any).
845 * @param paArgs Pointer to (readonly) array of arguments.
846 * @param cArgs Number of arguments in the array.
847 */
848static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
849{
850 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
851
852 /* check that the parser did what it's supposed to do. */
853 if ( cArgs != 0
854 && ( cArgs != 1
855 || paArgs[0].enmType != DBGCVAR_TYPE_NUMBER))
856 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
857 if (!pVM)
858 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
859
860 int rc;
861 if (!cArgs)
862 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Current CPU ID: %u\n", pDbgc->idCpu);
863 else
864 {
865/** @todo add a DBGF getter for this. */
866 if (paArgs[0].u.u64Number >= pVM->cCpus)
867 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: idCpu %u is out of range! Highest ID is %u.\n",
868 paArgs[0].u.u64Number, pVM->cCpus);
869 else
870 {
871 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Changed CPU from %u to %u.\n",
872 pDbgc->idCpu, (VMCPUID)paArgs[0].u.u64Number);
873 pDbgc->idCpu = (VMCPUID)paArgs[0].u.u64Number;
874 }
875 }
876 return rc;
877}
878
879
880/**
881 * The 'info' command.
882 *
883 * @returns VBox status.
884 * @param pCmd Pointer to the command descriptor (as registered).
885 * @param pCmdHlp Pointer to command helper functions.
886 * @param pVM Pointer to the current VM (if any).
887 * @param paArgs Pointer to (readonly) array of arguments.
888 * @param cArgs Number of arguments in the array.
889 */
890static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
891{
892 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
893
894 /*
895 * Validate input.
896 */
897 if ( cArgs < 1
898 || cArgs > 2
899 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
900 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
901 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
902 if (!pVM)
903 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
904
905 /*
906 * Dump it.
907 */
908 /** @todo DBGFR3Info should do this, not we. */
909 int rc = VMR3ReqCallWait(pVM, pDbgc->idCpu, (PFNRT)DBGFR3Info, 4,
910 pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL,
911 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
912 if (RT_FAILURE(rc))
913 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
914
915 NOREF(pCmd);
916 return 0;
917}
918
919
920/**
921 * The 'log' command.
922 *
923 * @returns VBox status.
924 * @param pCmd Pointer to the command descriptor (as registered).
925 * @param pCmdHlp Pointer to command helper functions.
926 * @param pVM Pointer to the current VM (if any).
927 * @param paArgs Pointer to (readonly) array of arguments.
928 * @param cArgs Number of arguments in the array.
929 */
930static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
931{
932 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
933 if (RT_SUCCESS(rc))
934 return VINF_SUCCESS;
935 NOREF(pCmd); NOREF(cArgs);
936 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
937}
938
939
940/**
941 * The 'logdest' command.
942 *
943 * @returns VBox status.
944 * @param pCmd Pointer to the command descriptor (as registered).
945 * @param pCmdHlp Pointer to command helper functions.
946 * @param pVM Pointer to the current VM (if any).
947 * @param paArgs Pointer to (readonly) array of arguments.
948 * @param cArgs Number of arguments in the array.
949 */
950static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
951{
952 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
953 if (RT_SUCCESS(rc))
954 return VINF_SUCCESS;
955 NOREF(pCmd); NOREF(cArgs);
956 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
957}
958
959
960/**
961 * The 'logflags' command.
962 *
963 * @returns VBox status.
964 * @param pCmd Pointer to the command descriptor (as registered).
965 * @param pCmdHlp Pointer to command helper functions.
966 * @param pVM Pointer to the current VM (if any).
967 * @param paArgs Pointer to (readonly) array of arguments.
968 * @param cArgs Number of arguments in the array.
969 */
970static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
971{
972 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
973 if (RT_SUCCESS(rc))
974 return VINF_SUCCESS;
975 NOREF(pCmd); NOREF(cArgs);
976 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
977}
978
979
980/**
981 * The 'format' command.
982 *
983 * @returns VBox status.
984 * @param pCmd Pointer to the command descriptor (as registered).
985 * @param pCmdHlp Pointer to command helper functions.
986 * @param pVM Pointer to the current VM (if any).
987 * @param paArgs Pointer to (readonly) array of arguments.
988 * @param cArgs Number of arguments in the array.
989 */
990static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
991{
992 LogFlow(("dbgcCmdFormat\n"));
993 static const char *apszRangeDesc[] =
994 {
995 "none", "bytes", "elements"
996 };
997 int rc;
998
999 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1000 {
1001 switch (paArgs[iArg].enmType)
1002 {
1003 case DBGCVAR_TYPE_UNKNOWN:
1004 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1005 "Unknown variable type!\n");
1006 break;
1007 case DBGCVAR_TYPE_GC_FLAT:
1008 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1009 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1010 "Guest flat address: %%%08x range %lld %s\n",
1011 paArgs[iArg].u.GCFlat,
1012 paArgs[iArg].u64Range,
1013 apszRangeDesc[paArgs[iArg].enmRangeType]);
1014 else
1015 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1016 "Guest flat address: %%%08x\n",
1017 paArgs[iArg].u.GCFlat);
1018 break;
1019 case DBGCVAR_TYPE_GC_FAR:
1020 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1021 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1022 "Guest far address: %04x:%08x range %lld %s\n",
1023 paArgs[iArg].u.GCFar.sel,
1024 paArgs[iArg].u.GCFar.off,
1025 paArgs[iArg].u64Range,
1026 apszRangeDesc[paArgs[iArg].enmRangeType]);
1027 else
1028 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1029 "Guest far address: %04x:%08x\n",
1030 paArgs[iArg].u.GCFar.sel,
1031 paArgs[iArg].u.GCFar.off);
1032 break;
1033 case DBGCVAR_TYPE_GC_PHYS:
1034 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1035 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1036 "Guest physical address: %%%%%08x range %lld %s\n",
1037 paArgs[iArg].u.GCPhys,
1038 paArgs[iArg].u64Range,
1039 apszRangeDesc[paArgs[iArg].enmRangeType]);
1040 else
1041 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1042 "Guest physical address: %%%%%08x\n",
1043 paArgs[iArg].u.GCPhys);
1044 break;
1045 case DBGCVAR_TYPE_HC_FLAT:
1046 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1047 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1048 "Host flat address: %%%08x range %lld %s\n",
1049 paArgs[iArg].u.pvHCFlat,
1050 paArgs[iArg].u64Range,
1051 apszRangeDesc[paArgs[iArg].enmRangeType]);
1052 else
1053 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1054 "Host flat address: %%%08x\n",
1055 paArgs[iArg].u.pvHCFlat);
1056 break;
1057 case DBGCVAR_TYPE_HC_PHYS:
1058 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1059 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1060 "Host physical address: %RHp range %lld %s\n",
1061 paArgs[iArg].u.HCPhys,
1062 paArgs[iArg].u64Range,
1063 apszRangeDesc[paArgs[iArg].enmRangeType]);
1064 else
1065 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1066 "Host physical address: %RHp\n",
1067 paArgs[iArg].u.HCPhys);
1068 break;
1069
1070 case DBGCVAR_TYPE_STRING:
1071 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1072 "String, %lld bytes long: %s\n",
1073 paArgs[iArg].u64Range,
1074 paArgs[iArg].u.pszString);
1075 break;
1076
1077 case DBGCVAR_TYPE_NUMBER:
1078 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1079 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1080 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1081 paArgs[iArg].u.u64Number,
1082 paArgs[iArg].u.u64Number,
1083 paArgs[iArg].u.u64Number,
1084 paArgs[iArg].u64Range,
1085 apszRangeDesc[paArgs[iArg].enmRangeType]);
1086 else
1087 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1088 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1089 paArgs[iArg].u.u64Number,
1090 paArgs[iArg].u.u64Number,
1091 paArgs[iArg].u.u64Number);
1092 break;
1093
1094 default:
1095 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1096 "Invalid argument type %d\n",
1097 paArgs[iArg].enmType);
1098 break;
1099 }
1100 } /* arg loop */
1101
1102 NOREF(pCmd); NOREF(pVM);
1103 return 0;
1104}
1105
1106
1107/**
1108 * The 'loadimage' command.
1109 *
1110 * @returns VBox status.
1111 * @param pCmd Pointer to the command descriptor (as registered).
1112 * @param pCmdHlp Pointer to command helper functions.
1113 * @param pVM Pointer to the current VM (if any).
1114 * @param paArgs Pointer to (readonly) array of arguments.
1115 * @param cArgs Number of arguments in the array.
1116 */
1117static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1118{
1119 /*
1120 * Validate the parsing and make sense of the input.
1121 * This is a mess as usual because we don't trust the parser yet.
1122 */
1123 AssertReturn( cArgs >= 2
1124 && cArgs <= 3
1125 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1126 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1127 VERR_PARSE_INCORRECT_ARG_TYPE);
1128
1129 const char *pszFilename = paArgs[0].u.pszString;
1130
1131 DBGFADDRESS ModAddress;
1132 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1133 if (RT_FAILURE(rc))
1134 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1135
1136 const char *pszModName = NULL;
1137 if (cArgs >= 3)
1138 {
1139 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1140 pszModName = paArgs[2].u.pszString;
1141 }
1142
1143 /*
1144 * Try create a module for it.
1145 */
1146 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1147 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1148 if (RT_FAILURE(rc))
1149 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1150 pszFilename, pszModName, &paArgs[1]);
1151
1152 NOREF(pCmd);
1153 return VINF_SUCCESS;
1154}
1155
1156
1157/**
1158 * The 'loadmap' command.
1159 *
1160 * @returns VBox status.
1161 * @param pCmd Pointer to the command descriptor (as registered).
1162 * @param pCmdHlp Pointer to command helper functions.
1163 * @param pVM Pointer to the current VM (if any).
1164 * @param paArgs Pointer to (readonly) array of arguments.
1165 * @param cArgs Number of arguments in the array.
1166 */
1167static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1168{
1169 /*
1170 * Validate the parsing and make sense of the input.
1171 * This is a mess as usual because we don't trust the parser yet.
1172 */
1173 AssertReturn( cArgs >= 2
1174 && cArgs <= 5
1175 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1176 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1177 VERR_PARSE_INCORRECT_ARG_TYPE);
1178
1179 const char *pszFilename = paArgs[0].u.pszString;
1180
1181 DBGFADDRESS ModAddress;
1182 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1183 if (RT_FAILURE(rc))
1184 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1185
1186 const char *pszModName = NULL;
1187 if (cArgs >= 3)
1188 {
1189 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1190 pszModName = paArgs[2].u.pszString;
1191 }
1192
1193 RTGCUINTPTR uSubtrahend = 0;
1194 if (cArgs >= 4)
1195 {
1196 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1197 uSubtrahend = paArgs[3].u.u64Number;
1198 }
1199
1200 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1201 if (cArgs >= 5)
1202 {
1203 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_PARSE_INCORRECT_ARG_TYPE);
1204 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1205 if ( iModSeg != paArgs[4].u.u64Number
1206 || iModSeg > RTDBGSEGIDX_LAST)
1207 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1208 }
1209
1210 /*
1211 * Try create a module for it.
1212 */
1213 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1214 rc = DBGFR3AsLoadMap(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1215 if (RT_FAILURE(rc))
1216 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1217 pszFilename, pszModName, &paArgs[1]);
1218
1219 NOREF(pCmd);
1220 return VINF_SUCCESS;
1221}
1222
1223
1224/**
1225 * The 'loadseg' command.
1226 *
1227 * @returns VBox status.
1228 * @param pCmd Pointer to the command descriptor (as registered).
1229 * @param pCmdHlp Pointer to command helper functions.
1230 * @param pVM Pointer to the current VM (if any).
1231 * @param paArgs Pointer to (readonly) array of arguments.
1232 * @param cArgs Number of arguments in the array.
1233 */
1234static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1235{
1236 /*
1237 * Validate the parsing and make sense of the input.
1238 * This is a mess as usual because we don't trust the parser yet.
1239 */
1240 AssertReturn( cArgs >= 3
1241 && cArgs <= 4
1242 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1243 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1244 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1245 VERR_PARSE_INCORRECT_ARG_TYPE);
1246
1247 const char *pszFilename = paArgs[0].u.pszString;
1248
1249 DBGFADDRESS ModAddress;
1250 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1251 if (RT_FAILURE(rc))
1252 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1253
1254 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1255 if ( iModSeg != paArgs[2].u.u64Number
1256 || iModSeg > RTDBGSEGIDX_LAST)
1257 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1258
1259 const char *pszModName = NULL;
1260 if (cArgs >= 4)
1261 {
1262 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_PARSE_INCORRECT_ARG_TYPE);
1263 pszModName = paArgs[3].u.pszString;
1264 }
1265
1266 /*
1267 * Call the debug info manager about this loading.
1268 */
1269 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1270 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, iModSeg, 0 /*fFlags*/);
1271 if (RT_FAILURE(rc))
1272 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1273 pszFilename, pszModName, &paArgs[1]);
1274
1275 NOREF(pCmd);
1276 return VINF_SUCCESS;
1277}
1278
1279
1280/**
1281 * The 'loadsyms' command.
1282 *
1283 * @returns VBox status.
1284 * @param pCmd Pointer to the command descriptor (as registered).
1285 * @param pCmdHlp Pointer to command helper functions.
1286 * @param pVM Pointer to the current VM (if any).
1287 * @param paArgs Pointer to (readonly) array of arguments.
1288 * @param cArgs Number of arguments in the array.
1289 */
1290static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1291{
1292 /*
1293 * Validate the parsing and make sense of the input.
1294 * This is a mess as usual because we don't trust the parser yet.
1295 */
1296 if ( cArgs < 1
1297 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1298 {
1299 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
1300 return VERR_PARSE_INCORRECT_ARG_TYPE;
1301 }
1302 DBGCVAR AddrVar;
1303 RTGCUINTPTR Delta = 0;
1304 const char *pszModule = NULL;
1305 RTGCUINTPTR ModuleAddress = 0;
1306 unsigned cbModule = 0;
1307 if (cArgs > 1)
1308 {
1309 unsigned iArg = 1;
1310 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
1311 {
1312 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
1313 iArg++;
1314 }
1315 if (iArg < cArgs)
1316 {
1317 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
1318 {
1319 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
1320 return VERR_PARSE_INCORRECT_ARG_TYPE;
1321 }
1322 pszModule = paArgs[iArg].u.pszString;
1323 iArg++;
1324 if (iArg < cArgs)
1325 {
1326 if (!DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
1327 {
1328 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
1329 return VERR_PARSE_INCORRECT_ARG_TYPE;
1330 }
1331 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
1332 if (RT_FAILURE(rc))
1333 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
1334 ModuleAddress = paArgs[iArg].u.GCFlat;
1335 iArg++;
1336 if (iArg < cArgs)
1337 {
1338 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
1339 {
1340 AssertMsgFailed(("Parse error, module argument required to be an integer!\n"));
1341 return VERR_PARSE_INCORRECT_ARG_TYPE;
1342 }
1343 cbModule = (unsigned)paArgs[iArg].u.u64Number;
1344 iArg++;
1345 if (iArg < cArgs)
1346 {
1347 AssertMsgFailed(("Parse error, too many arguments!\n"));
1348 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1349 }
1350 }
1351 }
1352 }
1353 }
1354
1355 /*
1356 * Call the debug info manager about this loading...
1357 */
1358 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
1359 if (RT_FAILURE(rc))
1360 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %RGv, '%s', %RGv, 0)\n",
1361 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
1362
1363 NOREF(pCmd);
1364 return VINF_SUCCESS;
1365}
1366
1367
1368/**
1369 * The 'set' command.
1370 *
1371 * @returns VBox status.
1372 * @param pCmd Pointer to the command descriptor (as registered).
1373 * @param pCmdHlp Pointer to command helper functions.
1374 * @param pVM Pointer to the current VM (if any).
1375 * @param paArgs Pointer to (readonly) array of arguments.
1376 * @param cArgs Number of arguments in the array.
1377 */
1378static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1379{
1380 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1381
1382 /* parse sanity check. */
1383 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1384 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1385 return VERR_PARSE_INCORRECT_ARG_TYPE;
1386
1387
1388 /*
1389 * A variable must start with an alpha chars and only contain alpha numerical chars.
1390 */
1391 const char *pszVar = paArgs[0].u.pszString;
1392 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1393 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1394 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
1395
1396 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1397 *pszVar++;
1398 if (*pszVar)
1399 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1400 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
1401
1402
1403 /*
1404 * Calc variable size.
1405 */
1406 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1407 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1408 cbVar += 1 + (size_t)paArgs[1].u64Range;
1409
1410 /*
1411 * Look for existing one.
1412 */
1413 pszVar = paArgs[0].u.pszString;
1414 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1415 {
1416 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1417 {
1418 /*
1419 * Update existing variable.
1420 */
1421 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1422 if (!pv)
1423 return VERR_PARSE_NO_MEMORY;
1424 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1425
1426 pVar->Var = paArgs[1];
1427 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1428 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1429 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1430 return 0;
1431 }
1432 }
1433
1434 /*
1435 * Allocate another.
1436 */
1437 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1438
1439 pVar->Var = paArgs[1];
1440 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1441 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1442 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1443
1444 /* need to reallocate the pointer array too? */
1445 if (!(pDbgc->cVars % 0x20))
1446 {
1447 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1448 if (!pv)
1449 {
1450 RTMemFree(pVar);
1451 return VERR_PARSE_NO_MEMORY;
1452 }
1453 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1454 }
1455 pDbgc->papVars[pDbgc->cVars++] = pVar;
1456
1457 NOREF(pCmd); NOREF(pVM); NOREF(cArgs);
1458 return 0;
1459}
1460
1461
1462/**
1463 * The 'unset' command.
1464 *
1465 * @returns VBox status.
1466 * @param pCmd Pointer to the command descriptor (as registered).
1467 * @param pCmdHlp Pointer to command helper functions.
1468 * @param pVM Pointer to the current VM (if any).
1469 * @param paArgs Pointer to (readonly) array of arguments.
1470 * @param cArgs Number of arguments in the array.
1471 */
1472static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1473{
1474 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1475
1476 /*
1477 * Don't trust the parser.
1478 */
1479 for (unsigned i = 0; i < cArgs; i++)
1480 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
1481 {
1482 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
1483 return VERR_PARSE_INCORRECT_ARG_TYPE;
1484 }
1485
1486 /*
1487 * Iterate the variables and unset them.
1488 */
1489 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1490 {
1491 const char *pszVar = paArgs[iArg].u.pszString;
1492
1493 /*
1494 * Look up the variable.
1495 */
1496 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1497 {
1498 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1499 {
1500 /*
1501 * Shuffle the array removing this entry.
1502 */
1503 void *pvFree = pDbgc->papVars[iVar];
1504 if (iVar + 1 < pDbgc->cVars)
1505 memmove(&pDbgc->papVars[iVar],
1506 &pDbgc->papVars[iVar + 1],
1507 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1508 pDbgc->papVars[--pDbgc->cVars] = NULL;
1509
1510 RTMemFree(pvFree);
1511 }
1512 } /* lookup */
1513 } /* arg loop */
1514
1515 NOREF(pCmd); NOREF(pVM);
1516 return 0;
1517}
1518
1519
1520/**
1521 * The 'loadvars' command.
1522 *
1523 * @returns VBox status.
1524 * @param pCmd Pointer to the command descriptor (as registered).
1525 * @param pCmdHlp Pointer to command helper functions.
1526 * @param pVM Pointer to the current VM (if any).
1527 * @param paArgs Pointer to (readonly) array of arguments.
1528 * @param cArgs Number of arguments in the array.
1529 */
1530static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1531{
1532 /*
1533 * Don't trust the parser.
1534 */
1535 if ( cArgs != 1
1536 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1537 {
1538 AssertMsgFailed(("Expected one string exactly!\n"));
1539 return VERR_PARSE_INCORRECT_ARG_TYPE;
1540 }
1541
1542 /*
1543 * Iterate the variables and unset them.
1544 */
1545 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1546 if (pFile)
1547 {
1548 char szLine[4096];
1549 while (fgets(szLine, sizeof(szLine), pFile))
1550 {
1551 /* Strip it. */
1552 char *psz = szLine;
1553 while (RT_C_IS_BLANK(*psz))
1554 psz++;
1555 int i = (int)strlen(psz) - 1;
1556 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1557 psz[i--] ='\0';
1558 /* Execute it if not comment or empty line. */
1559 if ( *psz != '\0'
1560 && *psz != '#'
1561 && *psz != ';')
1562 {
1563 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
1564 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1565 }
1566 }
1567 fclose(pFile);
1568 }
1569 else
1570 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1571
1572 NOREF(pCmd); NOREF(pVM);
1573 return 0;
1574}
1575
1576
1577/**
1578 * The 'showvars' command.
1579 *
1580 * @returns VBox status.
1581 * @param pCmd Pointer to the command descriptor (as registered).
1582 * @param pCmdHlp Pointer to command helper functions.
1583 * @param pVM Pointer to the current VM (if any).
1584 * @param paArgs Pointer to (readonly) array of arguments.
1585 * @param cArgs Number of arguments in the array.
1586 */
1587static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1588{
1589 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1590
1591 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1592 {
1593 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
1594 if (!rc)
1595 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1);
1596 if (rc)
1597 return rc;
1598 }
1599
1600 NOREF(paArgs); NOREF(cArgs);
1601 return 0;
1602}
1603
1604
1605/**
1606 * Extracts the plugin name from a plugin specifier that may or may not include
1607 * path and/or suffix.
1608 *
1609 * @returns VBox status code.
1610 *
1611 * @param pszDst Where to return the name. At least DBGCPLUGIN_MAX_NAME
1612 * worth of buffer space.
1613 * @param pszPlugIn The plugin specifier to parse.
1614 */
1615static int dbgcPlugInExtractName(char *pszDst, const char *pszPlugIn)
1616{
1617 /*
1618 * Parse out the name stopping at the extension.
1619 */
1620 const char *pszName = RTPathFilename(pszPlugIn);
1621 if (!pszName || !*pszName)
1622 return VERR_INVALID_NAME;
1623 if (!RTStrNICmp(pszName, DBGC_PLUG_IN_PREFIX, sizeof(DBGC_PLUG_IN_PREFIX) - 1))
1624 {
1625 pszName += sizeof(DBGC_PLUG_IN_PREFIX) - 1;
1626 if (!*pszName)
1627 return VERR_INVALID_NAME;
1628 }
1629
1630 int ch;
1631 size_t cchName = 0;
1632 while ( (ch = pszName[cchName]) != '\0'
1633 && ch != '.')
1634 {
1635 if ( !RT_C_IS_ALPHA(ch)
1636 && ( !RT_C_IS_DIGIT(ch)
1637 || cchName == 0))
1638 return VERR_INVALID_NAME;
1639 cchName++;
1640 }
1641
1642 if (cchName >= DBGCPLUGIN_MAX_NAME)
1643 return VERR_OUT_OF_RANGE;
1644
1645 /*
1646 * We're very picky about the extension if there is no path.
1647 */
1648 if ( ch == '.'
1649 && !RTPathHavePath(pszPlugIn)
1650 && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
1651 return VERR_INVALID_NAME;
1652
1653 /*
1654 * Copy it.
1655 */
1656 memcpy(pszDst, pszName, cchName);
1657 pszDst[cchName] = '\0';
1658 return VINF_SUCCESS;
1659}
1660
1661
1662/**
1663 * Locate a plug-in in list.
1664 *
1665 * @returns Pointer to the plug-in tracking structure.
1666 * @param pDbgc Pointer to the DBGC instance data.
1667 * @param pszName The name of the plug-in we're looking for.
1668 * @param ppPrev Where to optionally return the pointer to the
1669 * previous list member.
1670 */
1671static PDBGCPLUGIN dbgcPlugInLocate(PDBGC pDbgc, const char *pszName, PDBGCPLUGIN *ppPrev)
1672{
1673 PDBGCPLUGIN pPrev = NULL;
1674 PDBGCPLUGIN pCur = pDbgc->pPlugInHead;
1675 while (pCur)
1676 {
1677 if (!RTStrICmp(pCur->szName, pszName))
1678 {
1679 if (ppPrev)
1680 *ppPrev = pPrev;
1681 return pCur;
1682 }
1683
1684 /* advance */
1685 pPrev = pCur;
1686 pCur = pCur->pNext;
1687 }
1688 return NULL;
1689}
1690
1691
1692/**
1693 * Try load the specified plug-in module.
1694 *
1695 * @returns VINF_SUCCESS on success, path error or loader error on failure.
1696 *
1697 * @param pPlugIn The plugin tracing record.
1698 * @param pszModule Module name.
1699 */
1700static int dbgcPlugInTryLoad(PDBGCPLUGIN pPlugIn, const char *pszModule)
1701{
1702 /*
1703 * Load it and try resolve the entry point.
1704 */
1705 int rc = RTLdrLoad(pszModule, &pPlugIn->hLdrMod);
1706 if (RT_SUCCESS(rc))
1707 {
1708 rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGC_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
1709 if (RT_SUCCESS(rc))
1710 return VINF_SUCCESS;
1711 LogRel(("DBGC: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGC_PLUG_IN_ENTRYPOINT, rc));
1712
1713 RTLdrClose(pPlugIn->hLdrMod);
1714 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1715 }
1716 return rc;
1717}
1718
1719
1720/**
1721 * RTPathTraverseList callback.
1722 *
1723 * @returns See FNRTPATHTRAVERSER.
1724 *
1725 * @param pchPath See FNRTPATHTRAVERSER.
1726 * @param cchPath See FNRTPATHTRAVERSER.
1727 * @param pvUser1 The plug-in specifier.
1728 * @param pvUser2 The plug-in tracking record.
1729 */
1730static DECLCALLBACK(int) dbgcPlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
1731{
1732 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)pvUser2;
1733 const char *pszPlugIn = (const char *)pvUser1;
1734
1735 /*
1736 * Join the path and the specified plug-in module name, first with the
1737 * prefix and then without it.
1738 */
1739 size_t cchModule = cchPath + 1 + strlen(pszPlugIn) + sizeof(DBGC_PLUG_IN_PREFIX) + 8;
1740 char *pszModule = (char *)alloca(cchModule);
1741 AssertReturn(pszModule, VERR_TRY_AGAIN);
1742 memcpy(pszModule, pchPath, cchPath);
1743 pszModule[cchPath] = '\0';
1744
1745 int rc = RTPathAppend(pszModule, cchModule, DBGC_PLUG_IN_PREFIX);
1746 AssertRCReturn(rc, VERR_TRY_AGAIN);
1747 strcat(pszModule, pszPlugIn);
1748 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1749 if (RT_SUCCESS(rc))
1750 return VINF_SUCCESS;
1751
1752 pszModule[cchPath] = '\0';
1753 rc = RTPathAppend(pszModule, cchModule, pszPlugIn);
1754 AssertRCReturn(rc, VERR_TRY_AGAIN);
1755 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1756 if (RT_SUCCESS(rc))
1757 return VINF_SUCCESS;
1758
1759 return VERR_TRY_AGAIN;
1760}
1761
1762
1763/**
1764 * Loads a plug-in.
1765 *
1766 * @returns VBox status code. If pCmd is specified, it's the return from
1767 * DBGCCmdHlpFail.
1768 * @param pDbgc The DBGC instance data.
1769 * @param pszName The plug-in name.
1770 * @param pszPlugIn The plug-in module name.
1771 * @param pCmd The command pointer if invoked by the user, NULL
1772 * if invoked from elsewhere.
1773 */
1774static int dbgcPlugInLoad(PDBGC pDbgc, const char *pszName, const char *pszPlugIn, PCDBGCCMD pCmd)
1775{
1776 PDBGCCMDHLP pCmdHlp = &pDbgc->CmdHlp;
1777
1778 /*
1779 * Try load it. If specified with a path, we're assuming the user
1780 * wants to load a plug-in from some specific location. Otherwise
1781 * search for it.
1782 */
1783 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)RTMemAllocZ(sizeof(*pPlugIn));
1784 if (!pPlugIn)
1785 return pCmd
1786 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "out of memory\n")
1787 : VERR_NO_MEMORY;
1788 strcpy(pPlugIn->szName, pszName);
1789
1790 int rc;
1791 if (RTPathHavePath(pszPlugIn))
1792 rc = dbgcPlugInTryLoad(pPlugIn, pszPlugIn);
1793 else
1794 {
1795 /* 1. The private architecture directory. */
1796 char szPath[4*_1K];
1797 rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
1798 if (RT_SUCCESS(rc))
1799 rc = RTPathTraverseList(szPath, '\0', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1800 if (RT_FAILURE(rc))
1801 {
1802 /* 2. The DBGC PLUGIN_PATH variable. */
1803 DBGCVAR PathVar;
1804 int rc2 = DBGCCmdHlpEval(pCmdHlp, &PathVar, "$PLUGIN_PATH");
1805 if ( RT_SUCCESS(rc2)
1806 && PathVar.enmType == DBGCVAR_TYPE_STRING)
1807 rc = RTPathTraverseList(PathVar.u.pszString, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1808 if (RT_FAILURE_NP(rc))
1809 {
1810 /* 3. The DBGC_PLUGIN_PATH environment variable. */
1811 rc2 = RTEnvGetEx(RTENV_DEFAULT, "DBGC_PLUGIN_PATH", szPath, sizeof(szPath), NULL);
1812 if (RT_SUCCESS(rc2))
1813 rc = RTPathTraverseList(szPath, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1814 }
1815 }
1816 }
1817 if (RT_FAILURE(rc))
1818 {
1819 RTMemFree(pPlugIn);
1820 return pCmd
1821 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "could not find/load '%s'\n", pszPlugIn)
1822 : rc;
1823 }
1824
1825 /*
1826 * Try initialize it.
1827 */
1828 rc = pPlugIn->pfnEntry(DBGCPLUGINOP_INIT, pDbgc->pVM, VBOX_VERSION);
1829 if (RT_FAILURE(rc))
1830 {
1831 RTLdrClose(pPlugIn->hLdrMod);
1832 RTMemFree(pPlugIn);
1833 return pCmd
1834 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "initialization of plug-in '%s' failed with rc=%Rrc\n", pszPlugIn, rc)
1835 : rc;
1836 }
1837
1838 /*
1839 * Link it and we're good.
1840 */
1841 pPlugIn->pNext = pDbgc->pPlugInHead;
1842 pDbgc->pPlugInHead = pPlugIn;
1843 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s'.\n", pPlugIn->szName);
1844 return VINF_SUCCESS;
1845}
1846
1847
1848
1849
1850/**
1851 * Automatically load plug-ins from the architecture private directory of
1852 * VirtualBox.
1853 *
1854 * This is called during console init.
1855 *
1856 * @param pDbgc The DBGC instance data.
1857 */
1858void dbgcPlugInAutoLoad(PDBGC pDbgc)
1859{
1860 /*
1861 * Open the architecture specific directory with a filter on our prefix
1862 * and names including a dot.
1863 */
1864 const char *pszSuff = RTLdrGetSuff();
1865 size_t cchSuff = strlen(pszSuff);
1866
1867 char szPath[RTPATH_MAX];
1868 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
1869 AssertRCReturnVoid(rc);
1870 size_t offDir = strlen(szPath);
1871
1872 rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGC_PLUG_IN_PREFIX "*");
1873 AssertRCReturnVoid(rc);
1874 strcat(szPath, pszSuff);
1875
1876 PRTDIR pDir;
1877 rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT);
1878 if (RT_SUCCESS(rc))
1879 {
1880 /*
1881 * Now read it and try load each of the plug-in modules.
1882 */
1883 RTDIRENTRY DirEntry;
1884 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1885 {
1886 szPath[offDir] = '\0';
1887 rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
1888 if (RT_SUCCESS(rc))
1889 {
1890 char szName[DBGCPLUGIN_MAX_NAME];
1891 rc = dbgcPlugInExtractName(szName, DirEntry.szName);
1892 if (RT_SUCCESS(rc))
1893 dbgcPlugInLoad(pDbgc, szName, szPath, NULL /*pCmd*/);
1894 }
1895 }
1896
1897 RTDirClose(pDir);
1898 }
1899}
1900
1901
1902/**
1903 * The 'loadplugin' command.
1904 *
1905 * @returns VBox status.
1906 * @param pCmd Pointer to the command descriptor (as registered).
1907 * @param pCmdHlp Pointer to command helper functions.
1908 * @param pVM Pointer to the current VM (if any).
1909 * @param paArgs Pointer to (readonly) array of arguments.
1910 * @param cArgs Number of arguments in the array.
1911 */
1912static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1913{
1914 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1915
1916 /*
1917 * Loop thru the plugin names.
1918 */
1919 for (unsigned i = 0; i < cArgs; i++)
1920 {
1921 const char *pszPlugIn = paArgs[i].u.pszString;
1922
1923 /* Extract the plug-in name. */
1924 char szName[DBGCPLUGIN_MAX_NAME];
1925 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1926 if (RT_FAILURE(rc))
1927 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1928
1929 /* Loaded? */
1930 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, NULL);
1931 if (pPlugIn)
1932 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is already loaded\n", szName);
1933
1934 /* Load it. */
1935 rc = dbgcPlugInLoad(pDbgc, szName, pszPlugIn, pCmd);
1936 if (RT_FAILURE(rc))
1937 return rc;
1938 }
1939
1940 return VINF_SUCCESS;
1941}
1942
1943
1944/**
1945 * Unload all plug-ins.
1946 *
1947 * @param pDbgc The DBGC instance data.
1948 */
1949void dbgcPlugInUnloadAll(PDBGC pDbgc)
1950{
1951 while (pDbgc->pPlugInHead)
1952 {
1953 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
1954 pDbgc->pPlugInHead = pPlugIn->pNext;
1955
1956 if ( pDbgc->pVM /* prevents trouble during destruction. */
1957 && pDbgc->pVM->enmVMState < VMSTATE_DESTROYING)
1958 {
1959 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
1960 RTLdrClose(pPlugIn->hLdrMod);
1961 }
1962 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1963
1964 RTMemFree(pPlugIn);
1965 }
1966}
1967
1968
1969/**
1970 * The 'unload' command.
1971 *
1972 * @returns VBox status.
1973 * @param pCmd Pointer to the command descriptor (as registered).
1974 * @param pCmdHlp Pointer to command helper functions.
1975 * @param pVM Pointer to the current VM (if any).
1976 * @param paArgs Pointer to (readonly) array of arguments.
1977 * @param cArgs Number of arguments in the array.
1978 */
1979static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1980{
1981 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1982
1983 /*
1984 * Loop thru the plugin names.
1985 */
1986 for (unsigned i = 0; i < cArgs; i++)
1987 {
1988 const char *pszPlugIn = paArgs[i].u.pszString;
1989
1990 /* Extract the plug-in name. */
1991 char szName[DBGCPLUGIN_MAX_NAME];
1992 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1993 if (RT_FAILURE(rc))
1994 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1995
1996 /* Loaded? */
1997 PDBGCPLUGIN pPrevPlugIn;
1998 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, &pPrevPlugIn);
1999 if (!pPlugIn)
2000 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is not\n", szName);
2001
2002 /*
2003 * Terminate and unload it.
2004 */
2005 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
2006 RTLdrClose(pPlugIn->hLdrMod);
2007 pPlugIn->hLdrMod = NIL_RTLDRMOD;
2008
2009 if (pPrevPlugIn)
2010 pPrevPlugIn->pNext = pPlugIn->pNext;
2011 else
2012 pDbgc->pPlugInHead = pPlugIn->pNext;
2013 RTMemFree(pPlugIn->pNext);
2014 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", szName);
2015 }
2016
2017 return VINF_SUCCESS;
2018}
2019
2020
2021/**
2022 * The 'showplugins' command.
2023 *
2024 * @returns VBox status.
2025 * @param pCmd Pointer to the command descriptor (as registered).
2026 * @param pCmdHlp Pointer to command helper functions.
2027 * @param pVM Pointer to the current VM (if any).
2028 * @param paArgs Pointer to (readonly) array of arguments.
2029 * @param cArgs Number of arguments in the array.
2030 */
2031static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2032{
2033 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2034 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
2035 if (!pPlugIn)
2036 return DBGCCmdHlpPrintf(pCmdHlp, "No plug-ins loaded\n");
2037
2038 DBGCCmdHlpPrintf(pCmdHlp, "Plug-ins: %s", pPlugIn->szName);
2039 for (;;)
2040 {
2041 pPlugIn = pPlugIn->pNext;
2042 if (!pPlugIn)
2043 break;
2044 DBGCCmdHlpPrintf(pCmdHlp, ", %s", pPlugIn->szName);
2045 }
2046 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
2047}
2048
2049
2050
2051/**
2052 * The 'harakiri' command.
2053 *
2054 * @returns VBox status.
2055 * @param pCmd Pointer to the command descriptor (as registered).
2056 * @param pCmdHlp Pointer to command helper functions.
2057 * @param pVM Pointer to the current VM (if any).
2058 * @param paArgs Pointer to (readonly) array of arguments.
2059 * @param cArgs Number of arguments in the array.
2060 */
2061static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2062{
2063 Log(("dbgcCmdHarakiri\n"));
2064 for (;;)
2065 exit(126);
2066 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs);
2067}
2068
2069
2070/**
2071 * The 'writecore' command.
2072 *
2073 * @returns VBox status.
2074 * @param pCmd Pointer to the command descriptor (as registered).
2075 * @param pCmdHlp Pointer to command helper functions.
2076 * @param pVM Pointer to the current VM (if any).
2077 * @param paArgs Pointer to (readonly) array of arguments.
2078 * @param cArgs Number of arguments in the array.
2079 */
2080static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2081{
2082 Log(("dbgcCmdWriteCore\n"));
2083
2084 /*
2085 * Validate input, lots of paranoia here.
2086 */
2087 if ( cArgs != 1
2088 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
2089 {
2090 AssertMsgFailed(("Expected one string exactly!\n"));
2091 return VERR_PARSE_INCORRECT_ARG_TYPE;
2092 }
2093
2094 const char *pszDumpPath = paArgs[0].u.pszString;
2095 if (!pszDumpPath)
2096 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
2097
2098 int rc = DBGFR3CoreWrite(pVM, pszDumpPath, true /*fReplaceFile*/);
2099 if (RT_FAILURE(rc))
2100 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
2101
2102 return VINF_SUCCESS;
2103}
2104
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