VirtualBox

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

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

DBGC: Working on making STRING the inflexible type and SYMBOL the flexible one.

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