VirtualBox

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

Last change on this file since 62480 was 62480, checked in by vboxsync, 8 years ago

(C) 2016

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