VirtualBox

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

Last change on this file since 38838 was 38838, checked in by vboxsync, 13 years ago

VMM,++: Try fix the async reset, suspend and power-off problems in PDM wrt conflicting VMM requests. Split them into priority requests and normal requests. The priority requests can safely be processed when PDM is doing async state change waits, the normal ones cannot. (The problem I bumped into was a unmap-chunk request from PGM being processed during PDMR3Reset, causing a recursive VMMR3EmtRendezvous deadlock.)

  • 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 38838 2011-09-23 11:21:55Z 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 int rc = DBGFR3InfoEx(pVM, pDbgc->idCpu,
909 paArgs[0].u.pszString,
910 cArgs == 2 ? paArgs[1].u.pszString : NULL,
911 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
912 if (RT_FAILURE(rc))
913 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3InfoEx()\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