VirtualBox

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

Last change on this file was 103433, checked in by vboxsync, 3 months ago

Debugger: Some warning fixes, bugref:3409

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

© 2023 Oracle
ContactPrivacy policyTerms of Use