VirtualBox

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

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

DBGC: Fixed cpu register references without @. Some symbol/string work. Updated the docs a little bit.

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