VirtualBox

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

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

Debugger Console: Drop the HC_FAR type.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette