VirtualBox

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

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

VMM/DBGF: Rework part 1 to make it work well with SMP VMs. bugref:9822

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