VirtualBox

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

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

Debugger: Started on dumpimage command.

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