VirtualBox

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

Last change on this file since 86100 was 86100, checked in by vboxsync, 4 years ago

Debugger: Add 'writegstmem' command to load data from a file and write it to guest memory at a particular address

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 79.9 KB
Line 
1/* $Id: DBGCCommands.cpp 86100 2020-09-13 08:15:53Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Native Commands.
4 */
5
6/*
7 * Copyright (C) 2006-2020 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 if (pCur)
418 {
419 pCur->cCmds = cCommands;
420 pCur->paCmds = paCommands;
421 pCur->pNext = g_pExtCmdsHead;
422 g_pExtCmdsHead = pCur;
423 }
424 else
425 rc = VERR_NO_MEMORY;
426 DBGCEXTLISTS_UNLOCK_WR();
427
428 return rc;
429}
430
431
432/**
433 * Deregister one or more external commands previously registered by
434 * DBGCRegisterCommands().
435 *
436 * @returns VBox status code.
437 * @param paCommands Pointer to an array of command descriptors
438 * as given to DBGCRegisterCommands().
439 * @param cCommands Number of commands.
440 */
441DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
442{
443 /*
444 * Lock the list.
445 */
446 DBGCEXTLISTS_LOCK_WR();
447 PDBGCEXTCMDS pPrev = NULL;
448 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
449 while (pCur)
450 {
451 if (paCommands == pCur->paCmds)
452 {
453 if (pPrev)
454 pPrev->pNext = pCur->pNext;
455 else
456 g_pExtCmdsHead = pCur->pNext;
457 DBGCEXTLISTS_UNLOCK_WR();
458
459 RTMemFree(pCur);
460 return VINF_SUCCESS;
461 }
462 pPrev = pCur;
463 pCur = pCur->pNext;
464 }
465 DBGCEXTLISTS_UNLOCK_WR();
466
467 NOREF(cCommands);
468 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
469}
470
471
472/**
473 * Outputs a command or function summary line.
474 *
475 * @returns Output status code
476 * @param pCmdHlp The command helpers.
477 * @param pszName The name of the function or command.
478 * @param fExternal Whether it's external.
479 * @param pszSyntax The syntax.
480 * @param pszDescription The description.
481 */
482static int dbgcCmdHelpCmdOrFunc(PDBGCCMDHLP pCmdHlp, const char *pszName, bool fExternal,
483 const char *pszSyntax, const char *pszDescription)
484{
485 /*
486 * Aiming for "%-11s %-30s %s". Need to adjust when any of the two
487 * columns are two wide as well as break the last column up if its
488 * too wide.
489 */
490 size_t const cchMaxWidth = 100;
491 size_t const cchCol1 = 11;
492 size_t const cchCol2 = 30;
493 size_t const cchCol3 = cchMaxWidth - cchCol1 - cchCol2 - 2;
494
495 size_t const cchName = strlen(pszName) + fExternal;
496 size_t const cchSyntax = strlen(pszSyntax);
497 size_t cchDesc = strlen(pszDescription);
498
499 /* Can we do it the simple + fast way? */
500 if ( cchName <= cchCol1
501 && cchSyntax <= cchCol2
502 && cchDesc <= cchCol3)
503 return DBGCCmdHlpPrintf(pCmdHlp,
504 !fExternal ? "%-*s %-*s %s\n" : ".%-*s %-*s %s\n",
505 cchCol1, pszName,
506 cchCol2, pszSyntax,
507 pszDescription);
508
509 /* Column 1. */
510 size_t off = 0;
511 DBGCCmdHlpPrintf(pCmdHlp, !fExternal ? "%s" : ".%s", pszName);
512 off += cchName;
513 ssize_t cchPadding = cchCol1 - off;
514 if (cchPadding <= 0)
515 cchPadding = 0;
516
517 /* Column 2. */
518 DBGCCmdHlpPrintf(pCmdHlp, "%*s %s", cchPadding, "", pszSyntax);
519 off += cchPadding + 1 + cchSyntax;
520 cchPadding = cchCol1 + 1 + cchCol2 - off;
521 if (cchPadding <= 0)
522 cchPadding = 0;
523 off += cchPadding;
524
525 /* Column 3. */
526 for (;;)
527 {
528 ssize_t cchCurWidth = cchMaxWidth - off - 1;
529 if (cchCurWidth != (ssize_t)cchCol3)
530 DBGCCmdHlpPrintf(pCmdHlp, "\n");
531 else if ((ssize_t)cchDesc <= cchCurWidth)
532 return DBGCCmdHlpPrintf(pCmdHlp, "%*s %s\n", cchPadding, "", pszDescription);
533 else
534 {
535 /* Split on preceeding blank. */
536 const char *pszEnd = &pszDescription[cchCurWidth];
537 if (!RT_C_IS_BLANK(*pszEnd))
538 while (pszEnd != pszDescription && !RT_C_IS_BLANK(pszEnd[-1]))
539 pszEnd--;
540 const char *pszNext = pszEnd;
541
542 while (pszEnd != pszDescription && RT_C_IS_BLANK(pszEnd[-1]))
543 pszEnd--;
544 if (pszEnd == pszDescription)
545 {
546 while (*pszEnd && !RT_C_IS_BLANK(*pszEnd))
547 pszEnd++;
548 pszNext = pszEnd;
549 }
550
551 while (RT_C_IS_BLANK(*pszNext))
552 pszNext++;
553
554 /* Output it and advance to the next line. */
555 if (!*pszNext)
556 return DBGCCmdHlpPrintf(pCmdHlp, "%*s %.*s\n", cchPadding, "", pszEnd - pszDescription, pszDescription);
557 DBGCCmdHlpPrintf(pCmdHlp, "%*s %.*s\n", cchPadding, "", pszEnd - pszDescription, pszDescription);
558
559 /* next */
560 cchDesc -= pszNext - pszDescription;
561 pszDescription = pszNext;
562 }
563 off = cchCol1 + 1 + cchCol2;
564 cchPadding = off;
565 }
566}
567
568
569/**
570 * Prints full command help.
571 */
572static void dbgcCmdHelpCmdOrFuncFull(PDBGCCMDHLP pCmdHlp, const char *pszName, bool fExternal,
573 const char *pszSyntax, const char *pszDescription,
574 uint32_t cArgsMin, uint32_t cArgsMax,
575 PCDBGCVARDESC paArgDescs, uint32_t cArgDescs, uint32_t *pcHits)
576{
577 if (*pcHits)
578 DBGCCmdHlpPrintf(pCmdHlp, "\n");
579 *pcHits += 1;
580
581 /* the command */
582 dbgcCmdHelpCmdOrFunc(pCmdHlp, pszName, fExternal, pszSyntax, pszDescription);
583#if 1
584 char szTmp[80];
585 if (!cArgsMin && cArgsMin == cArgsMax)
586 RTStrPrintf(szTmp, sizeof(szTmp), "<no args>");
587 else if (cArgsMin == cArgsMax)
588 RTStrPrintf(szTmp, sizeof(szTmp), " <%u args>", cArgsMin);
589 else if (cArgsMax == ~0U)
590 RTStrPrintf(szTmp, sizeof(szTmp), " <%u+ args>", cArgsMin);
591 else
592 RTStrPrintf(szTmp, sizeof(szTmp), " <%u to %u args>", cArgsMin, cArgsMax);
593 dbgcCmdHelpCmdOrFunc(pCmdHlp, "", false, szTmp, "");
594#endif
595
596 /* argument descriptions. */
597 for (uint32_t i = 0; i < cArgDescs; i++)
598 {
599 DBGCCmdHlpPrintf(pCmdHlp, " %-12s %s", paArgDescs[i].pszName, paArgDescs[i].pszDescription);
600 if (!paArgDescs[i].cTimesMin)
601 {
602 if (paArgDescs[i].cTimesMax == ~0U)
603 DBGCCmdHlpPrintf(pCmdHlp, " <optional+>\n");
604 else
605 DBGCCmdHlpPrintf(pCmdHlp, " <optional-%u>\n", paArgDescs[i].cTimesMax);
606 }
607 else
608 {
609 if (paArgDescs[i].cTimesMax == ~0U)
610 DBGCCmdHlpPrintf(pCmdHlp, " <%u+>\n", paArgDescs[i].cTimesMin);
611 else
612 DBGCCmdHlpPrintf(pCmdHlp, " <%u-%u>\n", paArgDescs[i].cTimesMin, paArgDescs[i].cTimesMax);
613 }
614 }
615}
616
617
618
619/**
620 * Prints full command help.
621 */
622static void dbgcPrintHelpCmd(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal, uint32_t *pcHits)
623{
624 dbgcCmdHelpCmdOrFuncFull(pCmdHlp, pCmd->pszCmd, fExternal, pCmd->pszSyntax, pCmd->pszDescription,
625 pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pcHits);
626}
627
628
629/**
630 * Prints full function help.
631 */
632static void dbgcPrintHelpFunction(PDBGCCMDHLP pCmdHlp, PCDBGCFUNC pFunc, bool fExternal, uint32_t *pcHits)
633{
634 dbgcCmdHelpCmdOrFuncFull(pCmdHlp, pFunc->pszFuncNm, fExternal, pFunc->pszSyntax, pFunc->pszDescription,
635 pFunc->cArgsMin, pFunc->cArgsMax, pFunc->paArgDescs, pFunc->cArgDescs, pcHits);
636}
637
638
639static void dbgcCmdHelpCommandsWorker(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, PCDBGCCMD paCmds, uint32_t cCmds, bool fExternal,
640 const char *pszDescFmt, ...)
641{
642 RT_NOREF1(pDbgc);
643 if (pszDescFmt)
644 {
645 va_list va;
646 va_start(va, pszDescFmt);
647 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszDescFmt, va);
648 va_end(va);
649 }
650
651 for (uint32_t i = 0; i < cCmds; i++)
652 dbgcCmdHelpCmdOrFunc(pCmdHlp, paCmds[i].pszCmd, fExternal, paCmds[i].pszSyntax, paCmds[i].pszDescription);
653}
654
655
656static void dbgcCmdHelpCommands(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
657{
658 if (*pcHits)
659 DBGCCmdHlpPrintf(pCmdHlp, "\n");
660 *pcHits += 1;
661
662 dbgcCmdHelpCommandsWorker(pDbgc, pCmdHlp, pDbgc->paEmulationCmds, pDbgc->cEmulationCmds, false,
663 "Commands for %s emulation:\n", pDbgc->pszEmulation);
664 dbgcCmdHelpCommandsWorker(pDbgc, pCmdHlp, g_aDbgcCmds, RT_ELEMENTS(g_aDbgcCmds), false,
665 "\nCommon Commands:\n");
666
667 DBGCEXTLISTS_LOCK_RD();
668 const char *pszDesc = "\nExternal Commands:\n";
669 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
670 {
671 dbgcCmdHelpCommandsWorker(pDbgc, pCmdHlp, pExtCmd->paCmds, pExtCmd->cCmds, false, pszDesc);
672 pszDesc = NULL;
673 }
674 DBGCEXTLISTS_UNLOCK_RD();
675}
676
677
678static void dbgcCmdHelpFunctionsWorker(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, PCDBGCFUNC paFuncs, size_t cFuncs, bool fExternal,
679 const char *pszDescFmt, ...)
680{
681 RT_NOREF1(pDbgc);
682 if (pszDescFmt)
683 {
684 va_list va;
685 va_start(va, pszDescFmt);
686 DBGCCmdHlpPrintf(pCmdHlp, pszDescFmt, va);
687 va_end(va);
688 }
689
690 for (uint32_t i = 0; i < cFuncs; i++)
691 dbgcCmdHelpCmdOrFunc(pCmdHlp, paFuncs[i].pszFuncNm, fExternal, paFuncs[i].pszSyntax, paFuncs[i].pszDescription);
692}
693
694
695static void dbgcCmdHelpFunctions(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
696{
697 if (*pcHits)
698 DBGCCmdHlpPrintf(pCmdHlp, "\n");
699 *pcHits += 1;
700
701 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, pDbgc->paEmulationFuncs, pDbgc->cEmulationFuncs, false,
702 "Functions for %s emulation:\n", pDbgc->pszEmulation);
703 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, g_aDbgcFuncs, g_cDbgcFuncs, false,
704 "\nCommon Functions:\n");
705#if 0
706 DBGCEXTLISTS_LOCK_RD();
707 const char *pszDesc = "\nExternal Functions:\n";
708 for (PDBGCEXTFUNCS pExtFunc = g_pExtFuncsHead; pExtFunc; pExtFunc = pExtFunc->pNext)
709 {
710 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, pExtFunc->paFuncs, pExtFunc->cFuncs, false,
711 pszDesc);
712 pszDesc = NULL;
713 }
714 DBGCEXTLISTS_UNLOCK_RD();
715#endif
716}
717
718
719static void dbgcCmdHelpOperators(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
720{
721 RT_NOREF1(pDbgc);
722 DBGCCmdHlpPrintf(pCmdHlp, !*pcHits ? "Operators:\n" : "\nOperators:\n");
723 *pcHits += 1;
724
725 unsigned iPrecedence = 0;
726 unsigned cLeft = g_cDbgcOps;
727 while (cLeft > 0)
728 {
729 for (unsigned i = 0; i < g_cDbgcOps; i++)
730 if (g_aDbgcOps[i].iPrecedence == iPrecedence)
731 {
732 dbgcCmdHelpCmdOrFunc(pCmdHlp, g_aDbgcOps[i].szName, false,
733 g_aDbgcOps[i].fBinary ? "Binary" : "Unary ",
734 g_aDbgcOps[i].pszDescription);
735 cLeft--;
736 }
737 iPrecedence++;
738 }
739}
740
741
742static void dbgcCmdHelpAll(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
743{
744 *pcHits += 1;
745 DBGCCmdHlpPrintf(pCmdHlp,
746 "\n"
747 "VirtualBox Debugger Help\n"
748 "------------------------\n"
749 "\n");
750 dbgcCmdHelpCommands(pDbgc, pCmdHlp, pcHits);
751 DBGCCmdHlpPrintf(pCmdHlp, "\n");
752 dbgcCmdHelpFunctions(pDbgc, pCmdHlp, pcHits);
753 DBGCCmdHlpPrintf(pCmdHlp, "\n");
754 dbgcCmdHelpOperators(pDbgc, pCmdHlp, pcHits);
755}
756
757
758static void dbgcCmdHelpSummary(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
759{
760 RT_NOREF1(pDbgc);
761 *pcHits += 1;
762 DBGCCmdHlpPrintf(pCmdHlp,
763 "\n"
764 "VirtualBox Debugger Help Summary\n"
765 "--------------------------------\n"
766 "\n"
767 "help commands Show help on all commands.\n"
768 "help functions Show help on all functions.\n"
769 "help operators Show help on all operators.\n"
770 "help all All the above.\n"
771 "help <cmd-pattern> [...]\n"
772 " Show details help on individual commands, simple\n"
773 " patterns can be used to match several commands.\n"
774 "help [summary] Displays this message.\n"
775 );
776}
777
778
779/**
780 * @callback_method_impl{FNDBGCCMD, The 'help' command.}
781 */
782static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
783{
784 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
785 int rc = VINF_SUCCESS;
786 uint32_t cHits = 0;
787
788 if (!cArgs)
789 /*
790 * No arguments, show summary.
791 */
792 dbgcCmdHelpSummary(pDbgc, pCmdHlp, &cHits);
793 else
794 {
795 /*
796 * Search for the arguments (strings).
797 */
798 DBGCEXTCMDS aFixedCmds[] =
799 {
800 { pDbgc->cEmulationCmds, pDbgc->paEmulationCmds, NULL },
801 { g_cDbgcCmds, g_aDbgcCmds, NULL },
802 };
803 DBGCEXTFUNCS aFixedFuncs[] =
804 {
805 { pDbgc->cEmulationFuncs, pDbgc->paEmulationFuncs, NULL },
806 { g_cDbgcFuncs, g_aDbgcFuncs, NULL },
807 };
808
809 for (unsigned iArg = 0; iArg < cArgs; iArg++)
810 {
811 AssertReturn(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_BUG);
812 const char *pszPattern = paArgs[iArg].u.pszString;
813
814 /* aliases */
815 if ( !strcmp(pszPattern, "commands")
816 || !strcmp(pszPattern, "cmds") )
817 dbgcCmdHelpCommands(pDbgc, pCmdHlp, &cHits);
818 else if ( !strcmp(pszPattern, "functions")
819 || !strcmp(pszPattern, "funcs") )
820 dbgcCmdHelpFunctions(pDbgc, pCmdHlp, &cHits);
821 else if ( !strcmp(pszPattern, "operators")
822 || !strcmp(pszPattern, "ops") )
823 dbgcCmdHelpOperators(pDbgc, pCmdHlp, &cHits);
824 else if (!strcmp(pszPattern, "all"))
825 dbgcCmdHelpAll(pDbgc, pCmdHlp, &cHits);
826 else if (!strcmp(pszPattern, "summary"))
827 dbgcCmdHelpSummary(pDbgc, pCmdHlp, &cHits);
828 /* Individual commands. */
829 else
830 {
831 uint32_t const cPrevHits = cHits;
832
833 /* lookup in the emulation command list first */
834 for (unsigned j = 0; j < RT_ELEMENTS(aFixedCmds); j++)
835 for (unsigned i = 0; i < aFixedCmds[j].cCmds; i++)
836 if (RTStrSimplePatternMatch(pszPattern, aFixedCmds[j].paCmds[i].pszCmd))
837 dbgcPrintHelpCmd(pCmdHlp, &aFixedCmds[j].paCmds[i], false, &cHits);
838 for (unsigned j = 0; j < RT_ELEMENTS(aFixedFuncs); j++)
839 for (unsigned i = 0; i < aFixedFuncs[j].cFuncs; i++)
840 if (RTStrSimplePatternMatch(pszPattern, aFixedFuncs[j].paFuncs[i].pszFuncNm))
841 dbgcPrintHelpFunction(pCmdHlp, &aFixedFuncs[j].paFuncs[i], false, &cHits);
842
843 /* external commands */
844 if ( g_pExtCmdsHead
845 && ( *pszPattern == '.'
846 || *pszPattern == '?'
847 || *pszPattern == '*'))
848 {
849 DBGCEXTLISTS_LOCK_RD();
850 const char *pszPattern2 = pszPattern + (*pszPattern == '.' || *pszPattern == '?');
851 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
852 for (unsigned i = 0; i < pExtCmd->cCmds; i++)
853 if (RTStrSimplePatternMatch(pszPattern2, pExtCmd->paCmds[i].pszCmd))
854 dbgcPrintHelpCmd(pCmdHlp, &pExtCmd->paCmds[i], true, &cHits);
855#if 0
856 for (PDBGCEXTFUNCS pExtFunc = g_pExtFuncsHead; pExtFunc; pExtFunc = pExtFunc->pNext)
857 for (unsigned i = 0; i < pExtFunc->cFuncs; i++)
858 if (RTStrSimplePatternMatch(pszPattern2, pExtFunc->paFuncs[i].pszFuncNm))
859 dbgcPrintHelpFunction(pCmdHlp, &pExtFunc->paFuncs[i], true, &cHits);
860#endif
861 DBGCEXTLISTS_UNLOCK_RD();
862 }
863
864 /* operators */
865 if (cHits == cPrevHits && strlen(paArgs[iArg].u.pszString) < sizeof(g_aDbgcOps[0].szName))
866 for (unsigned i = 0; i < g_cDbgcOps && RT_SUCCESS(rc); i++)
867 if (RTStrSimplePatternMatch(pszPattern, g_aDbgcOps[i].szName))
868 {
869 if (cHits++)
870 DBGCCmdHlpPrintf(pCmdHlp, "\n");
871 dbgcCmdHelpCmdOrFunc(pCmdHlp, g_aDbgcOps[i].szName, false,
872 g_aDbgcOps[i].fBinary ? "Binary" : "Unary ",
873 g_aDbgcOps[i].pszDescription);
874 }
875
876 /* found? */
877 if (cHits == cPrevHits)
878 {
879 DBGCCmdHlpPrintf(pCmdHlp, "error: '%s' was not found!\n",
880 paArgs[iArg].u.pszString);
881 rc = VERR_DBGC_COMMAND_FAILED;
882 }
883 }
884 } /* foreach argument */
885 }
886
887 NOREF(pCmd);
888 NOREF(pUVM);
889 return rc;
890}
891
892
893/**
894 * @callback_method_impl{FNDBGCCMD, The 'multistep' command.}
895 */
896static DECLCALLBACK(int) dbgcCmdMultiStep(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
897{
898 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
899
900 /*
901 * Parse arguments.
902 */
903 uint32_t cSteps = 64;
904 if (cArgs > 0)
905 {
906 if (paArgs[0].u.u64Number == 0 || paArgs[0].u.u64Number > _2G)
907 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
908 "The 'count' argument is out of range: %#llx - 1..2GiB\n", paArgs[0].u.u64Number);
909 cSteps = (uint32_t)paArgs[0].u.u64Number;
910 }
911 uint32_t uStrideLength = 1;
912 if (cArgs > 1)
913 {
914 if (paArgs[1].u.u64Number == 0 || paArgs[1].u.u64Number > _2G)
915 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, VERR_OUT_OF_RANGE,
916 "The 'stride' argument is out of range: %#llx - 1..2GiB\n", paArgs[0].u.u64Number);
917 uStrideLength = (uint32_t)paArgs[0].u.u64Number;
918 }
919
920 /*
921 * Take the first step.
922 */
923 int rc = DBGFR3StepEx(pUVM, pDbgc->idCpu, DBGF_STEP_F_INTO, NULL, NULL, 0, uStrideLength);
924 if (RT_SUCCESS(rc))
925 {
926 pDbgc->cMultiStepsLeft = cSteps;
927 pDbgc->uMultiStepStrideLength = uStrideLength;
928 pDbgc->pMultiStepCmd = pCmd;
929 pDbgc->fReady = false;
930 }
931 else
932 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3StepEx(,,DBGF_STEP_F_INTO,) failed");
933
934 NOREF(pCmd);
935 return rc;
936}
937
938
939/**
940 * @callback_method_impl{FNDBGCCMD, The 'quit'\, 'exit' and 'bye' commands. }
941 */
942static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
943{
944 DBGCCmdHlpPrintf(pCmdHlp, "Quitting console...\n");
945 NOREF(pCmd);
946 NOREF(pUVM);
947 NOREF(paArgs);
948 NOREF(cArgs);
949 return VERR_DBGC_QUIT;
950}
951
952
953/**
954 * @callback_method_impl{FNDBGCCMD, The 'stop' command.}
955 */
956static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
957{
958 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
959
960 /*
961 * Parse arguments.
962 */
963 VMCPUID idCpu = VMCPUID_ALL;
964 if (cArgs == 1)
965 {
966 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
967 if (paArgs[0].u.u64Number >= cCpus)
968 return DBGCCmdHlpFail(pCmdHlp, pCmd, "idCpu %RU64 is out of range! Highest valid ID is %u.\n",
969 paArgs[0].u.u64Number, cCpus - 1);
970 idCpu = (VMCPUID)paArgs[0].u.u64Number;
971 }
972 else
973 Assert(cArgs == 0);
974
975 /*
976 * Try halt the VM or VCpu.
977 */
978 int rc = DBGFR3Halt(pUVM, idCpu);
979 if (RT_SUCCESS(rc))
980 {
981 Assert(rc == VINF_SUCCESS || rc == VWRN_DBGF_ALREADY_HALTED);
982 if (rc != VWRN_DBGF_ALREADY_HALTED)
983 rc = VWRN_DBGC_CMD_PENDING;
984 else if (idCpu == VMCPUID_ALL)
985 rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: The VM is already halted...\n");
986 else
987 rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: CPU %u is already halted...\n", idCpu);
988 }
989 else
990 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
991
992 return rc;
993}
994
995
996/**
997 * @callback_method_impl{FNDBGCCMD, The 'echo' command.}
998 */
999static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1000{
1001 /*
1002 * Loop thru the arguments and print them with one space between.
1003 */
1004 int rc = 0;
1005 for (unsigned i = 0; i < cArgs; i++)
1006 {
1007 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_BUG);
1008 rc = DBGCCmdHlpPrintf(pCmdHlp, i ? " %s" : "%s", paArgs[i].u.pszString);
1009 if (RT_FAILURE(rc))
1010 return rc;
1011 }
1012 NOREF(pCmd); NOREF(pUVM);
1013 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
1014}
1015
1016
1017/**
1018 * @callback_method_impl{FNDBGCCMD, The 'runscript' command.}
1019 */
1020static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1021{
1022 RT_NOREF2(pUVM, pCmd);
1023
1024 /* check that the parser did what it's supposed to do. */
1025 if ( cArgs != 1
1026 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1027 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1028
1029 /* Pass it on to a common function. */
1030 const char *pszFilename = paArgs[0].u.pszString;
1031 return dbgcEvalScript(DBGC_CMDHLP2DBGC(pCmdHlp), pszFilename, false /*fAnnounce*/);
1032}
1033
1034
1035/**
1036 * @callback_method_impl{FNDBGCCMD, The 'detect' command.}
1037 */
1038static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1039{
1040 /* check that the parser did what it's supposed to do. */
1041 if (cArgs != 0)
1042 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1043
1044 /*
1045 * Perform the detection.
1046 */
1047 char szName[64];
1048 int rc = DBGFR3OSDetect(pUVM, szName, sizeof(szName));
1049 if (RT_FAILURE(rc))
1050 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().\n");
1051 if (rc == VINF_SUCCESS)
1052 {
1053 rc = DBGCCmdHlpPrintf(pCmdHlp, "Guest OS: %s\n", szName);
1054 char szVersion[512];
1055 int rc2 = DBGFR3OSQueryNameAndVersion(pUVM, NULL, 0, szVersion, sizeof(szVersion));
1056 if (RT_SUCCESS(rc2))
1057 rc = DBGCCmdHlpPrintf(pCmdHlp, "Version : %s\n", szVersion);
1058 }
1059 else
1060 rc = DBGCCmdHlpPrintf(pCmdHlp, "Unable to figure out which guest OS it is, sorry.\n");
1061 NOREF(pCmd); NOREF(paArgs);
1062 return rc;
1063}
1064
1065
1066/**
1067 * @callback_method_impl{FNDBGCCMD, The 'dmesg' command.}
1068 */
1069static DECLCALLBACK(int) dbgcCmdDmesg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1070{
1071 /* check that the parser did what it's supposed to do. */
1072 if (cArgs > 1)
1073 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1074 uint32_t cMessages = UINT32_MAX;
1075 if (cArgs == 1)
1076 {
1077 if (paArgs[0].enmType != DBGCVAR_TYPE_NUMBER)
1078 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1079 cMessages = paArgs[0].u.u64Number <= UINT32_MAX ? (uint32_t)paArgs[0].u.u64Number : UINT32_MAX;
1080 }
1081
1082 /*
1083 * Query the interface.
1084 */
1085 int rc;
1086 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(pUVM, DBGFOSINTERFACE_DMESG);
1087 if (pDmesg)
1088 {
1089 size_t cbActual;
1090 size_t cbBuf = _512K;
1091 char *pszBuf = (char *)RTMemAlloc(cbBuf);
1092 if (pszBuf)
1093 {
1094 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
1095
1096 uint32_t cTries = 10;
1097 while (rc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1098 {
1099 RTMemFree(pszBuf);
1100 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1101 pszBuf = (char *)RTMemAlloc(cbBuf);
1102 if (RT_UNLIKELY(!pszBuf))
1103 {
1104 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
1105 break;
1106 }
1107 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
1108 }
1109 if (RT_SUCCESS(rc))
1110 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\n", pszBuf);
1111 else if (rc == VERR_BUFFER_OVERFLOW && pszBuf)
1112 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\nWarning: incomplete\n", pszBuf);
1113 else
1114 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "pfnQueryKernelLog failed: %Rrc\n", rc);
1115 RTMemFree(pszBuf);
1116 }
1117 else
1118 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
1119 }
1120 else
1121 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "The dmesg interface isn't implemented by guest OS.\n");
1122 return rc;
1123}
1124
1125
1126/**
1127 * @callback_method_impl{FNDBGCCMD, The 'cpu' command.}
1128 */
1129static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1130{
1131 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1132
1133 /* check that the parser did what it's supposed to do. */
1134 if ( cArgs != 0
1135 && ( cArgs != 1
1136 || paArgs[0].enmType != DBGCVAR_TYPE_NUMBER))
1137 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1138 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1139
1140 int rc;
1141 if (!cArgs)
1142 rc = DBGCCmdHlpPrintf(pCmdHlp, "Current CPU ID: %u\n", pDbgc->idCpu);
1143 else
1144 {
1145 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
1146 if (paArgs[0].u.u64Number >= cCpus)
1147 rc = DBGCCmdHlpPrintf(pCmdHlp, "error: idCpu %u is out of range! Highest ID is %u.\n",
1148 paArgs[0].u.u64Number, cCpus-1);
1149 else
1150 {
1151 rc = DBGCCmdHlpPrintf(pCmdHlp, "Changed CPU from %u to %u.\n",
1152 pDbgc->idCpu, (VMCPUID)paArgs[0].u.u64Number);
1153 pDbgc->idCpu = (VMCPUID)paArgs[0].u.u64Number;
1154 }
1155 }
1156 return rc;
1157}
1158
1159
1160/**
1161 * @callback_method_impl{FNDBGCCMD, The 'info' command.}
1162 */
1163static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1164{
1165 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1166
1167 /*
1168 * Validate input.
1169 */
1170 if ( cArgs < 1
1171 || cArgs > 2
1172 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
1173 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
1174 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
1175 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1176
1177 /*
1178 * Dump it.
1179 */
1180 int rc = DBGFR3InfoEx(pUVM, pDbgc->idCpu,
1181 paArgs[0].u.pszString,
1182 cArgs == 2 ? paArgs[1].u.pszString : NULL,
1183 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
1184 if (RT_FAILURE(rc))
1185 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3InfoEx()\n");
1186
1187 NOREF(pCmd);
1188 return 0;
1189}
1190
1191
1192/**
1193 * @callback_method_impl{FNDBGCCMD, The 'log' command.}
1194 */
1195static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1196{
1197 int rc;
1198 if (cArgs == 0)
1199 {
1200 char szBuf[_64K];
1201 rc = RTLogGetGroupSettings(NULL, szBuf, sizeof(szBuf));
1202 if (RT_FAILURE(rc))
1203 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1204 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG=%s\n", szBuf);
1205 }
1206 else
1207 {
1208 rc = DBGFR3LogModifyGroups(pUVM, paArgs[0].u.pszString);
1209 if (RT_FAILURE(rc))
1210 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1211 }
1212 NOREF(pCmd);
1213 return VINF_SUCCESS;
1214}
1215
1216
1217/**
1218 * @callback_method_impl{FNDBGCCMD, The 'logdest' command.}
1219 */
1220static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1221{
1222 int rc;
1223 if (cArgs == 0)
1224 {
1225 char szBuf[_16K];
1226 rc = RTLogGetDestinations(NULL, szBuf, sizeof(szBuf));
1227 if (RT_FAILURE(rc))
1228 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1229 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_DEST=%s\n", szBuf);
1230 }
1231 else
1232 {
1233 rc = DBGFR3LogModifyDestinations(pUVM, paArgs[0].u.pszString);
1234 if (RT_FAILURE(rc))
1235 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1236 }
1237 NOREF(pCmd);
1238 return VINF_SUCCESS;
1239}
1240
1241
1242/**
1243 * @callback_method_impl{FNDBGCCMD, The 'logflags' command.}
1244 */
1245static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1246{
1247 int rc;
1248 if (cArgs == 0)
1249 {
1250 char szBuf[_16K];
1251 rc = RTLogGetFlags(NULL, szBuf, sizeof(szBuf));
1252 if (RT_FAILURE(rc))
1253 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetFlags(NULL,,%#zx)\n", sizeof(szBuf));
1254 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_FLAGS=%s\n", szBuf);
1255 }
1256 else
1257 {
1258 rc = DBGFR3LogModifyFlags(pUVM, paArgs[0].u.pszString);
1259 if (RT_FAILURE(rc))
1260 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1261 }
1262
1263 NOREF(pCmd);
1264 return rc;
1265}
1266
1267
1268/**
1269 * @callback_method_impl{FNDBGCCMD, The 'logflush' command.}
1270 */
1271static DECLCALLBACK(int) dbgcCmdLogFlush(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1272{
1273 RT_NOREF3(pCmdHlp, pUVM, paArgs);
1274
1275 RTLogFlush(NULL);
1276 PRTLOGGER pLogRel = RTLogRelGetDefaultInstance();
1277 if (pLogRel)
1278 RTLogFlush(pLogRel);
1279
1280 NOREF(pCmd); NOREF(cArgs);
1281 return VINF_SUCCESS;
1282}
1283
1284
1285/**
1286 * @callback_method_impl{FNDBGCCMD, The 'format' command.}
1287 */
1288static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1289{
1290 LogFlow(("dbgcCmdFormat\n"));
1291 static const char *apszRangeDesc[] =
1292 {
1293 "none", "bytes", "elements"
1294 };
1295 int rc;
1296
1297 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1298 {
1299 switch (paArgs[iArg].enmType)
1300 {
1301 case DBGCVAR_TYPE_UNKNOWN:
1302 rc = DBGCCmdHlpPrintf(pCmdHlp,
1303 "Unknown variable type!\n");
1304 break;
1305 case DBGCVAR_TYPE_GC_FLAT:
1306 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1307 rc = DBGCCmdHlpPrintf(pCmdHlp,
1308 "Guest flat address: %%%08x range %lld %s\n",
1309 paArgs[iArg].u.GCFlat,
1310 paArgs[iArg].u64Range,
1311 apszRangeDesc[paArgs[iArg].enmRangeType]);
1312 else
1313 rc = DBGCCmdHlpPrintf(pCmdHlp,
1314 "Guest flat address: %%%08x\n",
1315 paArgs[iArg].u.GCFlat);
1316 break;
1317 case DBGCVAR_TYPE_GC_FAR:
1318 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1319 rc = DBGCCmdHlpPrintf(pCmdHlp,
1320 "Guest far address: %04x:%08x range %lld %s\n",
1321 paArgs[iArg].u.GCFar.sel,
1322 paArgs[iArg].u.GCFar.off,
1323 paArgs[iArg].u64Range,
1324 apszRangeDesc[paArgs[iArg].enmRangeType]);
1325 else
1326 rc = DBGCCmdHlpPrintf(pCmdHlp,
1327 "Guest far address: %04x:%08x\n",
1328 paArgs[iArg].u.GCFar.sel,
1329 paArgs[iArg].u.GCFar.off);
1330 break;
1331 case DBGCVAR_TYPE_GC_PHYS:
1332 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1333 rc = DBGCCmdHlpPrintf(pCmdHlp,
1334 "Guest physical address: %%%%%08x range %lld %s\n",
1335 paArgs[iArg].u.GCPhys,
1336 paArgs[iArg].u64Range,
1337 apszRangeDesc[paArgs[iArg].enmRangeType]);
1338 else
1339 rc = DBGCCmdHlpPrintf(pCmdHlp,
1340 "Guest physical address: %%%%%08x\n",
1341 paArgs[iArg].u.GCPhys);
1342 break;
1343 case DBGCVAR_TYPE_HC_FLAT:
1344 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1345 rc = DBGCCmdHlpPrintf(pCmdHlp,
1346 "Host flat address: %%%08x range %lld %s\n",
1347 paArgs[iArg].u.pvHCFlat,
1348 paArgs[iArg].u64Range,
1349 apszRangeDesc[paArgs[iArg].enmRangeType]);
1350 else
1351 rc = DBGCCmdHlpPrintf(pCmdHlp,
1352 "Host flat address: %%%08x\n",
1353 paArgs[iArg].u.pvHCFlat);
1354 break;
1355 case DBGCVAR_TYPE_HC_PHYS:
1356 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1357 rc = DBGCCmdHlpPrintf(pCmdHlp,
1358 "Host physical address: %RHp range %lld %s\n",
1359 paArgs[iArg].u.HCPhys,
1360 paArgs[iArg].u64Range,
1361 apszRangeDesc[paArgs[iArg].enmRangeType]);
1362 else
1363 rc = DBGCCmdHlpPrintf(pCmdHlp,
1364 "Host physical address: %RHp\n",
1365 paArgs[iArg].u.HCPhys);
1366 break;
1367
1368 case DBGCVAR_TYPE_STRING:
1369 rc = DBGCCmdHlpPrintf(pCmdHlp,
1370 "String, %lld bytes long: %s\n",
1371 paArgs[iArg].u64Range,
1372 paArgs[iArg].u.pszString);
1373 break;
1374
1375 case DBGCVAR_TYPE_SYMBOL:
1376 rc = DBGCCmdHlpPrintf(pCmdHlp,
1377 "Symbol, %lld bytes long: %s\n",
1378 paArgs[iArg].u64Range,
1379 paArgs[iArg].u.pszString);
1380 break;
1381
1382 case DBGCVAR_TYPE_NUMBER:
1383 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1384 rc = DBGCCmdHlpPrintf(pCmdHlp,
1385 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1386 paArgs[iArg].u.u64Number,
1387 paArgs[iArg].u.u64Number,
1388 paArgs[iArg].u.u64Number,
1389 paArgs[iArg].u64Range,
1390 apszRangeDesc[paArgs[iArg].enmRangeType]);
1391 else
1392 rc = DBGCCmdHlpPrintf(pCmdHlp,
1393 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1394 paArgs[iArg].u.u64Number,
1395 paArgs[iArg].u.u64Number,
1396 paArgs[iArg].u.u64Number);
1397 break;
1398
1399 default:
1400 rc = DBGCCmdHlpPrintf(pCmdHlp,
1401 "Invalid argument type %d\n",
1402 paArgs[iArg].enmType);
1403 break;
1404 }
1405 } /* arg loop */
1406
1407 NOREF(pCmd); NOREF(pUVM);
1408 return 0;
1409}
1410
1411
1412/**
1413 * @callback_method_impl{FNDBGCCMD, The 'loadimage' command.}
1414 */
1415static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1416{
1417 /*
1418 * Validate the parsing and make sense of the input.
1419 * This is a mess as usual because we don't trust the parser yet.
1420 */
1421 AssertReturn( cArgs >= 2
1422 && cArgs <= 3
1423 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1424 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1425 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1426
1427 const char *pszFilename = paArgs[0].u.pszString;
1428
1429 DBGFADDRESS ModAddress;
1430 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1431 if (RT_FAILURE(rc))
1432 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1433
1434 const char *pszModName = NULL;
1435 if (cArgs >= 3)
1436 {
1437 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1438 pszModName = paArgs[2].u.pszString;
1439 }
1440
1441 /*
1442 * Determine the desired image arch from the load command used.
1443 */
1444 RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
1445 if (pCmd->pszCmd[sizeof("loadimage") - 1] == '3')
1446 enmArch = RTLDRARCH_X86_32;
1447 else if (pCmd->pszCmd[sizeof("loadimage") - 1] == '6')
1448 enmArch = RTLDRARCH_AMD64;
1449
1450 /*
1451 * Try create a module for it.
1452 */
1453 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1454 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, enmArch, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1455 if (RT_FAILURE(rc))
1456 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1457 pszFilename, pszModName, &paArgs[1]);
1458
1459 return VINF_SUCCESS;
1460}
1461
1462
1463/**
1464 * @callback_method_impl{FNDBGCCMD, The 'loadinmem' command.}
1465 */
1466static DECLCALLBACK(int) dbgcCmdLoadInMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1467{
1468 /*
1469 * Validate the parsing and make sense of the input.
1470 * This is a mess as usual because we don't trust the parser yet.
1471 */
1472 AssertReturn( cArgs >= 1
1473 && cArgs <= 2
1474 && DBGCVAR_ISPOINTER(paArgs[0].enmType)
1475 && (cArgs < 2 || paArgs[1].enmType == DBGCVAR_TYPE_STRING),
1476 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1477
1478 RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
1479 const char *pszModName = cArgs >= 2 ? paArgs[1].u.pszString : NULL;
1480 DBGFADDRESS ModAddress;
1481 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[0], &ModAddress);
1482 if (RT_FAILURE(rc))
1483 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1484
1485 /*
1486 * Try create a module for it.
1487 */
1488 uint32_t fFlags = DBGFMODINMEM_F_NO_CONTAINER_FALLBACK | DBGFMODINMEM_F_NO_READER_FALLBACK;
1489 RTDBGMOD hDbgMod;
1490 RTERRINFOSTATIC ErrInfo;
1491 rc = DBGFR3ModInMem(pUVM, &ModAddress, fFlags, pszModName, pszModName, enmArch, 0 /*cbImage*/,
1492 &hDbgMod, RTErrInfoInitStatic(&ErrInfo));
1493 if (RT_FAILURE(rc))
1494 {
1495 if (RTErrInfoIsSet(&ErrInfo.Core))
1496 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3ModInMem failed for %Dv: %s", &ModAddress, ErrInfo.Core.pszMsg);
1497 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3ModInMem failed for %Dv", &ModAddress);
1498 }
1499
1500 /*
1501 * Link the module into the appropriate address space.
1502 */
1503 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1504 rc = DBGFR3AsLinkModule(pUVM, pDbgc->hDbgAs, hDbgMod, &ModAddress, NIL_RTDBGSEGIDX, RTDBGASLINK_FLAGS_REPLACE);
1505 RTDbgModRelease(hDbgMod);
1506 if (RT_FAILURE(rc))
1507 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3AsLinkModule failed for %Dv", &ModAddress);
1508 return VINF_SUCCESS;
1509}
1510
1511
1512/**
1513 * @callback_method_impl{FNDBGCCMD, The 'loadmap' command.}
1514 */
1515static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1516{
1517 /*
1518 * Validate the parsing and make sense of the input.
1519 * This is a mess as usual because we don't trust the parser yet.
1520 */
1521 AssertReturn( cArgs >= 2
1522 && cArgs <= 5
1523 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1524 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1525 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1526
1527 const char *pszFilename = paArgs[0].u.pszString;
1528
1529 DBGFADDRESS ModAddress;
1530 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1531 if (RT_FAILURE(rc))
1532 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1533
1534 const char *pszModName = NULL;
1535 if (cArgs >= 3)
1536 {
1537 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1538 pszModName = paArgs[2].u.pszString;
1539 }
1540
1541 RTGCUINTPTR uSubtrahend = 0;
1542 if (cArgs >= 4)
1543 {
1544 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1545 uSubtrahend = paArgs[3].u.u64Number;
1546 }
1547
1548 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1549 if (cArgs >= 5)
1550 {
1551 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1552 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1553 if ( iModSeg != paArgs[4].u.u64Number
1554 || iModSeg > RTDBGSEGIDX_LAST)
1555 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1556 }
1557
1558 /*
1559 * Try create a module for it.
1560 */
1561 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1562 rc = DBGFR3AsLoadMap(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1563 if (RT_FAILURE(rc))
1564 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1565 pszFilename, pszModName, &paArgs[1]);
1566
1567 NOREF(pCmd);
1568 return VINF_SUCCESS;
1569}
1570
1571
1572/**
1573 * @callback_method_impl{FNDBGCCMD, The 'loadseg' command.}
1574 */
1575static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1576{
1577 /*
1578 * Validate the parsing and make sense of the input.
1579 * This is a mess as usual because we don't trust the parser yet.
1580 */
1581 AssertReturn( cArgs >= 3
1582 && cArgs <= 4
1583 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1584 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1585 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1586 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1587
1588 const char *pszFilename = paArgs[0].u.pszString;
1589
1590 DBGFADDRESS ModAddress;
1591 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1592 if (RT_FAILURE(rc))
1593 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1594
1595 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[2].u.u64Number;
1596 if ( iModSeg != paArgs[2].u.u64Number
1597 || iModSeg > RTDBGSEGIDX_LAST)
1598 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1599
1600 const char *pszModName = NULL;
1601 if (cArgs >= 4)
1602 {
1603 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1604 pszModName = paArgs[3].u.pszString;
1605 }
1606
1607 /*
1608 * Call the debug info manager about this loading.
1609 */
1610 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1611 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, RTLDRARCH_WHATEVER,
1612 &ModAddress, iModSeg, RTDBGASLINK_FLAGS_REPLACE);
1613 if (RT_FAILURE(rc))
1614 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,,)\n",
1615 pszFilename, pszModName, &paArgs[1]);
1616
1617 NOREF(pCmd);
1618 return VINF_SUCCESS;
1619}
1620
1621
1622/**
1623 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1624 */
1625static DECLCALLBACK(int) dbgcCmdUnload(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1626{
1627 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1628
1629 /*
1630 * Validate the parsing and make sense of the input.
1631 * This is a mess as usual because we don't trust the parser yet.
1632 */
1633 AssertReturn( cArgs >= 1
1634 && paArgs[0].enmType == DBGCVAR_TYPE_STRING,
1635 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1636 for (unsigned i = 0; i < cArgs; i++)
1637 {
1638 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1639
1640 int rc = DBGFR3AsUnlinkModuleByName(pUVM, pDbgc->hDbgAs, paArgs[i].u.pszString);
1641 if (RT_FAILURE(rc))
1642 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsUnlinkModuleByName(,,'%s')\n", paArgs[i].u.pszString);
1643 }
1644
1645 NOREF(pCmd);
1646 return VINF_SUCCESS;
1647}
1648
1649
1650/**
1651 * @callback_method_impl{FNDBGCCMD, The 'set' command.}
1652 */
1653static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1654{
1655 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1656
1657 /* parse sanity check. */
1658 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1659 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1660 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1661
1662
1663 /*
1664 * A variable must start with an alpha chars and only contain alpha numerical chars.
1665 */
1666 const char *pszVar = paArgs[0].u.pszString;
1667 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1668 return DBGCCmdHlpPrintf(pCmdHlp,
1669 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!",
1670 paArgs[0].u.pszString);
1671
1672 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1673 pszVar++;
1674 if (*pszVar)
1675 return DBGCCmdHlpPrintf(pCmdHlp,
1676 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!",
1677 paArgs[0].u.pszString);
1678
1679
1680 /*
1681 * Calc variable size.
1682 */
1683 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1684 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1685 cbVar += 1 + (size_t)paArgs[1].u64Range;
1686
1687 /*
1688 * Look for existing one.
1689 */
1690 pszVar = paArgs[0].u.pszString;
1691 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1692 {
1693 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1694 {
1695 /*
1696 * Update existing variable.
1697 */
1698 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1699 if (!pv)
1700 return VERR_DBGC_PARSE_NO_MEMORY;
1701 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1702
1703 pVar->Var = paArgs[1];
1704 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1705 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1706 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1707 return 0;
1708 }
1709 }
1710
1711 /*
1712 * Allocate another.
1713 */
1714 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1715
1716 pVar->Var = paArgs[1];
1717 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1718 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1719 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1720
1721 /* need to reallocate the pointer array too? */
1722 if (!(pDbgc->cVars % 0x20))
1723 {
1724 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1725 if (!pv)
1726 {
1727 RTMemFree(pVar);
1728 return VERR_DBGC_PARSE_NO_MEMORY;
1729 }
1730 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1731 }
1732 pDbgc->papVars[pDbgc->cVars++] = pVar;
1733
1734 NOREF(pCmd); NOREF(pUVM); NOREF(cArgs);
1735 return 0;
1736}
1737
1738
1739/**
1740 * @callback_method_impl{FNDBGCCMD, The 'unset' command.}
1741 */
1742static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1743{
1744 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1745 for (unsigned i = 0; i < cArgs; i++)
1746 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_SYMBOL, VERR_DBGC_PARSE_BUG);
1747
1748 /*
1749 * Iterate the variables and unset them.
1750 */
1751 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1752 {
1753 const char *pszVar = paArgs[iArg].u.pszString;
1754
1755 /*
1756 * Look up the variable.
1757 */
1758 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1759 {
1760 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1761 {
1762 /*
1763 * Shuffle the array removing this entry.
1764 */
1765 void *pvFree = pDbgc->papVars[iVar];
1766 if (iVar + 1 < pDbgc->cVars)
1767 memmove(&pDbgc->papVars[iVar],
1768 &pDbgc->papVars[iVar + 1],
1769 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1770 pDbgc->papVars[--pDbgc->cVars] = NULL;
1771
1772 RTMemFree(pvFree);
1773 }
1774 } /* lookup */
1775 } /* arg loop */
1776
1777 NOREF(pCmd); NOREF(pUVM);
1778 return 0;
1779}
1780
1781
1782/**
1783 * @callback_method_impl{FNDBGCCMD, The 'loadvars' command.}
1784 */
1785static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1786{
1787 /*
1788 * Don't trust the parser.
1789 */
1790 if ( cArgs != 1
1791 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1792 {
1793 AssertMsgFailed(("Expected one string exactly!\n"));
1794 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1795 }
1796
1797 /*
1798 * Iterate the variables and unset them.
1799 */
1800 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1801 if (pFile)
1802 {
1803 char szLine[4096];
1804 while (fgets(szLine, sizeof(szLine), pFile))
1805 {
1806 /* Strip it. */
1807 char *psz = szLine;
1808 while (RT_C_IS_BLANK(*psz))
1809 psz++;
1810 int i = (int)strlen(psz) - 1;
1811 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1812 psz[i--] ='\0';
1813 /* Execute it if not comment or empty line. */
1814 if ( *psz != '\0'
1815 && *psz != '#'
1816 && *psz != ';')
1817 {
1818 DBGCCmdHlpPrintf(pCmdHlp, "dbg: set %s", psz);
1819 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1820 }
1821 }
1822 fclose(pFile);
1823 }
1824 else
1825 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1826
1827 NOREF(pCmd); NOREF(pUVM);
1828 return 0;
1829}
1830
1831
1832/**
1833 * @callback_method_impl{FNDBGCCMD, The 'showvars' command.}
1834 */
1835static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1836{
1837 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1838
1839 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1840 {
1841 int rc = DBGCCmdHlpPrintf(pCmdHlp, "%-20s ", &pDbgc->papVars[iVar]->szName);
1842 if (!rc)
1843 rc = dbgcCmdFormat(pCmd, pCmdHlp, pUVM, &pDbgc->papVars[iVar]->Var, 1);
1844 if (rc)
1845 return rc;
1846 }
1847
1848 NOREF(paArgs); NOREF(cArgs);
1849 return 0;
1850}
1851
1852
1853/**
1854 * @callback_method_impl{FNDBGCCMD, The 'loadplugin' command.}
1855 */
1856static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1857{
1858 RT_NOREF1(pUVM);
1859 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1860
1861 /*
1862 * Loop thru the plugin names.
1863 */
1864 for (unsigned i = 0; i < cArgs; i++)
1865 {
1866 char szPlugIn[128];
1867 RTERRINFOSTATIC ErrInfo;
1868 szPlugIn[0] = '\0';
1869 int rc = DBGFR3PlugInLoad(pDbgc->pUVM, paArgs[i].u.pszString, szPlugIn, sizeof(szPlugIn), RTErrInfoInitStatic(&ErrInfo));
1870 if (RT_SUCCESS(rc))
1871 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s' (%s)\n", szPlugIn, paArgs[i].u.pszString);
1872 else if (rc == VERR_ALREADY_EXISTS)
1873 DBGCCmdHlpPrintf(pCmdHlp, "A plug-in named '%s' is already loaded\n", szPlugIn);
1874 else if (szPlugIn[0])
1875 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s' ('%s'): %s",
1876 szPlugIn, paArgs[i].u.pszString, ErrInfo.szMsg);
1877 else
1878 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s': %s",
1879 paArgs[i].u.pszString, ErrInfo.szMsg);
1880 }
1881
1882 return VINF_SUCCESS;
1883}
1884
1885
1886/**
1887 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1888 */
1889static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1890{
1891 RT_NOREF1(pUVM);
1892 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1893
1894 /*
1895 * Loop thru the given plug-in names.
1896 */
1897 for (unsigned i = 0; i < cArgs; i++)
1898 {
1899 int rc = DBGFR3PlugInUnload(pDbgc->pUVM, paArgs[i].u.pszString);
1900 if (RT_SUCCESS(rc))
1901 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", paArgs[i].u.pszString);
1902 else if (rc == VERR_NOT_FOUND)
1903 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' was not found\n", paArgs[i].u.pszString);
1904 else
1905 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInUnload failed for '%s'", paArgs[i].u.pszString);
1906 }
1907
1908 return VINF_SUCCESS;
1909}
1910
1911
1912/**
1913 * @callback_method_impl{FNDBGCCMD, The 'harakiri' command.}
1914 */
1915static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1916{
1917 Log(("dbgcCmdHarakiri\n"));
1918 for (;;)
1919 exit(126);
1920 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs);
1921}
1922
1923
1924/**
1925 * @callback_method_impl{FNDBGCCMD, The 'writecore' command.}
1926 */
1927static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1928{
1929 Log(("dbgcCmdWriteCore\n"));
1930
1931 /*
1932 * Validate input, lots of paranoia here.
1933 */
1934 if ( cArgs != 1
1935 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1936 {
1937 AssertMsgFailed(("Expected one string exactly!\n"));
1938 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1939 }
1940
1941 const char *pszDumpPath = paArgs[0].u.pszString;
1942 if (!pszDumpPath)
1943 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
1944
1945 int rc = DBGFR3CoreWrite(pUVM, pszDumpPath, true /*fReplaceFile*/);
1946 if (RT_FAILURE(rc))
1947 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
1948
1949 return VINF_SUCCESS;
1950}
1951
1952
1953/**
1954 * @callback_method_impl{FNDBGCCMD, The 'writegstmem' command.}
1955 */
1956static DECLCALLBACK(int) dbgcCmdWriteGstMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1957{
1958 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1959 LogFunc(("\n"));
1960
1961 /*
1962 * Validate the parsing and make sense of the input.
1963 * This is a mess as usual because we don't trust the parser yet.
1964 */
1965 AssertReturn( cArgs == 2
1966 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1967 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1968 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1969
1970 const char *pszFile = paArgs[0].u.pszString;
1971 if (!pszFile)
1972 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
1973
1974 DBGFADDRESS LoadAddress;
1975 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &LoadAddress);
1976 if (RT_FAILURE(rc))
1977 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1978
1979 RTFILE hFile = NIL_RTFILE;
1980 rc = RTFileOpen(&hFile, pszFile, RTFILE_O_READ | RTFILE_O_OPEN | RTFILE_O_DENY_NONE);
1981 if (RT_SUCCESS(rc))
1982 {
1983 uint64_t cbFile;
1984 rc = RTFileQuerySize(hFile, &cbFile);
1985 if (RT_SUCCESS(rc))
1986 {
1987 void *pvBuf = RTMemTmpAlloc(_16K);
1988 if (RT_LIKELY(pvBuf))
1989 {
1990 size_t cbLeft = cbFile;
1991
1992 while ( cbLeft
1993 && RT_SUCCESS(rc))
1994 {
1995 uint64_t cbThisCopy = RT_MIN(cbFile, _16K);
1996
1997 rc = RTFileRead(hFile, pvBuf, cbThisCopy, NULL /*pcbRead*/);
1998 if (RT_SUCCESS(rc))
1999 {
2000 rc = DBGFR3MemWrite(pUVM, pDbgc->idCpu, &LoadAddress, pvBuf, cbThisCopy);
2001 if (RT_SUCCESS(rc))
2002 DBGFR3AddrAdd(&LoadAddress, cbThisCopy);
2003 else
2004 {
2005 DBGCVAR VarCur;
2006 rc = DBGCCmdHlpVarFromDbgfAddr(pCmdHlp, &LoadAddress, &VarCur);
2007 if (RT_SUCCESS(rc))
2008 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3MemWrite(,,%DV,,%RX64) failed. rc=%Rrc\n", &VarCur, cbThisCopy, rc);
2009 else
2010 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGCCmdHlpVarFromDbgfAddr\n");
2011 }
2012 }
2013 else
2014 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "RTFileRead() failed. rc=%Rrc\n", rc);
2015
2016 cbLeft -= cbThisCopy;
2017 }
2018
2019 if (RT_SUCCESS(rc))
2020 DBGCCmdHlpPrintf(pCmdHlp, "Wrote 0x%RX64 (%RU64) bytes to %Dv\n", cbFile, cbFile, &paArgs[1]);
2021
2022 RTMemTmpFree(pvBuf);
2023 }
2024 else
2025 {
2026 rc = VERR_NO_MEMORY;
2027 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "RTMemTmpAlloc() failed. rc=%Rrc\n", rc);
2028 }
2029 }
2030 else
2031 rc = DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "RTFileQuerySize() failed. rc=%Rrc\n", rc);
2032
2033 RTFileClose(hFile);
2034 }
2035 else
2036 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "RTFileOpen(,%s,) failed. rc=%Rrc\n", pszFile, rc);
2037
2038 return rc;
2039}
2040
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