VirtualBox

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

Last change on this file since 73150 was 73150, checked in by vboxsync, 6 years ago

VMM,DBGC,IPRT: In memory

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