VirtualBox

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

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

scm --update-copyright-year

  • 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 76553 2019-01-01 01:45:53Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Native Commands.
4 */
5
6/*
7 * Copyright (C) 2006-2019 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, pszModName, enmArch, 0 /*cbImage*/,
1400 &hDbgMod, RTErrInfoInitStatic(&ErrInfo));
1401 if (RT_FAILURE(rc))
1402 {
1403 if (RTErrInfoIsSet(&ErrInfo.Core))
1404 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3ModInMem failed for %Dv: %s", &ModAddress, ErrInfo.Core.pszMsg);
1405 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3ModInMem failed for %Dv", &ModAddress);
1406 }
1407
1408 /*
1409 * Link the module into the appropriate address space.
1410 */
1411 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1412 rc = DBGFR3AsLinkModule(pUVM, pDbgc->hDbgAs, hDbgMod, &ModAddress, NIL_RTDBGSEGIDX, RTDBGASLINK_FLAGS_REPLACE);
1413 RTDbgModRelease(hDbgMod);
1414 if (RT_FAILURE(rc))
1415 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3AsLinkModule failed for %Dv", &ModAddress);
1416 return VINF_SUCCESS;
1417}
1418
1419
1420/**
1421 * @callback_method_impl{FNDBGCCMD, The 'loadmap' command.}
1422 */
1423static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1424{
1425 /*
1426 * Validate the parsing and make sense of the input.
1427 * This is a mess as usual because we don't trust the parser yet.
1428 */
1429 AssertReturn( cArgs >= 2
1430 && cArgs <= 5
1431 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1432 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1433 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1434
1435 const char *pszFilename = paArgs[0].u.pszString;
1436
1437 DBGFADDRESS ModAddress;
1438 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1439 if (RT_FAILURE(rc))
1440 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1441
1442 const char *pszModName = NULL;
1443 if (cArgs >= 3)
1444 {
1445 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1446 pszModName = paArgs[2].u.pszString;
1447 }
1448
1449 RTGCUINTPTR uSubtrahend = 0;
1450 if (cArgs >= 4)
1451 {
1452 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1453 uSubtrahend = paArgs[3].u.u64Number;
1454 }
1455
1456 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1457 if (cArgs >= 5)
1458 {
1459 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1460 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1461 if ( iModSeg != paArgs[4].u.u64Number
1462 || iModSeg > RTDBGSEGIDX_LAST)
1463 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1464 }
1465
1466 /*
1467 * Try create a module for it.
1468 */
1469 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1470 rc = DBGFR3AsLoadMap(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1471 if (RT_FAILURE(rc))
1472 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1473 pszFilename, pszModName, &paArgs[1]);
1474
1475 NOREF(pCmd);
1476 return VINF_SUCCESS;
1477}
1478
1479
1480/**
1481 * @callback_method_impl{FNDBGCCMD, The 'loadseg' command.}
1482 */
1483static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1484{
1485 /*
1486 * Validate the parsing and make sense of the input.
1487 * This is a mess as usual because we don't trust the parser yet.
1488 */
1489 AssertReturn( cArgs >= 3
1490 && cArgs <= 4
1491 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1492 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1493 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1494 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1495
1496 const char *pszFilename = paArgs[0].u.pszString;
1497
1498 DBGFADDRESS ModAddress;
1499 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1500 if (RT_FAILURE(rc))
1501 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1502
1503 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[2].u.u64Number;
1504 if ( iModSeg != paArgs[2].u.u64Number
1505 || iModSeg > RTDBGSEGIDX_LAST)
1506 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1507
1508 const char *pszModName = NULL;
1509 if (cArgs >= 4)
1510 {
1511 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1512 pszModName = paArgs[3].u.pszString;
1513 }
1514
1515 /*
1516 * Call the debug info manager about this loading.
1517 */
1518 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1519 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, RTLDRARCH_WHATEVER,
1520 &ModAddress, iModSeg, RTDBGASLINK_FLAGS_REPLACE);
1521 if (RT_FAILURE(rc))
1522 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,,)\n",
1523 pszFilename, pszModName, &paArgs[1]);
1524
1525 NOREF(pCmd);
1526 return VINF_SUCCESS;
1527}
1528
1529
1530/**
1531 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1532 */
1533static DECLCALLBACK(int) dbgcCmdUnload(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1534{
1535 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1536
1537 /*
1538 * Validate the parsing and make sense of the input.
1539 * This is a mess as usual because we don't trust the parser yet.
1540 */
1541 AssertReturn( cArgs >= 1
1542 && paArgs[0].enmType == DBGCVAR_TYPE_STRING,
1543 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1544 for (unsigned i = 0; i < cArgs; i++)
1545 {
1546 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1547
1548 int rc = DBGFR3AsUnlinkModuleByName(pUVM, pDbgc->hDbgAs, paArgs[i].u.pszString);
1549 if (RT_FAILURE(rc))
1550 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsUnlinkModuleByName(,,'%s')\n", paArgs[i].u.pszString);
1551 }
1552
1553 NOREF(pCmd);
1554 return VINF_SUCCESS;
1555}
1556
1557
1558/**
1559 * @callback_method_impl{FNDBGCCMD, The 'set' command.}
1560 */
1561static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1562{
1563 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1564
1565 /* parse sanity check. */
1566 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1567 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1568 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1569
1570
1571 /*
1572 * A variable must start with an alpha chars and only contain alpha numerical chars.
1573 */
1574 const char *pszVar = paArgs[0].u.pszString;
1575 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1576 return DBGCCmdHlpPrintf(pCmdHlp,
1577 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!",
1578 paArgs[0].u.pszString);
1579
1580 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1581 pszVar++;
1582 if (*pszVar)
1583 return DBGCCmdHlpPrintf(pCmdHlp,
1584 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!",
1585 paArgs[0].u.pszString);
1586
1587
1588 /*
1589 * Calc variable size.
1590 */
1591 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1592 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1593 cbVar += 1 + (size_t)paArgs[1].u64Range;
1594
1595 /*
1596 * Look for existing one.
1597 */
1598 pszVar = paArgs[0].u.pszString;
1599 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1600 {
1601 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1602 {
1603 /*
1604 * Update existing variable.
1605 */
1606 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1607 if (!pv)
1608 return VERR_DBGC_PARSE_NO_MEMORY;
1609 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1610
1611 pVar->Var = paArgs[1];
1612 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1613 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1614 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1615 return 0;
1616 }
1617 }
1618
1619 /*
1620 * Allocate another.
1621 */
1622 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1623
1624 pVar->Var = paArgs[1];
1625 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1626 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1627 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1628
1629 /* need to reallocate the pointer array too? */
1630 if (!(pDbgc->cVars % 0x20))
1631 {
1632 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1633 if (!pv)
1634 {
1635 RTMemFree(pVar);
1636 return VERR_DBGC_PARSE_NO_MEMORY;
1637 }
1638 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1639 }
1640 pDbgc->papVars[pDbgc->cVars++] = pVar;
1641
1642 NOREF(pCmd); NOREF(pUVM); NOREF(cArgs);
1643 return 0;
1644}
1645
1646
1647/**
1648 * @callback_method_impl{FNDBGCCMD, The 'unset' command.}
1649 */
1650static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1651{
1652 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1653 for (unsigned i = 0; i < cArgs; i++)
1654 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_SYMBOL, VERR_DBGC_PARSE_BUG);
1655
1656 /*
1657 * Iterate the variables and unset them.
1658 */
1659 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1660 {
1661 const char *pszVar = paArgs[iArg].u.pszString;
1662
1663 /*
1664 * Look up the variable.
1665 */
1666 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1667 {
1668 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1669 {
1670 /*
1671 * Shuffle the array removing this entry.
1672 */
1673 void *pvFree = pDbgc->papVars[iVar];
1674 if (iVar + 1 < pDbgc->cVars)
1675 memmove(&pDbgc->papVars[iVar],
1676 &pDbgc->papVars[iVar + 1],
1677 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1678 pDbgc->papVars[--pDbgc->cVars] = NULL;
1679
1680 RTMemFree(pvFree);
1681 }
1682 } /* lookup */
1683 } /* arg loop */
1684
1685 NOREF(pCmd); NOREF(pUVM);
1686 return 0;
1687}
1688
1689
1690/**
1691 * @callback_method_impl{FNDBGCCMD, The 'loadvars' command.}
1692 */
1693static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1694{
1695 /*
1696 * Don't trust the parser.
1697 */
1698 if ( cArgs != 1
1699 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1700 {
1701 AssertMsgFailed(("Expected one string exactly!\n"));
1702 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1703 }
1704
1705 /*
1706 * Iterate the variables and unset them.
1707 */
1708 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1709 if (pFile)
1710 {
1711 char szLine[4096];
1712 while (fgets(szLine, sizeof(szLine), pFile))
1713 {
1714 /* Strip it. */
1715 char *psz = szLine;
1716 while (RT_C_IS_BLANK(*psz))
1717 psz++;
1718 int i = (int)strlen(psz) - 1;
1719 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1720 psz[i--] ='\0';
1721 /* Execute it if not comment or empty line. */
1722 if ( *psz != '\0'
1723 && *psz != '#'
1724 && *psz != ';')
1725 {
1726 DBGCCmdHlpPrintf(pCmdHlp, "dbg: set %s", psz);
1727 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1728 }
1729 }
1730 fclose(pFile);
1731 }
1732 else
1733 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1734
1735 NOREF(pCmd); NOREF(pUVM);
1736 return 0;
1737}
1738
1739
1740/**
1741 * @callback_method_impl{FNDBGCCMD, The 'showvars' command.}
1742 */
1743static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1744{
1745 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1746
1747 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1748 {
1749 int rc = DBGCCmdHlpPrintf(pCmdHlp, "%-20s ", &pDbgc->papVars[iVar]->szName);
1750 if (!rc)
1751 rc = dbgcCmdFormat(pCmd, pCmdHlp, pUVM, &pDbgc->papVars[iVar]->Var, 1);
1752 if (rc)
1753 return rc;
1754 }
1755
1756 NOREF(paArgs); NOREF(cArgs);
1757 return 0;
1758}
1759
1760
1761/**
1762 * @callback_method_impl{FNDBGCCMD, The 'loadplugin' command.}
1763 */
1764static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1765{
1766 RT_NOREF1(pUVM);
1767 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1768
1769 /*
1770 * Loop thru the plugin names.
1771 */
1772 for (unsigned i = 0; i < cArgs; i++)
1773 {
1774 char szPlugIn[128];
1775 RTERRINFOSTATIC ErrInfo;
1776 szPlugIn[0] = '\0';
1777 int rc = DBGFR3PlugInLoad(pDbgc->pUVM, paArgs[i].u.pszString, szPlugIn, sizeof(szPlugIn), RTErrInfoInitStatic(&ErrInfo));
1778 if (RT_SUCCESS(rc))
1779 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s' (%s)\n", szPlugIn, paArgs[i].u.pszString);
1780 else if (rc == VERR_ALREADY_EXISTS)
1781 DBGCCmdHlpPrintf(pCmdHlp, "A plug-in named '%s' is already loaded\n", szPlugIn);
1782 else if (szPlugIn[0])
1783 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s' ('%s'): %s",
1784 szPlugIn, paArgs[i].u.pszString, ErrInfo.szMsg);
1785 else
1786 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s': %s",
1787 paArgs[i].u.pszString, ErrInfo.szMsg);
1788 }
1789
1790 return VINF_SUCCESS;
1791}
1792
1793
1794/**
1795 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1796 */
1797static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1798{
1799 RT_NOREF1(pUVM);
1800 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1801
1802 /*
1803 * Loop thru the given plug-in names.
1804 */
1805 for (unsigned i = 0; i < cArgs; i++)
1806 {
1807 int rc = DBGFR3PlugInUnload(pDbgc->pUVM, paArgs[i].u.pszString);
1808 if (RT_SUCCESS(rc))
1809 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", paArgs[i].u.pszString);
1810 else if (rc == VERR_NOT_FOUND)
1811 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' was not found\n", paArgs[i].u.pszString);
1812 else
1813 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInUnload failed for '%s'", paArgs[i].u.pszString);
1814 }
1815
1816 return VINF_SUCCESS;
1817}
1818
1819
1820/**
1821 * @callback_method_impl{FNDBGCCMD, The 'harakiri' command.}
1822 */
1823static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1824{
1825 Log(("dbgcCmdHarakiri\n"));
1826 for (;;)
1827 exit(126);
1828 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs);
1829}
1830
1831
1832/**
1833 * @callback_method_impl{FNDBGCCMD, The 'writecore' command.}
1834 */
1835static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1836{
1837 Log(("dbgcCmdWriteCore\n"));
1838
1839 /*
1840 * Validate input, lots of paranoia here.
1841 */
1842 if ( cArgs != 1
1843 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1844 {
1845 AssertMsgFailed(("Expected one string exactly!\n"));
1846 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1847 }
1848
1849 const char *pszDumpPath = paArgs[0].u.pszString;
1850 if (!pszDumpPath)
1851 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
1852
1853 int rc = DBGFR3CoreWrite(pUVM, pszDumpPath, true /*fReplaceFile*/);
1854 if (RT_FAILURE(rc))
1855 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
1856
1857 return VINF_SUCCESS;
1858}
1859
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