VirtualBox

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

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

doxygen: fixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 71.7 KB
Line 
1/* $Id: DBGCCommands.cpp 58170 2015-10-12 09:27:14Z 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 /** @todo Load the script here, but someone else should do the actual
912 * evaluation and execution of it. */
913
914 /*
915 * Try open the script.
916 */
917 const char *pszFilename = paArgs[0].u.pszString;
918 FILE *pFile = fopen(pszFilename, "r");
919 if (!pFile)
920 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to open '%s'.\n", pszFilename);
921
922 /*
923 * Execute it line by line.
924 */
925 int rc = 0;
926 unsigned iLine = 0;
927 char szLine[8192];
928 while (fgets(szLine, sizeof(szLine), pFile))
929 {
930 /* check that the line isn't too long. */
931 char *pszEnd = strchr(szLine, '\0');
932 if (pszEnd == &szLine[sizeof(szLine) - 1])
933 {
934 rc = DBGCCmdHlpPrintf(pCmdHlp, "runscript error: Line #%u is too long\n", iLine);
935 break;
936 }
937 iLine++;
938
939 /* strip leading blanks and check for comment / blank line. */
940 char *psz = RTStrStripL(szLine);
941 if ( *psz == '\0'
942 || *psz == '\n'
943 || *psz == '#')
944 continue;
945
946 /* strip trailing blanks and check for empty line (\r case). */
947 while ( pszEnd > psz
948 && RT_C_IS_SPACE(pszEnd[-1])) /* RT_C_IS_SPACE includes \n and \r normally. */
949 *--pszEnd = '\0';
950
951 /** @todo check for Control-C / Cancel at this point... */
952
953 /*
954 * Execute the command.
955 *
956 * This is a bit wasteful with scratch space btw., can fix it later.
957 * The whole return code crap should be fixed too, so that it's possible
958 * to know whether a command succeeded (RT_SUCCESS()) or failed, and
959 * more importantly why it failed.
960 */
961 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
962 if (RT_FAILURE(rc))
963 {
964 if (rc == VERR_BUFFER_OVERFLOW)
965 rc = DBGCCmdHlpPrintf(pCmdHlp, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
966 break;
967 }
968 if (rc == VWRN_DBGC_CMD_PENDING)
969 {
970 rc = DBGCCmdHlpPrintf(pCmdHlp, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
971 break;
972 }
973 }
974
975 fclose(pFile);
976
977 NOREF(pCmd); NOREF(pUVM);
978 return rc;
979}
980
981
982/**
983 * @callback_method_impl{FNDBGCCMD, The 'detect' command.}
984 */
985static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
986{
987 /* check that the parser did what it's supposed to do. */
988 if (cArgs != 0)
989 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
990
991 /*
992 * Perform the detection.
993 */
994 char szName[64];
995 int rc = DBGFR3OSDetect(pUVM, szName, sizeof(szName));
996 if (RT_FAILURE(rc))
997 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().\n");
998 if (rc == VINF_SUCCESS)
999 {
1000 rc = DBGCCmdHlpPrintf(pCmdHlp, "Guest OS: %s\n", szName);
1001 char szVersion[512];
1002 int rc2 = DBGFR3OSQueryNameAndVersion(pUVM, NULL, 0, szVersion, sizeof(szVersion));
1003 if (RT_SUCCESS(rc2))
1004 rc = DBGCCmdHlpPrintf(pCmdHlp, "Version : %s\n", szVersion);
1005 }
1006 else
1007 rc = DBGCCmdHlpPrintf(pCmdHlp, "Unable to figure out which guest OS it is, sorry.\n");
1008 NOREF(pCmd); NOREF(paArgs);
1009 return rc;
1010}
1011
1012
1013/**
1014 * @callback_method_impl{FNDBGCCMD, The 'dmesg' command.}
1015 */
1016static DECLCALLBACK(int) dbgcCmdDmesg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1017{
1018 /* check that the parser did what it's supposed to do. */
1019 if (cArgs > 1)
1020 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1021 uint32_t cMessages = UINT32_MAX;
1022 if (cArgs == 1)
1023 {
1024 if (paArgs[0].enmType != DBGCVAR_TYPE_NUMBER)
1025 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1026 cMessages = paArgs[0].u.u64Number <= UINT32_MAX ? (uint32_t)paArgs[0].u.u64Number : UINT32_MAX;
1027 }
1028
1029 /*
1030 * Query the interface.
1031 */
1032 int rc;
1033 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(pUVM, DBGFOSINTERFACE_DMESG);
1034 if (pDmesg)
1035 {
1036 size_t cbActual;
1037 size_t cbBuf = _512K;
1038 char *pszBuf = (char *)RTMemAlloc(cbBuf);
1039 if (pszBuf)
1040 {
1041 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
1042
1043 uint32_t cTries = 10;
1044 while (rc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
1045 {
1046 RTMemFree(pszBuf);
1047 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
1048 pszBuf = (char *)RTMemAlloc(cbBuf);
1049 if (RT_UNLIKELY(!pszBuf))
1050 {
1051 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
1052 break;
1053 }
1054 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
1055 }
1056 if (RT_SUCCESS(rc))
1057 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\n", pszBuf);
1058 else if (rc == VERR_BUFFER_OVERFLOW && pszBuf)
1059 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\nWarning: incomplete\n", pszBuf);
1060 else
1061 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "pfnQueryKernelLog failed: %Rrc\n", rc);
1062 RTMemFree(pszBuf);
1063 }
1064 else
1065 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
1066 }
1067 else
1068 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "The dmesg interface isn't implemented by guest OS.\n");
1069 return rc;
1070}
1071
1072
1073/**
1074 * @callback_method_impl{FNDBGCCMD, The 'cpu' command.}
1075 */
1076static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1077{
1078 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1079
1080 /* check that the parser did what it's supposed to do. */
1081 if ( cArgs != 0
1082 && ( cArgs != 1
1083 || paArgs[0].enmType != DBGCVAR_TYPE_NUMBER))
1084 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1085 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1086
1087 int rc;
1088 if (!cArgs)
1089 rc = DBGCCmdHlpPrintf(pCmdHlp, "Current CPU ID: %u\n", pDbgc->idCpu);
1090 else
1091 {
1092 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
1093 if (paArgs[0].u.u64Number >= cCpus)
1094 rc = DBGCCmdHlpPrintf(pCmdHlp, "error: idCpu %u is out of range! Highest ID is %u.\n",
1095 paArgs[0].u.u64Number, cCpus-1);
1096 else
1097 {
1098 rc = DBGCCmdHlpPrintf(pCmdHlp, "Changed CPU from %u to %u.\n",
1099 pDbgc->idCpu, (VMCPUID)paArgs[0].u.u64Number);
1100 pDbgc->idCpu = (VMCPUID)paArgs[0].u.u64Number;
1101 }
1102 }
1103 return rc;
1104}
1105
1106
1107/**
1108 * @callback_method_impl{FNDBGCCMD, The 'info' command.}
1109 */
1110static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1111{
1112 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1113
1114 /*
1115 * Validate input.
1116 */
1117 if ( cArgs < 1
1118 || cArgs > 2
1119 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
1120 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
1121 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
1122 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1123
1124 /*
1125 * Dump it.
1126 */
1127 int rc = DBGFR3InfoEx(pUVM, pDbgc->idCpu,
1128 paArgs[0].u.pszString,
1129 cArgs == 2 ? paArgs[1].u.pszString : NULL,
1130 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
1131 if (RT_FAILURE(rc))
1132 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3InfoEx()\n");
1133
1134 NOREF(pCmd);
1135 return 0;
1136}
1137
1138
1139/**
1140 * @callback_method_impl{FNDBGCCMD, The 'log' command.}
1141 */
1142static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1143{
1144 int rc;
1145 if (cArgs == 0)
1146 {
1147 char szBuf[_64K];
1148 rc = RTLogGetGroupSettings(NULL, szBuf, sizeof(szBuf));
1149 if (RT_FAILURE(rc))
1150 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1151 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG=%s\n", szBuf);
1152 }
1153 else
1154 {
1155 rc = DBGFR3LogModifyGroups(pUVM, paArgs[0].u.pszString);
1156 if (RT_FAILURE(rc))
1157 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1158 }
1159 NOREF(pCmd);
1160 return VINF_SUCCESS;
1161}
1162
1163
1164/**
1165 * @callback_method_impl{FNDBGCCMD, The 'logdest' command.}
1166 */
1167static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1168{
1169 int rc;
1170 if (cArgs == 0)
1171 {
1172 char szBuf[_16K];
1173 rc = RTLogGetDestinations(NULL, szBuf, sizeof(szBuf));
1174 if (RT_FAILURE(rc))
1175 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1176 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_DEST=%s\n", szBuf);
1177 }
1178 else
1179 {
1180 rc = DBGFR3LogModifyDestinations(pUVM, paArgs[0].u.pszString);
1181 if (RT_FAILURE(rc))
1182 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1183 }
1184 NOREF(pCmd);
1185 return VINF_SUCCESS;
1186}
1187
1188
1189/**
1190 * @callback_method_impl{FNDBGCCMD, The 'logflags' command.}
1191 */
1192static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1193{
1194 int rc;
1195 if (cArgs == 0)
1196 {
1197 char szBuf[_16K];
1198 rc = RTLogGetFlags(NULL, szBuf, sizeof(szBuf));
1199 if (RT_FAILURE(rc))
1200 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetFlags(NULL,,%#zx)\n", sizeof(szBuf));
1201 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_FLAGS=%s\n", szBuf);
1202 }
1203 else
1204 {
1205 rc = DBGFR3LogModifyFlags(pUVM, paArgs[0].u.pszString);
1206 if (RT_FAILURE(rc))
1207 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1208 }
1209
1210 NOREF(pCmd);
1211 return rc;
1212}
1213
1214
1215/**
1216 * @callback_method_impl{FNDBGCCMD, The 'logflush' command.}
1217 */
1218static DECLCALLBACK(int) dbgcCmdLogFlush(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1219{
1220 RTLogFlush(NULL);
1221 PRTLOGGER pLogRel = RTLogRelGetDefaultInstance();
1222 if (pLogRel)
1223 RTLogFlush(pLogRel);
1224
1225 NOREF(pCmd); NOREF(cArgs);
1226 return VINF_SUCCESS;
1227}
1228
1229
1230/**
1231 * @callback_method_impl{FNDBGCCMD, The 'format' command.}
1232 */
1233static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1234{
1235 LogFlow(("dbgcCmdFormat\n"));
1236 static const char *apszRangeDesc[] =
1237 {
1238 "none", "bytes", "elements"
1239 };
1240 int rc;
1241
1242 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1243 {
1244 switch (paArgs[iArg].enmType)
1245 {
1246 case DBGCVAR_TYPE_UNKNOWN:
1247 rc = DBGCCmdHlpPrintf(pCmdHlp,
1248 "Unknown variable type!\n");
1249 break;
1250 case DBGCVAR_TYPE_GC_FLAT:
1251 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1252 rc = DBGCCmdHlpPrintf(pCmdHlp,
1253 "Guest flat address: %%%08x range %lld %s\n",
1254 paArgs[iArg].u.GCFlat,
1255 paArgs[iArg].u64Range,
1256 apszRangeDesc[paArgs[iArg].enmRangeType]);
1257 else
1258 rc = DBGCCmdHlpPrintf(pCmdHlp,
1259 "Guest flat address: %%%08x\n",
1260 paArgs[iArg].u.GCFlat);
1261 break;
1262 case DBGCVAR_TYPE_GC_FAR:
1263 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1264 rc = DBGCCmdHlpPrintf(pCmdHlp,
1265 "Guest far address: %04x:%08x range %lld %s\n",
1266 paArgs[iArg].u.GCFar.sel,
1267 paArgs[iArg].u.GCFar.off,
1268 paArgs[iArg].u64Range,
1269 apszRangeDesc[paArgs[iArg].enmRangeType]);
1270 else
1271 rc = DBGCCmdHlpPrintf(pCmdHlp,
1272 "Guest far address: %04x:%08x\n",
1273 paArgs[iArg].u.GCFar.sel,
1274 paArgs[iArg].u.GCFar.off);
1275 break;
1276 case DBGCVAR_TYPE_GC_PHYS:
1277 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1278 rc = DBGCCmdHlpPrintf(pCmdHlp,
1279 "Guest physical address: %%%%%08x range %lld %s\n",
1280 paArgs[iArg].u.GCPhys,
1281 paArgs[iArg].u64Range,
1282 apszRangeDesc[paArgs[iArg].enmRangeType]);
1283 else
1284 rc = DBGCCmdHlpPrintf(pCmdHlp,
1285 "Guest physical address: %%%%%08x\n",
1286 paArgs[iArg].u.GCPhys);
1287 break;
1288 case DBGCVAR_TYPE_HC_FLAT:
1289 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1290 rc = DBGCCmdHlpPrintf(pCmdHlp,
1291 "Host flat address: %%%08x range %lld %s\n",
1292 paArgs[iArg].u.pvHCFlat,
1293 paArgs[iArg].u64Range,
1294 apszRangeDesc[paArgs[iArg].enmRangeType]);
1295 else
1296 rc = DBGCCmdHlpPrintf(pCmdHlp,
1297 "Host flat address: %%%08x\n",
1298 paArgs[iArg].u.pvHCFlat);
1299 break;
1300 case DBGCVAR_TYPE_HC_PHYS:
1301 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1302 rc = DBGCCmdHlpPrintf(pCmdHlp,
1303 "Host physical address: %RHp range %lld %s\n",
1304 paArgs[iArg].u.HCPhys,
1305 paArgs[iArg].u64Range,
1306 apszRangeDesc[paArgs[iArg].enmRangeType]);
1307 else
1308 rc = DBGCCmdHlpPrintf(pCmdHlp,
1309 "Host physical address: %RHp\n",
1310 paArgs[iArg].u.HCPhys);
1311 break;
1312
1313 case DBGCVAR_TYPE_STRING:
1314 rc = DBGCCmdHlpPrintf(pCmdHlp,
1315 "String, %lld bytes long: %s\n",
1316 paArgs[iArg].u64Range,
1317 paArgs[iArg].u.pszString);
1318 break;
1319
1320 case DBGCVAR_TYPE_SYMBOL:
1321 rc = DBGCCmdHlpPrintf(pCmdHlp,
1322 "Symbol, %lld bytes long: %s\n",
1323 paArgs[iArg].u64Range,
1324 paArgs[iArg].u.pszString);
1325 break;
1326
1327 case DBGCVAR_TYPE_NUMBER:
1328 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1329 rc = DBGCCmdHlpPrintf(pCmdHlp,
1330 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1331 paArgs[iArg].u.u64Number,
1332 paArgs[iArg].u.u64Number,
1333 paArgs[iArg].u.u64Number,
1334 paArgs[iArg].u64Range,
1335 apszRangeDesc[paArgs[iArg].enmRangeType]);
1336 else
1337 rc = DBGCCmdHlpPrintf(pCmdHlp,
1338 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1339 paArgs[iArg].u.u64Number,
1340 paArgs[iArg].u.u64Number,
1341 paArgs[iArg].u.u64Number);
1342 break;
1343
1344 default:
1345 rc = DBGCCmdHlpPrintf(pCmdHlp,
1346 "Invalid argument type %d\n",
1347 paArgs[iArg].enmType);
1348 break;
1349 }
1350 } /* arg loop */
1351
1352 NOREF(pCmd); NOREF(pUVM);
1353 return 0;
1354}
1355
1356
1357/**
1358 * @callback_method_impl{FNDBGCCMD, The 'loadimage' command.}
1359 */
1360static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1361{
1362 /*
1363 * Validate the parsing and make sense of the input.
1364 * This is a mess as usual because we don't trust the parser yet.
1365 */
1366 AssertReturn( cArgs >= 2
1367 && cArgs <= 3
1368 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1369 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1370 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1371
1372 const char *pszFilename = paArgs[0].u.pszString;
1373
1374 DBGFADDRESS ModAddress;
1375 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1376 if (RT_FAILURE(rc))
1377 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1378
1379 const char *pszModName = NULL;
1380 if (cArgs >= 3)
1381 {
1382 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1383 pszModName = paArgs[2].u.pszString;
1384 }
1385
1386 /*
1387 * Determine the desired image arch from the load command used.
1388 */
1389 RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
1390 if (pCmd->pszCmd[sizeof("loadimage") - 1] == '3')
1391 enmArch = RTLDRARCH_X86_32;
1392 else if (pCmd->pszCmd[sizeof("loadimage") - 1] == '6')
1393 enmArch = RTLDRARCH_AMD64;
1394
1395 /*
1396 * Try create a module for it.
1397 */
1398 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1399 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, enmArch, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1400 if (RT_FAILURE(rc))
1401 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1402 pszFilename, pszModName, &paArgs[1]);
1403
1404 return VINF_SUCCESS;
1405}
1406
1407
1408/**
1409 * @callback_method_impl{FNDBGCCMD, The 'loadmap' command.}
1410 */
1411static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1412{
1413 /*
1414 * Validate the parsing and make sense of the input.
1415 * This is a mess as usual because we don't trust the parser yet.
1416 */
1417 AssertReturn( cArgs >= 2
1418 && cArgs <= 5
1419 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1420 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1421 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1422
1423 const char *pszFilename = paArgs[0].u.pszString;
1424
1425 DBGFADDRESS ModAddress;
1426 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1427 if (RT_FAILURE(rc))
1428 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1429
1430 const char *pszModName = NULL;
1431 if (cArgs >= 3)
1432 {
1433 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1434 pszModName = paArgs[2].u.pszString;
1435 }
1436
1437 RTGCUINTPTR uSubtrahend = 0;
1438 if (cArgs >= 4)
1439 {
1440 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1441 uSubtrahend = paArgs[3].u.u64Number;
1442 }
1443
1444 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1445 if (cArgs >= 5)
1446 {
1447 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1448 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1449 if ( iModSeg != paArgs[4].u.u64Number
1450 || iModSeg > RTDBGSEGIDX_LAST)
1451 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1452 }
1453
1454 /*
1455 * Try create a module for it.
1456 */
1457 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1458 rc = DBGFR3AsLoadMap(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1459 if (RT_FAILURE(rc))
1460 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1461 pszFilename, pszModName, &paArgs[1]);
1462
1463 NOREF(pCmd);
1464 return VINF_SUCCESS;
1465}
1466
1467
1468/**
1469 * @callback_method_impl{FNDBGCCMD, The 'loadseg' command.}
1470 */
1471static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1472{
1473 /*
1474 * Validate the parsing and make sense of the input.
1475 * This is a mess as usual because we don't trust the parser yet.
1476 */
1477 AssertReturn( cArgs >= 3
1478 && cArgs <= 4
1479 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1480 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1481 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1482 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1483
1484 const char *pszFilename = paArgs[0].u.pszString;
1485
1486 DBGFADDRESS ModAddress;
1487 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1488 if (RT_FAILURE(rc))
1489 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1490
1491 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1492 if ( iModSeg != paArgs[2].u.u64Number
1493 || iModSeg > RTDBGSEGIDX_LAST)
1494 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1495
1496 const char *pszModName = NULL;
1497 if (cArgs >= 4)
1498 {
1499 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1500 pszModName = paArgs[3].u.pszString;
1501 }
1502
1503 /*
1504 * Call the debug info manager about this loading.
1505 */
1506 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1507 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, RTLDRARCH_WHATEVER, &ModAddress, iModSeg, 0 /*fFlags*/);
1508 if (RT_FAILURE(rc))
1509 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1510 pszFilename, pszModName, &paArgs[1]);
1511
1512 NOREF(pCmd);
1513 return VINF_SUCCESS;
1514}
1515
1516
1517/**
1518 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1519 */
1520static DECLCALLBACK(int) dbgcCmdUnload(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1521{
1522 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1523
1524 /*
1525 * Validate the parsing and make sense of the input.
1526 * This is a mess as usual because we don't trust the parser yet.
1527 */
1528 AssertReturn( cArgs >= 1
1529 && paArgs[0].enmType == DBGCVAR_TYPE_STRING,
1530 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1531 for (unsigned i = 0; i < cArgs; i++)
1532 {
1533 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1534
1535 int rc = DBGFR3AsUnlinkModuleByName(pUVM, pDbgc->hDbgAs, paArgs[i].u.pszString);
1536 if (RT_FAILURE(rc))
1537 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsUnlinkModuleByName(,,'%s')\n", paArgs[i].u.pszString);
1538 }
1539
1540 NOREF(pCmd);
1541 return VINF_SUCCESS;
1542}
1543
1544
1545/**
1546 * @callback_method_impl{FNDBGCCMD, The 'set' command.}
1547 */
1548static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1549{
1550 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1551
1552 /* parse sanity check. */
1553 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1554 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1555 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1556
1557
1558 /*
1559 * A variable must start with an alpha chars and only contain alpha numerical chars.
1560 */
1561 const char *pszVar = paArgs[0].u.pszString;
1562 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1563 return DBGCCmdHlpPrintf(pCmdHlp,
1564 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!",
1565 paArgs[0].u.pszString);
1566
1567 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1568 pszVar++;
1569 if (*pszVar)
1570 return DBGCCmdHlpPrintf(pCmdHlp,
1571 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!",
1572 paArgs[0].u.pszString);
1573
1574
1575 /*
1576 * Calc variable size.
1577 */
1578 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1579 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1580 cbVar += 1 + (size_t)paArgs[1].u64Range;
1581
1582 /*
1583 * Look for existing one.
1584 */
1585 pszVar = paArgs[0].u.pszString;
1586 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1587 {
1588 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1589 {
1590 /*
1591 * Update existing variable.
1592 */
1593 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1594 if (!pv)
1595 return VERR_DBGC_PARSE_NO_MEMORY;
1596 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1597
1598 pVar->Var = paArgs[1];
1599 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1600 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1601 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1602 return 0;
1603 }
1604 }
1605
1606 /*
1607 * Allocate another.
1608 */
1609 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1610
1611 pVar->Var = paArgs[1];
1612 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1613 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1614 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1615
1616 /* need to reallocate the pointer array too? */
1617 if (!(pDbgc->cVars % 0x20))
1618 {
1619 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1620 if (!pv)
1621 {
1622 RTMemFree(pVar);
1623 return VERR_DBGC_PARSE_NO_MEMORY;
1624 }
1625 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1626 }
1627 pDbgc->papVars[pDbgc->cVars++] = pVar;
1628
1629 NOREF(pCmd); NOREF(pUVM); NOREF(cArgs);
1630 return 0;
1631}
1632
1633
1634/**
1635 * @callback_method_impl{FNDBGCCMD, The 'unset' command.}
1636 */
1637static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1638{
1639 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1640 for (unsigned i = 0; i < cArgs; i++)
1641 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_SYMBOL, VERR_DBGC_PARSE_BUG);
1642
1643 /*
1644 * Iterate the variables and unset them.
1645 */
1646 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1647 {
1648 const char *pszVar = paArgs[iArg].u.pszString;
1649
1650 /*
1651 * Look up the variable.
1652 */
1653 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1654 {
1655 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1656 {
1657 /*
1658 * Shuffle the array removing this entry.
1659 */
1660 void *pvFree = pDbgc->papVars[iVar];
1661 if (iVar + 1 < pDbgc->cVars)
1662 memmove(&pDbgc->papVars[iVar],
1663 &pDbgc->papVars[iVar + 1],
1664 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1665 pDbgc->papVars[--pDbgc->cVars] = NULL;
1666
1667 RTMemFree(pvFree);
1668 }
1669 } /* lookup */
1670 } /* arg loop */
1671
1672 NOREF(pCmd); NOREF(pUVM);
1673 return 0;
1674}
1675
1676
1677/**
1678 * @callback_method_impl{FNDBGCCMD, The 'loadvars' command.}
1679 */
1680static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1681{
1682 /*
1683 * Don't trust the parser.
1684 */
1685 if ( cArgs != 1
1686 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1687 {
1688 AssertMsgFailed(("Expected one string exactly!\n"));
1689 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1690 }
1691
1692 /*
1693 * Iterate the variables and unset them.
1694 */
1695 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1696 if (pFile)
1697 {
1698 char szLine[4096];
1699 while (fgets(szLine, sizeof(szLine), pFile))
1700 {
1701 /* Strip it. */
1702 char *psz = szLine;
1703 while (RT_C_IS_BLANK(*psz))
1704 psz++;
1705 int i = (int)strlen(psz) - 1;
1706 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1707 psz[i--] ='\0';
1708 /* Execute it if not comment or empty line. */
1709 if ( *psz != '\0'
1710 && *psz != '#'
1711 && *psz != ';')
1712 {
1713 DBGCCmdHlpPrintf(pCmdHlp, "dbg: set %s", psz);
1714 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1715 }
1716 }
1717 fclose(pFile);
1718 }
1719 else
1720 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1721
1722 NOREF(pCmd); NOREF(pUVM);
1723 return 0;
1724}
1725
1726
1727/**
1728 * @callback_method_impl{FNDBGCCMD, The 'showvars' command.}
1729 */
1730static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1731{
1732 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1733
1734 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1735 {
1736 int rc = DBGCCmdHlpPrintf(pCmdHlp, "%-20s ", &pDbgc->papVars[iVar]->szName);
1737 if (!rc)
1738 rc = dbgcCmdFormat(pCmd, pCmdHlp, pUVM, &pDbgc->papVars[iVar]->Var, 1);
1739 if (rc)
1740 return rc;
1741 }
1742
1743 NOREF(paArgs); NOREF(cArgs);
1744 return 0;
1745}
1746
1747
1748/**
1749 * @callback_method_impl{FNDBGCCMD, The 'loadplugin' command.}
1750 */
1751static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1752{
1753 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1754
1755 /*
1756 * Loop thru the plugin names.
1757 */
1758 for (unsigned i = 0; i < cArgs; i++)
1759 {
1760 char szPlugIn[128];
1761 RTERRINFOSTATIC ErrInfo;
1762 szPlugIn[0] = '\0';
1763 int rc = DBGFR3PlugInLoad(pDbgc->pUVM, paArgs[i].u.pszString, szPlugIn, sizeof(szPlugIn), RTErrInfoInitStatic(&ErrInfo));
1764 if (RT_SUCCESS(rc))
1765 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s' (%s)\n", szPlugIn, paArgs[i].u.pszString);
1766 else if (rc == VERR_ALREADY_EXISTS)
1767 DBGCCmdHlpPrintf(pCmdHlp, "A plug-in named '%s' is already loaded\n", szPlugIn);
1768 else if (szPlugIn[0])
1769 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s' ('%s'): %s",
1770 szPlugIn, paArgs[i].u.pszString, ErrInfo.szMsg);
1771 else
1772 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s': %s",
1773 paArgs[i].u.pszString, ErrInfo.szMsg);
1774 }
1775
1776 return VINF_SUCCESS;
1777}
1778
1779
1780/**
1781 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1782 */
1783static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1784{
1785 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1786
1787 /*
1788 * Loop thru the given plug-in names.
1789 */
1790 for (unsigned i = 0; i < cArgs; i++)
1791 {
1792 int rc = DBGFR3PlugInUnload(pDbgc->pUVM, paArgs[i].u.pszString);
1793 if (RT_SUCCESS(rc))
1794 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", paArgs[i].u.pszString);
1795 else if (rc == VERR_NOT_FOUND)
1796 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' was not found\n", paArgs[i].u.pszString);
1797 else
1798 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInUnload failed for '%s'", paArgs[i].u.pszString);
1799 }
1800
1801 return VINF_SUCCESS;
1802}
1803
1804
1805/**
1806 * @callback_method_impl{FNDBGCCMD, The 'harakiri' command.}
1807 */
1808static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1809{
1810 Log(("dbgcCmdHarakiri\n"));
1811 for (;;)
1812 exit(126);
1813 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs);
1814}
1815
1816
1817/**
1818 * @callback_method_impl{FNDBGCCMD, The 'writecore' command.}
1819 */
1820static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1821{
1822 Log(("dbgcCmdWriteCore\n"));
1823
1824 /*
1825 * Validate input, lots of paranoia here.
1826 */
1827 if ( cArgs != 1
1828 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1829 {
1830 AssertMsgFailed(("Expected one string exactly!\n"));
1831 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1832 }
1833
1834 const char *pszDumpPath = paArgs[0].u.pszString;
1835 if (!pszDumpPath)
1836 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
1837
1838 int rc = DBGFR3CoreWrite(pUVM, pszDumpPath, true /*fReplaceFile*/);
1839 if (RT_FAILURE(rc))
1840 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
1841
1842 return VINF_SUCCESS;
1843}
1844
1845
1846
1847/**
1848 * @callback_method_impl{FNDBGCFUNC, The randu32() function implementation.}
1849 */
1850static DECLCALLBACK(int) dbgcFuncRandU32(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PVM pUVM, PCDBGCVAR paArgs, uint32_t cArgs,
1851 PDBGCVAR pResult)
1852{
1853 AssertReturn(cArgs == 0, VERR_DBGC_PARSE_BUG);
1854 uint32_t u32 = RTRandU32();
1855 DBGCVAR_INIT_NUMBER(pResult, u32);
1856 NOREF(pFunc); NOREF(pCmdHlp); NOREF(pUVM); NOREF(paArgs);
1857 return VINF_SUCCESS;
1858}
1859
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette