VirtualBox

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

Last change on this file since 41575 was 41575, checked in by vboxsync, 12 years ago

Brushing up the help command.

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