VirtualBox

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

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

DBGC: Made the parse cope with functions.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 81.2 KB
Line 
1/* $Id: DBGCCommands.cpp 41561 2012-06-04 12:10:19Z 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_NUMBER:
1067 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1068 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1069 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1070 paArgs[iArg].u.u64Number,
1071 paArgs[iArg].u.u64Number,
1072 paArgs[iArg].u.u64Number,
1073 paArgs[iArg].u64Range,
1074 apszRangeDesc[paArgs[iArg].enmRangeType]);
1075 else
1076 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1077 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1078 paArgs[iArg].u.u64Number,
1079 paArgs[iArg].u.u64Number,
1080 paArgs[iArg].u.u64Number);
1081 break;
1082
1083 default:
1084 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1085 "Invalid argument type %d\n",
1086 paArgs[iArg].enmType);
1087 break;
1088 }
1089 } /* arg loop */
1090
1091 NOREF(pCmd); NOREF(pVM);
1092 return 0;
1093}
1094
1095
1096/**
1097 * The 'loadimage' command.
1098 *
1099 * @returns VBox status.
1100 * @param pCmd Pointer to the command descriptor (as registered).
1101 * @param pCmdHlp Pointer to command helper functions.
1102 * @param pVM Pointer to the current VM (if any).
1103 * @param paArgs Pointer to (readonly) array of arguments.
1104 * @param cArgs Number of arguments in the array.
1105 */
1106static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1107{
1108 /*
1109 * Validate the parsing and make sense of the input.
1110 * This is a mess as usual because we don't trust the parser yet.
1111 */
1112 AssertReturn( cArgs >= 2
1113 && cArgs <= 3
1114 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1115 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1116 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1117
1118 const char *pszFilename = paArgs[0].u.pszString;
1119
1120 DBGFADDRESS ModAddress;
1121 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1122 if (RT_FAILURE(rc))
1123 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1124
1125 const char *pszModName = NULL;
1126 if (cArgs >= 3)
1127 {
1128 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1129 pszModName = paArgs[2].u.pszString;
1130 }
1131
1132 /*
1133 * Try create a module for it.
1134 */
1135 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1136 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1137 if (RT_FAILURE(rc))
1138 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1139 pszFilename, pszModName, &paArgs[1]);
1140
1141 NOREF(pCmd);
1142 return VINF_SUCCESS;
1143}
1144
1145
1146/**
1147 * The 'loadmap' command.
1148 *
1149 * @returns VBox status.
1150 * @param pCmd Pointer to the command descriptor (as registered).
1151 * @param pCmdHlp Pointer to command helper functions.
1152 * @param pVM Pointer to the current VM (if any).
1153 * @param paArgs Pointer to (readonly) array of arguments.
1154 * @param cArgs Number of arguments in the array.
1155 */
1156static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1157{
1158 /*
1159 * Validate the parsing and make sense of the input.
1160 * This is a mess as usual because we don't trust the parser yet.
1161 */
1162 AssertReturn( cArgs >= 2
1163 && cArgs <= 5
1164 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1165 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1166 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1167
1168 const char *pszFilename = paArgs[0].u.pszString;
1169
1170 DBGFADDRESS ModAddress;
1171 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1172 if (RT_FAILURE(rc))
1173 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1174
1175 const char *pszModName = NULL;
1176 if (cArgs >= 3)
1177 {
1178 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1179 pszModName = paArgs[2].u.pszString;
1180 }
1181
1182 RTGCUINTPTR uSubtrahend = 0;
1183 if (cArgs >= 4)
1184 {
1185 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1186 uSubtrahend = paArgs[3].u.u64Number;
1187 }
1188
1189 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1190 if (cArgs >= 5)
1191 {
1192 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1193 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1194 if ( iModSeg != paArgs[4].u.u64Number
1195 || iModSeg > RTDBGSEGIDX_LAST)
1196 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1197 }
1198
1199 /*
1200 * Try create a module for it.
1201 */
1202 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1203 rc = DBGFR3AsLoadMap(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1204 if (RT_FAILURE(rc))
1205 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1206 pszFilename, pszModName, &paArgs[1]);
1207
1208 NOREF(pCmd);
1209 return VINF_SUCCESS;
1210}
1211
1212
1213/**
1214 * The 'loadseg' command.
1215 *
1216 * @returns VBox status.
1217 * @param pCmd Pointer to the command descriptor (as registered).
1218 * @param pCmdHlp Pointer to command helper functions.
1219 * @param pVM Pointer to the current VM (if any).
1220 * @param paArgs Pointer to (readonly) array of arguments.
1221 * @param cArgs Number of arguments in the array.
1222 */
1223static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1224{
1225 /*
1226 * Validate the parsing and make sense of the input.
1227 * This is a mess as usual because we don't trust the parser yet.
1228 */
1229 AssertReturn( cArgs >= 3
1230 && cArgs <= 4
1231 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1232 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1233 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1234 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1235
1236 const char *pszFilename = paArgs[0].u.pszString;
1237
1238 DBGFADDRESS ModAddress;
1239 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1240 if (RT_FAILURE(rc))
1241 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1242
1243 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1244 if ( iModSeg != paArgs[2].u.u64Number
1245 || iModSeg > RTDBGSEGIDX_LAST)
1246 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1247
1248 const char *pszModName = NULL;
1249 if (cArgs >= 4)
1250 {
1251 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1252 pszModName = paArgs[3].u.pszString;
1253 }
1254
1255 /*
1256 * Call the debug info manager about this loading.
1257 */
1258 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1259 rc = DBGFR3AsLoadImage(pVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, iModSeg, 0 /*fFlags*/);
1260 if (RT_FAILURE(rc))
1261 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1262 pszFilename, pszModName, &paArgs[1]);
1263
1264 NOREF(pCmd);
1265 return VINF_SUCCESS;
1266}
1267
1268
1269/**
1270 * The 'loadsyms' command.
1271 *
1272 * @returns VBox status.
1273 * @param pCmd Pointer to the command descriptor (as registered).
1274 * @param pCmdHlp Pointer to command helper functions.
1275 * @param pVM Pointer to the current VM (if any).
1276 * @param paArgs Pointer to (readonly) array of arguments.
1277 * @param cArgs Number of arguments in the array.
1278 */
1279static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1280{
1281 /*
1282 * Validate the parsing and make sense of the input.
1283 * This is a mess as usual because we don't trust the parser yet.
1284 */
1285 if ( cArgs < 1
1286 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1287 {
1288 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
1289 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1290 }
1291 DBGCVAR AddrVar;
1292 RTGCUINTPTR Delta = 0;
1293 const char *pszModule = NULL;
1294 RTGCUINTPTR ModuleAddress = 0;
1295 unsigned cbModule = 0;
1296 if (cArgs > 1)
1297 {
1298 unsigned iArg = 1;
1299 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
1300 {
1301 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
1302 iArg++;
1303 }
1304 if (iArg < cArgs)
1305 {
1306 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
1307 {
1308 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
1309 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1310 }
1311 pszModule = paArgs[iArg].u.pszString;
1312 iArg++;
1313 if (iArg < cArgs)
1314 {
1315 if (!DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
1316 {
1317 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
1318 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1319 }
1320 int rc = DBGCCmdHlpEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
1321 if (RT_FAILURE(rc))
1322 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
1323 ModuleAddress = paArgs[iArg].u.GCFlat;
1324 iArg++;
1325 if (iArg < cArgs)
1326 {
1327 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
1328 {
1329 AssertMsgFailed(("Parse error, module argument required to be an integer!\n"));
1330 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1331 }
1332 cbModule = (unsigned)paArgs[iArg].u.u64Number;
1333 iArg++;
1334 if (iArg < cArgs)
1335 {
1336 AssertMsgFailed(("Parse error, too many arguments!\n"));
1337 return VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS;
1338 }
1339 }
1340 }
1341 }
1342 }
1343
1344 /*
1345 * Call the debug info manager about this loading...
1346 */
1347 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
1348 if (RT_FAILURE(rc))
1349 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %RGv, '%s', %RGv, 0)\n",
1350 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
1351
1352 NOREF(pCmd);
1353 return VINF_SUCCESS;
1354}
1355
1356
1357/**
1358 * The 'set' command.
1359 *
1360 * @returns VBox status.
1361 * @param pCmd Pointer to the command descriptor (as registered).
1362 * @param pCmdHlp Pointer to command helper functions.
1363 * @param pVM Pointer to the current VM (if any).
1364 * @param paArgs Pointer to (readonly) array of arguments.
1365 * @param cArgs Number of arguments in the array.
1366 */
1367static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1368{
1369 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1370
1371 /* parse sanity check. */
1372 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1373 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1374 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1375
1376
1377 /*
1378 * A variable must start with an alpha chars and only contain alpha numerical chars.
1379 */
1380 const char *pszVar = paArgs[0].u.pszString;
1381 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1382 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1383 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
1384
1385 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1386 *pszVar++;
1387 if (*pszVar)
1388 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1389 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
1390
1391
1392 /*
1393 * Calc variable size.
1394 */
1395 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1396 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1397 cbVar += 1 + (size_t)paArgs[1].u64Range;
1398
1399 /*
1400 * Look for existing one.
1401 */
1402 pszVar = paArgs[0].u.pszString;
1403 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1404 {
1405 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1406 {
1407 /*
1408 * Update existing variable.
1409 */
1410 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1411 if (!pv)
1412 return VERR_DBGC_PARSE_NO_MEMORY;
1413 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1414
1415 pVar->Var = paArgs[1];
1416 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1417 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1418 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1419 return 0;
1420 }
1421 }
1422
1423 /*
1424 * Allocate another.
1425 */
1426 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1427
1428 pVar->Var = paArgs[1];
1429 memcpy(pVar->szName, pszVar, (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
1433 /* need to reallocate the pointer array too? */
1434 if (!(pDbgc->cVars % 0x20))
1435 {
1436 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1437 if (!pv)
1438 {
1439 RTMemFree(pVar);
1440 return VERR_DBGC_PARSE_NO_MEMORY;
1441 }
1442 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1443 }
1444 pDbgc->papVars[pDbgc->cVars++] = pVar;
1445
1446 NOREF(pCmd); NOREF(pVM); NOREF(cArgs);
1447 return 0;
1448}
1449
1450
1451/**
1452 * The 'unset' command.
1453 *
1454 * @returns VBox status.
1455 * @param pCmd Pointer to the command descriptor (as registered).
1456 * @param pCmdHlp Pointer to command helper functions.
1457 * @param pVM Pointer to the current VM (if any).
1458 * @param paArgs Pointer to (readonly) array of arguments.
1459 * @param cArgs Number of arguments in the array.
1460 */
1461static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1462{
1463 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1464
1465 /*
1466 * Don't trust the parser.
1467 */
1468 for (unsigned i = 0; i < cArgs; i++)
1469 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
1470 {
1471 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
1472 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1473 }
1474
1475 /*
1476 * Iterate the variables and unset them.
1477 */
1478 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1479 {
1480 const char *pszVar = paArgs[iArg].u.pszString;
1481
1482 /*
1483 * Look up the variable.
1484 */
1485 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1486 {
1487 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1488 {
1489 /*
1490 * Shuffle the array removing this entry.
1491 */
1492 void *pvFree = pDbgc->papVars[iVar];
1493 if (iVar + 1 < pDbgc->cVars)
1494 memmove(&pDbgc->papVars[iVar],
1495 &pDbgc->papVars[iVar + 1],
1496 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1497 pDbgc->papVars[--pDbgc->cVars] = NULL;
1498
1499 RTMemFree(pvFree);
1500 }
1501 } /* lookup */
1502 } /* arg loop */
1503
1504 NOREF(pCmd); NOREF(pVM);
1505 return 0;
1506}
1507
1508
1509/**
1510 * The 'loadvars' command.
1511 *
1512 * @returns VBox status.
1513 * @param pCmd Pointer to the command descriptor (as registered).
1514 * @param pCmdHlp Pointer to command helper functions.
1515 * @param pVM Pointer to the current VM (if any).
1516 * @param paArgs Pointer to (readonly) array of arguments.
1517 * @param cArgs Number of arguments in the array.
1518 */
1519static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1520{
1521 /*
1522 * Don't trust the parser.
1523 */
1524 if ( cArgs != 1
1525 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1526 {
1527 AssertMsgFailed(("Expected one string exactly!\n"));
1528 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1529 }
1530
1531 /*
1532 * Iterate the variables and unset them.
1533 */
1534 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1535 if (pFile)
1536 {
1537 char szLine[4096];
1538 while (fgets(szLine, sizeof(szLine), pFile))
1539 {
1540 /* Strip it. */
1541 char *psz = szLine;
1542 while (RT_C_IS_BLANK(*psz))
1543 psz++;
1544 int i = (int)strlen(psz) - 1;
1545 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1546 psz[i--] ='\0';
1547 /* Execute it if not comment or empty line. */
1548 if ( *psz != '\0'
1549 && *psz != '#'
1550 && *psz != ';')
1551 {
1552 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
1553 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1554 }
1555 }
1556 fclose(pFile);
1557 }
1558 else
1559 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1560
1561 NOREF(pCmd); NOREF(pVM);
1562 return 0;
1563}
1564
1565
1566/**
1567 * The 'showvars' command.
1568 *
1569 * @returns VBox status.
1570 * @param pCmd Pointer to the command descriptor (as registered).
1571 * @param pCmdHlp Pointer to command helper functions.
1572 * @param pVM Pointer to the current VM (if any).
1573 * @param paArgs Pointer to (readonly) array of arguments.
1574 * @param cArgs Number of arguments in the array.
1575 */
1576static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1577{
1578 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1579
1580 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1581 {
1582 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
1583 if (!rc)
1584 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1);
1585 if (rc)
1586 return rc;
1587 }
1588
1589 NOREF(paArgs); NOREF(cArgs);
1590 return 0;
1591}
1592
1593
1594/**
1595 * Extracts the plugin name from a plugin specifier that may or may not include
1596 * path and/or suffix.
1597 *
1598 * @returns VBox status code.
1599 *
1600 * @param pszDst Where to return the name. At least DBGCPLUGIN_MAX_NAME
1601 * worth of buffer space.
1602 * @param pszPlugIn The plugin specifier to parse.
1603 */
1604static int dbgcPlugInExtractName(char *pszDst, const char *pszPlugIn)
1605{
1606 /*
1607 * Parse out the name stopping at the extension.
1608 */
1609 const char *pszName = RTPathFilename(pszPlugIn);
1610 if (!pszName || !*pszName)
1611 return VERR_INVALID_NAME;
1612 if (!RTStrNICmp(pszName, DBGC_PLUG_IN_PREFIX, sizeof(DBGC_PLUG_IN_PREFIX) - 1))
1613 {
1614 pszName += sizeof(DBGC_PLUG_IN_PREFIX) - 1;
1615 if (!*pszName)
1616 return VERR_INVALID_NAME;
1617 }
1618
1619 int ch;
1620 size_t cchName = 0;
1621 while ( (ch = pszName[cchName]) != '\0'
1622 && ch != '.')
1623 {
1624 if ( !RT_C_IS_ALPHA(ch)
1625 && ( !RT_C_IS_DIGIT(ch)
1626 || cchName == 0))
1627 return VERR_INVALID_NAME;
1628 cchName++;
1629 }
1630
1631 if (cchName >= DBGCPLUGIN_MAX_NAME)
1632 return VERR_OUT_OF_RANGE;
1633
1634 /*
1635 * We're very picky about the extension if there is no path.
1636 */
1637 if ( ch == '.'
1638 && !RTPathHavePath(pszPlugIn)
1639 && RTStrICmp(&pszName[cchName], RTLdrGetSuff()))
1640 return VERR_INVALID_NAME;
1641
1642 /*
1643 * Copy it.
1644 */
1645 memcpy(pszDst, pszName, cchName);
1646 pszDst[cchName] = '\0';
1647 return VINF_SUCCESS;
1648}
1649
1650
1651/**
1652 * Locate a plug-in in list.
1653 *
1654 * @returns Pointer to the plug-in tracking structure.
1655 * @param pDbgc Pointer to the DBGC instance data.
1656 * @param pszName The name of the plug-in we're looking for.
1657 * @param ppPrev Where to optionally return the pointer to the
1658 * previous list member.
1659 */
1660static PDBGCPLUGIN dbgcPlugInLocate(PDBGC pDbgc, const char *pszName, PDBGCPLUGIN *ppPrev)
1661{
1662 PDBGCPLUGIN pPrev = NULL;
1663 PDBGCPLUGIN pCur = pDbgc->pPlugInHead;
1664 while (pCur)
1665 {
1666 if (!RTStrICmp(pCur->szName, pszName))
1667 {
1668 if (ppPrev)
1669 *ppPrev = pPrev;
1670 return pCur;
1671 }
1672
1673 /* advance */
1674 pPrev = pCur;
1675 pCur = pCur->pNext;
1676 }
1677 return NULL;
1678}
1679
1680
1681/**
1682 * Try load the specified plug-in module.
1683 *
1684 * @returns VINF_SUCCESS on success, path error or loader error on failure.
1685 *
1686 * @param pPlugIn The plugin tracing record.
1687 * @param pszModule Module name.
1688 */
1689static int dbgcPlugInTryLoad(PDBGCPLUGIN pPlugIn, const char *pszModule)
1690{
1691 /*
1692 * Load it and try resolve the entry point.
1693 */
1694 int rc = RTLdrLoad(pszModule, &pPlugIn->hLdrMod);
1695 if (RT_SUCCESS(rc))
1696 {
1697 rc = RTLdrGetSymbol(pPlugIn->hLdrMod, DBGC_PLUG_IN_ENTRYPOINT, (void **)&pPlugIn->pfnEntry);
1698 if (RT_SUCCESS(rc))
1699 return VINF_SUCCESS;
1700 LogRel(("DBGC: RTLdrGetSymbol('%s', '%s',) -> %Rrc\n", pszModule, DBGC_PLUG_IN_ENTRYPOINT, rc));
1701
1702 RTLdrClose(pPlugIn->hLdrMod);
1703 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1704 }
1705 return rc;
1706}
1707
1708
1709/**
1710 * RTPathTraverseList callback.
1711 *
1712 * @returns See FNRTPATHTRAVERSER.
1713 *
1714 * @param pchPath See FNRTPATHTRAVERSER.
1715 * @param cchPath See FNRTPATHTRAVERSER.
1716 * @param pvUser1 The plug-in specifier.
1717 * @param pvUser2 The plug-in tracking record.
1718 */
1719static DECLCALLBACK(int) dbgcPlugInLoadCallback(const char *pchPath, size_t cchPath, void *pvUser1, void *pvUser2)
1720{
1721 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)pvUser2;
1722 const char *pszPlugIn = (const char *)pvUser1;
1723
1724 /*
1725 * Join the path and the specified plug-in module name, first with the
1726 * prefix and then without it.
1727 */
1728 size_t cchModule = cchPath + 1 + strlen(pszPlugIn) + sizeof(DBGC_PLUG_IN_PREFIX) + 8;
1729 char *pszModule = (char *)alloca(cchModule);
1730 AssertReturn(pszModule, VERR_TRY_AGAIN);
1731 memcpy(pszModule, pchPath, cchPath);
1732 pszModule[cchPath] = '\0';
1733
1734 int rc = RTPathAppend(pszModule, cchModule, DBGC_PLUG_IN_PREFIX);
1735 AssertRCReturn(rc, VERR_TRY_AGAIN);
1736 strcat(pszModule, pszPlugIn);
1737 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1738 if (RT_SUCCESS(rc))
1739 return VINF_SUCCESS;
1740
1741 pszModule[cchPath] = '\0';
1742 rc = RTPathAppend(pszModule, cchModule, pszPlugIn);
1743 AssertRCReturn(rc, VERR_TRY_AGAIN);
1744 rc = dbgcPlugInTryLoad(pPlugIn, pszModule);
1745 if (RT_SUCCESS(rc))
1746 return VINF_SUCCESS;
1747
1748 return VERR_TRY_AGAIN;
1749}
1750
1751
1752/**
1753 * Loads a plug-in.
1754 *
1755 * @returns VBox status code. If pCmd is specified, it's the return from
1756 * DBGCCmdHlpFail.
1757 * @param pDbgc The DBGC instance data.
1758 * @param pszName The plug-in name.
1759 * @param pszPlugIn The plug-in module name.
1760 * @param pCmd The command pointer if invoked by the user, NULL
1761 * if invoked from elsewhere.
1762 */
1763static int dbgcPlugInLoad(PDBGC pDbgc, const char *pszName, const char *pszPlugIn, PCDBGCCMD pCmd)
1764{
1765 PDBGCCMDHLP pCmdHlp = &pDbgc->CmdHlp;
1766
1767 /*
1768 * Try load it. If specified with a path, we're assuming the user
1769 * wants to load a plug-in from some specific location. Otherwise
1770 * search for it.
1771 */
1772 PDBGCPLUGIN pPlugIn = (PDBGCPLUGIN)RTMemAllocZ(sizeof(*pPlugIn));
1773 if (!pPlugIn)
1774 return pCmd
1775 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "out of memory\n")
1776 : VERR_NO_MEMORY;
1777 strcpy(pPlugIn->szName, pszName);
1778
1779 int rc;
1780 if (RTPathHavePath(pszPlugIn))
1781 rc = dbgcPlugInTryLoad(pPlugIn, pszPlugIn);
1782 else
1783 {
1784 /* 1. The private architecture directory. */
1785 char szPath[4*_1K];
1786 rc = RTPathAppPrivateArch(szPath, sizeof(szPath));
1787 if (RT_SUCCESS(rc))
1788 rc = RTPathTraverseList(szPath, '\0', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1789 if (RT_FAILURE(rc))
1790 {
1791 /* 2. The DBGC PLUGIN_PATH variable. */
1792 DBGCVAR PathVar;
1793 int rc2 = DBGCCmdHlpEval(pCmdHlp, &PathVar, "$PLUGIN_PATH");
1794 if ( RT_SUCCESS(rc2)
1795 && PathVar.enmType == DBGCVAR_TYPE_STRING)
1796 rc = RTPathTraverseList(PathVar.u.pszString, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1797 if (RT_FAILURE_NP(rc))
1798 {
1799 /* 3. The DBGC_PLUGIN_PATH environment variable. */
1800 rc2 = RTEnvGetEx(RTENV_DEFAULT, "DBGC_PLUGIN_PATH", szPath, sizeof(szPath), NULL);
1801 if (RT_SUCCESS(rc2))
1802 rc = RTPathTraverseList(szPath, ';', dbgcPlugInLoadCallback, (void *)pszPlugIn, pPlugIn);
1803 }
1804 }
1805 }
1806 if (RT_FAILURE(rc))
1807 {
1808 RTMemFree(pPlugIn);
1809 return pCmd
1810 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "could not find/load '%s'\n", pszPlugIn)
1811 : rc;
1812 }
1813
1814 /*
1815 * Try initialize it.
1816 */
1817 rc = pPlugIn->pfnEntry(DBGCPLUGINOP_INIT, pDbgc->pVM, VBOX_VERSION);
1818 if (RT_FAILURE(rc))
1819 {
1820 RTLdrClose(pPlugIn->hLdrMod);
1821 RTMemFree(pPlugIn);
1822 return pCmd
1823 ? DBGCCmdHlpFail(pCmdHlp, pCmd, "initialization of plug-in '%s' failed with rc=%Rrc\n", pszPlugIn, rc)
1824 : rc;
1825 }
1826
1827 /*
1828 * Link it and we're good.
1829 */
1830 pPlugIn->pNext = pDbgc->pPlugInHead;
1831 pDbgc->pPlugInHead = pPlugIn;
1832 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s'.\n", pPlugIn->szName);
1833 return VINF_SUCCESS;
1834}
1835
1836
1837
1838
1839/**
1840 * Automatically load plug-ins from the architecture private directory of
1841 * VirtualBox.
1842 *
1843 * This is called during console init.
1844 *
1845 * @param pDbgc The DBGC instance data.
1846 */
1847void dbgcPlugInAutoLoad(PDBGC pDbgc)
1848{
1849 /*
1850 * Open the architecture specific directory with a filter on our prefix
1851 * and names including a dot.
1852 */
1853 const char *pszSuff = RTLdrGetSuff();
1854 size_t cchSuff = strlen(pszSuff);
1855
1856 char szPath[RTPATH_MAX];
1857 int rc = RTPathAppPrivateArch(szPath, sizeof(szPath) - cchSuff);
1858 AssertRCReturnVoid(rc);
1859 size_t offDir = strlen(szPath);
1860
1861 rc = RTPathAppend(szPath, sizeof(szPath) - cchSuff, DBGC_PLUG_IN_PREFIX "*");
1862 AssertRCReturnVoid(rc);
1863 strcat(szPath, pszSuff);
1864
1865 PRTDIR pDir;
1866 rc = RTDirOpenFiltered(&pDir, szPath, RTDIRFILTER_WINNT, 0);
1867 if (RT_SUCCESS(rc))
1868 {
1869 /*
1870 * Now read it and try load each of the plug-in modules.
1871 */
1872 RTDIRENTRY DirEntry;
1873 while (RT_SUCCESS(RTDirRead(pDir, &DirEntry, NULL)))
1874 {
1875 szPath[offDir] = '\0';
1876 rc = RTPathAppend(szPath, sizeof(szPath), DirEntry.szName);
1877 if (RT_SUCCESS(rc))
1878 {
1879 char szName[DBGCPLUGIN_MAX_NAME];
1880 rc = dbgcPlugInExtractName(szName, DirEntry.szName);
1881 if (RT_SUCCESS(rc))
1882 dbgcPlugInLoad(pDbgc, szName, szPath, NULL /*pCmd*/);
1883 }
1884 }
1885
1886 RTDirClose(pDir);
1887 }
1888}
1889
1890
1891/**
1892 * The 'loadplugin' command.
1893 *
1894 * @returns VBox status.
1895 * @param pCmd Pointer to the command descriptor (as registered).
1896 * @param pCmdHlp Pointer to command helper functions.
1897 * @param pVM Pointer to the current VM (if any).
1898 * @param paArgs Pointer to (readonly) array of arguments.
1899 * @param cArgs Number of arguments in the array.
1900 */
1901static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1902{
1903 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1904
1905 /*
1906 * Loop thru the plugin names.
1907 */
1908 for (unsigned i = 0; i < cArgs; i++)
1909 {
1910 const char *pszPlugIn = paArgs[i].u.pszString;
1911
1912 /* Extract the plug-in name. */
1913 char szName[DBGCPLUGIN_MAX_NAME];
1914 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1915 if (RT_FAILURE(rc))
1916 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1917
1918 /* Loaded? */
1919 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, NULL);
1920 if (pPlugIn)
1921 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is already loaded\n", szName);
1922
1923 /* Load it. */
1924 rc = dbgcPlugInLoad(pDbgc, szName, pszPlugIn, pCmd);
1925 if (RT_FAILURE(rc))
1926 return rc;
1927 }
1928
1929 return VINF_SUCCESS;
1930}
1931
1932
1933/**
1934 * Unload all plug-ins.
1935 *
1936 * @param pDbgc The DBGC instance data.
1937 */
1938void dbgcPlugInUnloadAll(PDBGC pDbgc)
1939{
1940 while (pDbgc->pPlugInHead)
1941 {
1942 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
1943 pDbgc->pPlugInHead = pPlugIn->pNext;
1944
1945 if ( pDbgc->pVM /* prevents trouble during destruction. */
1946 && pDbgc->pVM->enmVMState < VMSTATE_DESTROYING)
1947 {
1948 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
1949 RTLdrClose(pPlugIn->hLdrMod);
1950 }
1951 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1952
1953 RTMemFree(pPlugIn);
1954 }
1955}
1956
1957
1958/**
1959 * The 'unload' command.
1960 *
1961 * @returns VBox status.
1962 * @param pCmd Pointer to the command descriptor (as registered).
1963 * @param pCmdHlp Pointer to command helper functions.
1964 * @param pVM Pointer to the current VM (if any).
1965 * @param paArgs Pointer to (readonly) array of arguments.
1966 * @param cArgs Number of arguments in the array.
1967 */
1968static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
1969{
1970 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1971
1972 /*
1973 * Loop thru the plugin names.
1974 */
1975 for (unsigned i = 0; i < cArgs; i++)
1976 {
1977 const char *pszPlugIn = paArgs[i].u.pszString;
1978
1979 /* Extract the plug-in name. */
1980 char szName[DBGCPLUGIN_MAX_NAME];
1981 int rc = dbgcPlugInExtractName(szName, pszPlugIn);
1982 if (RT_FAILURE(rc))
1983 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Malformed plug-in name: '%s'\n", pszPlugIn);
1984
1985 /* Loaded? */
1986 PDBGCPLUGIN pPrevPlugIn;
1987 PDBGCPLUGIN pPlugIn = dbgcPlugInLocate(pDbgc, szName, &pPrevPlugIn);
1988 if (!pPlugIn)
1989 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' is not\n", szName);
1990
1991 /*
1992 * Terminate and unload it.
1993 */
1994 pPlugIn->pfnEntry(DBGCPLUGINOP_TERM, pDbgc->pVM, 0);
1995 RTLdrClose(pPlugIn->hLdrMod);
1996 pPlugIn->hLdrMod = NIL_RTLDRMOD;
1997
1998 if (pPrevPlugIn)
1999 pPrevPlugIn->pNext = pPlugIn->pNext;
2000 else
2001 pDbgc->pPlugInHead = pPlugIn->pNext;
2002 RTMemFree(pPlugIn->pNext);
2003 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", szName);
2004 }
2005
2006 return VINF_SUCCESS;
2007}
2008
2009
2010/**
2011 * The 'showplugins' command.
2012 *
2013 * @returns VBox status.
2014 * @param pCmd Pointer to the command descriptor (as registered).
2015 * @param pCmdHlp Pointer to command helper functions.
2016 * @param pVM Pointer to the current VM (if any).
2017 * @param paArgs Pointer to (readonly) array of arguments.
2018 * @param cArgs Number of arguments in the array.
2019 */
2020static DECLCALLBACK(int) dbgcCmdShowPlugIns(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2021{
2022 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
2023 PDBGCPLUGIN pPlugIn = pDbgc->pPlugInHead;
2024 if (!pPlugIn)
2025 return DBGCCmdHlpPrintf(pCmdHlp, "No plug-ins loaded\n");
2026
2027 DBGCCmdHlpPrintf(pCmdHlp, "Plug-ins: %s", pPlugIn->szName);
2028 for (;;)
2029 {
2030 pPlugIn = pPlugIn->pNext;
2031 if (!pPlugIn)
2032 break;
2033 DBGCCmdHlpPrintf(pCmdHlp, ", %s", pPlugIn->szName);
2034 }
2035 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
2036}
2037
2038
2039
2040/**
2041 * The 'harakiri' command.
2042 *
2043 * @returns VBox status.
2044 * @param pCmd Pointer to the command descriptor (as registered).
2045 * @param pCmdHlp Pointer to command helper functions.
2046 * @param pVM Pointer to the current VM (if any).
2047 * @param paArgs Pointer to (readonly) array of arguments.
2048 * @param cArgs Number of arguments in the array.
2049 */
2050static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2051{
2052 Log(("dbgcCmdHarakiri\n"));
2053 for (;;)
2054 exit(126);
2055 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs);
2056}
2057
2058
2059/**
2060 * The 'writecore' command.
2061 *
2062 * @returns VBox status.
2063 * @param pCmd Pointer to the command descriptor (as registered).
2064 * @param pCmdHlp Pointer to command helper functions.
2065 * @param pVM Pointer to the current VM (if any).
2066 * @param paArgs Pointer to (readonly) array of arguments.
2067 * @param cArgs Number of arguments in the array.
2068 */
2069static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs)
2070{
2071 Log(("dbgcCmdWriteCore\n"));
2072
2073 /*
2074 * Validate input, lots of paranoia here.
2075 */
2076 if ( cArgs != 1
2077 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
2078 {
2079 AssertMsgFailed(("Expected one string exactly!\n"));
2080 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
2081 }
2082
2083 const char *pszDumpPath = paArgs[0].u.pszString;
2084 if (!pszDumpPath)
2085 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
2086
2087 int rc = DBGFR3CoreWrite(pVM, pszDumpPath, true /*fReplaceFile*/);
2088 if (RT_FAILURE(rc))
2089 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
2090
2091 return VINF_SUCCESS;
2092}
2093
2094
2095
2096/**
2097 * @callback_method_impl{The randu32() function implementation.}
2098 */
2099static DECLCALLBACK(int) dbgcFuncRandU32(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, uint32_t cArgs,
2100 PDBGCVAR pResult)
2101{
2102 AssertReturn(cArgs == 0, VERR_DBGC_PARSE_BUG);
2103 uint32_t u32 = RTRandU32();
2104 DBGCVAR_INIT_NUMBER(pResult, u32);
2105 NOREF(pFunc); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs);
2106 return VINF_SUCCESS;
2107}
2108
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