VirtualBox

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

Last change on this file since 93115 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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