VirtualBox

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

Last change on this file since 59229 was 59229, checked in by vboxsync, 9 years ago

DBGC,Main: Global and per-VM debugger console init script support.

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