VirtualBox

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

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

Debugger: warnings

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 69.4 KB
Line 
1/* $Id: DBGCCommands.cpp 62838 2016-08-01 17:01:57Z 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 RT_NOREF1(pDbgc);
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 RT_NOREF1(pDbgc);
633 if (pszDescFmt)
634 {
635 va_list va;
636 va_start(va, pszDescFmt);
637 DBGCCmdHlpPrintf(pCmdHlp, pszDescFmt, va);
638 va_end(va);
639 }
640
641 for (uint32_t i = 0; i < cFuncs; i++)
642 dbgcCmdHelpCmdOrFunc(pCmdHlp, paFuncs[i].pszFuncNm, fExternal, paFuncs[i].pszSyntax, paFuncs[i].pszDescription);
643}
644
645
646static void dbgcCmdHelpFunctions(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
647{
648 if (*pcHits)
649 DBGCCmdHlpPrintf(pCmdHlp, "\n");
650 *pcHits += 1;
651
652 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, pDbgc->paEmulationFuncs, pDbgc->cEmulationFuncs, false,
653 "Functions for %s emulation:\n", pDbgc->pszEmulation);
654 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, g_aDbgcFuncs, g_cDbgcFuncs, false,
655 "\nCommon Functions:\n");
656#if 0
657 DBGCEXTLISTS_LOCK_RD();
658 const char *pszDesc = "\nExternal Functions:\n";
659 for (PDBGCEXTFUNCS pExtFunc = g_pExtFuncsHead; pExtFunc; pExtFunc = pExtFunc->pNext)
660 {
661 dbgcCmdHelpFunctionsWorker(pDbgc, pCmdHlp, pExtFunc->paFuncs, pExtFunc->cFuncs, false,
662 pszDesc);
663 pszDesc = NULL;
664 }
665 DBGCEXTLISTS_UNLOCK_RD();
666#endif
667}
668
669
670static void dbgcCmdHelpOperators(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
671{
672 RT_NOREF1(pDbgc);
673 DBGCCmdHlpPrintf(pCmdHlp, !*pcHits ? "Operators:\n" : "\nOperators:\n");
674 *pcHits += 1;
675
676 unsigned iPrecedence = 0;
677 unsigned cLeft = g_cDbgcOps;
678 while (cLeft > 0)
679 {
680 for (unsigned i = 0; i < g_cDbgcOps; i++)
681 if (g_aDbgcOps[i].iPrecedence == iPrecedence)
682 {
683 dbgcCmdHelpCmdOrFunc(pCmdHlp, g_aDbgcOps[i].szName, false,
684 g_aDbgcOps[i].fBinary ? "Binary" : "Unary ",
685 g_aDbgcOps[i].pszDescription);
686 cLeft--;
687 }
688 iPrecedence++;
689 }
690}
691
692
693static void dbgcCmdHelpAll(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
694{
695 *pcHits += 1;
696 DBGCCmdHlpPrintf(pCmdHlp,
697 "\n"
698 "VirtualBox Debugger Help\n"
699 "------------------------\n"
700 "\n");
701 dbgcCmdHelpCommands(pDbgc, pCmdHlp, pcHits);
702 DBGCCmdHlpPrintf(pCmdHlp, "\n");
703 dbgcCmdHelpFunctions(pDbgc, pCmdHlp, pcHits);
704 DBGCCmdHlpPrintf(pCmdHlp, "\n");
705 dbgcCmdHelpOperators(pDbgc, pCmdHlp, pcHits);
706}
707
708
709static void dbgcCmdHelpSummary(PDBGC pDbgc, PDBGCCMDHLP pCmdHlp, uint32_t *pcHits)
710{
711 RT_NOREF1(pDbgc);
712 *pcHits += 1;
713 DBGCCmdHlpPrintf(pCmdHlp,
714 "\n"
715 "VirtualBox Debugger Help Summary\n"
716 "--------------------------------\n"
717 "\n"
718 "help commands Show help on all commands.\n"
719 "help functions Show help on all functions.\n"
720 "help operators Show help on all operators.\n"
721 "help all All the above.\n"
722 "help <cmd-pattern> [...]\n"
723 " Show details help on individual commands, simple\n"
724 " patterns can be used to match several commands.\n"
725 "help [summary] Displays this message.\n"
726 );
727}
728
729
730/**
731 * @callback_method_impl{FNDBGCCMD, The 'help' command.}
732 */
733static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
734{
735 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
736 int rc = VINF_SUCCESS;
737 uint32_t cHits = 0;
738
739 if (!cArgs)
740 /*
741 * No arguments, show summary.
742 */
743 dbgcCmdHelpSummary(pDbgc, pCmdHlp, &cHits);
744 else
745 {
746 /*
747 * Search for the arguments (strings).
748 */
749 DBGCEXTCMDS aFixedCmds[] =
750 {
751 { pDbgc->cEmulationCmds, pDbgc->paEmulationCmds, NULL },
752 { g_cDbgcCmds, g_aDbgcCmds, NULL },
753 };
754 DBGCEXTFUNCS aFixedFuncs[] =
755 {
756 { pDbgc->cEmulationFuncs, pDbgc->paEmulationFuncs, NULL },
757 { g_cDbgcFuncs, g_aDbgcFuncs, NULL },
758 };
759
760 for (unsigned iArg = 0; iArg < cArgs; iArg++)
761 {
762 AssertReturn(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_BUG);
763 const char *pszPattern = paArgs[iArg].u.pszString;
764
765 /* aliases */
766 if ( !strcmp(pszPattern, "commands")
767 || !strcmp(pszPattern, "cmds") )
768 dbgcCmdHelpCommands(pDbgc, pCmdHlp, &cHits);
769 else if ( !strcmp(pszPattern, "functions")
770 || !strcmp(pszPattern, "funcs") )
771 dbgcCmdHelpFunctions(pDbgc, pCmdHlp, &cHits);
772 else if ( !strcmp(pszPattern, "operators")
773 || !strcmp(pszPattern, "ops") )
774 dbgcCmdHelpOperators(pDbgc, pCmdHlp, &cHits);
775 else if (!strcmp(pszPattern, "all"))
776 dbgcCmdHelpAll(pDbgc, pCmdHlp, &cHits);
777 else if (!strcmp(pszPattern, "summary"))
778 dbgcCmdHelpSummary(pDbgc, pCmdHlp, &cHits);
779 /* Individual commands. */
780 else
781 {
782 uint32_t const cPrevHits = cHits;
783
784 /* lookup in the emulation command list first */
785 for (unsigned j = 0; j < RT_ELEMENTS(aFixedCmds); j++)
786 for (unsigned i = 0; i < aFixedCmds[j].cCmds; i++)
787 if (RTStrSimplePatternMatch(pszPattern, aFixedCmds[j].paCmds[i].pszCmd))
788 dbgcPrintHelpCmd(pCmdHlp, &aFixedCmds[j].paCmds[i], false, &cHits);
789 for (unsigned j = 0; j < RT_ELEMENTS(aFixedFuncs); j++)
790 for (unsigned i = 0; i < aFixedFuncs[j].cFuncs; i++)
791 if (RTStrSimplePatternMatch(pszPattern, aFixedFuncs[j].paFuncs[i].pszFuncNm))
792 dbgcPrintHelpFunction(pCmdHlp, &aFixedFuncs[j].paFuncs[i], false, &cHits);
793
794 /* external commands */
795 if ( g_pExtCmdsHead
796 && ( *pszPattern == '.'
797 || *pszPattern == '?'
798 || *pszPattern == '*'))
799 {
800 DBGCEXTLISTS_LOCK_RD();
801 const char *pszPattern2 = pszPattern + (*pszPattern == '.' || *pszPattern == '?');
802 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
803 for (unsigned i = 0; i < pExtCmd->cCmds; i++)
804 if (RTStrSimplePatternMatch(pszPattern2, pExtCmd->paCmds[i].pszCmd))
805 dbgcPrintHelpCmd(pCmdHlp, &pExtCmd->paCmds[i], true, &cHits);
806#if 0
807 for (PDBGCEXTFUNCS pExtFunc = g_pExtFuncsHead; pExtFunc; pExtFunc = pExtFunc->pNext)
808 for (unsigned i = 0; i < pExtFunc->cFuncs; i++)
809 if (RTStrSimplePatternMatch(pszPattern2, pExtFunc->paFuncs[i].pszFuncNm))
810 dbgcPrintHelpFunction(pCmdHlp, &pExtFunc->paFuncs[i], true, &cHits);
811#endif
812 DBGCEXTLISTS_UNLOCK_RD();
813 }
814
815 /* operators */
816 if (cHits == cPrevHits && strlen(paArgs[iArg].u.pszString) < sizeof(g_aDbgcOps[0].szName))
817 for (unsigned i = 0; i < g_cDbgcOps && RT_SUCCESS(rc); i++)
818 if (RTStrSimplePatternMatch(pszPattern, g_aDbgcOps[i].szName))
819 {
820 if (cHits++)
821 DBGCCmdHlpPrintf(pCmdHlp, "\n");
822 dbgcCmdHelpCmdOrFunc(pCmdHlp, g_aDbgcOps[i].szName, false,
823 g_aDbgcOps[i].fBinary ? "Binary" : "Unary ",
824 g_aDbgcOps[i].pszDescription);
825 }
826
827 /* found? */
828 if (cHits == cPrevHits)
829 {
830 DBGCCmdHlpPrintf(pCmdHlp, "error: '%s' was not found!\n",
831 paArgs[iArg].u.pszString);
832 rc = VERR_DBGC_COMMAND_FAILED;
833 }
834 }
835 } /* foreach argument */
836 }
837
838 NOREF(pCmd);
839 NOREF(pUVM);
840 return rc;
841}
842
843
844/**
845 * @callback_method_impl{FNDBGCCMD, The 'quit'\, 'exit' and 'bye' commands. }
846 */
847static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
848{
849 DBGCCmdHlpPrintf(pCmdHlp, "Quitting console...\n");
850 NOREF(pCmd);
851 NOREF(pUVM);
852 NOREF(paArgs);
853 NOREF(cArgs);
854 return VERR_DBGC_QUIT;
855}
856
857
858/**
859 * @callback_method_impl{FNDBGCCMD, The 'stop' command.}
860 */
861static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
862{
863 /*
864 * Check if the VM is halted or not before trying to halt it.
865 */
866 int rc;
867 if (DBGFR3IsHalted(pUVM))
868 rc = DBGCCmdHlpPrintf(pCmdHlp, "warning: The VM is already halted...\n");
869 else
870 {
871 rc = DBGFR3Halt(pUVM);
872 if (RT_SUCCESS(rc))
873 rc = VWRN_DBGC_CMD_PENDING;
874 else
875 rc = DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
876 }
877
878 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs);
879 return rc;
880}
881
882
883/**
884 * @callback_method_impl{FNDBGCCMD, The 'echo' command.}
885 */
886static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
887{
888 /*
889 * Loop thru the arguments and print them with one space between.
890 */
891 int rc = 0;
892 for (unsigned i = 0; i < cArgs; i++)
893 {
894 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_BUG);
895 rc = DBGCCmdHlpPrintf(pCmdHlp, i ? " %s" : "%s", paArgs[i].u.pszString);
896 if (RT_FAILURE(rc))
897 return rc;
898 }
899 NOREF(pCmd); NOREF(pUVM);
900 return DBGCCmdHlpPrintf(pCmdHlp, "\n");
901}
902
903
904/**
905 * @callback_method_impl{FNDBGCCMD, The 'runscript' command.}
906 */
907static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
908{
909 RT_NOREF2(pUVM, pCmd);
910
911 /* check that the parser did what it's supposed to do. */
912 if ( cArgs != 1
913 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
914 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
915
916 /* Pass it on to a common function. */
917 const char *pszFilename = paArgs[0].u.pszString;
918 return dbgcEvalScript(DBGC_CMDHLP2DBGC(pCmdHlp), pszFilename, false /*fAnnounce*/);
919}
920
921
922/**
923 * @callback_method_impl{FNDBGCCMD, The 'detect' command.}
924 */
925static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
926{
927 /* check that the parser did what it's supposed to do. */
928 if (cArgs != 0)
929 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
930
931 /*
932 * Perform the detection.
933 */
934 char szName[64];
935 int rc = DBGFR3OSDetect(pUVM, szName, sizeof(szName));
936 if (RT_FAILURE(rc))
937 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().\n");
938 if (rc == VINF_SUCCESS)
939 {
940 rc = DBGCCmdHlpPrintf(pCmdHlp, "Guest OS: %s\n", szName);
941 char szVersion[512];
942 int rc2 = DBGFR3OSQueryNameAndVersion(pUVM, NULL, 0, szVersion, sizeof(szVersion));
943 if (RT_SUCCESS(rc2))
944 rc = DBGCCmdHlpPrintf(pCmdHlp, "Version : %s\n", szVersion);
945 }
946 else
947 rc = DBGCCmdHlpPrintf(pCmdHlp, "Unable to figure out which guest OS it is, sorry.\n");
948 NOREF(pCmd); NOREF(paArgs);
949 return rc;
950}
951
952
953/**
954 * @callback_method_impl{FNDBGCCMD, The 'dmesg' command.}
955 */
956static DECLCALLBACK(int) dbgcCmdDmesg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
957{
958 /* check that the parser did what it's supposed to do. */
959 if (cArgs > 1)
960 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
961 uint32_t cMessages = UINT32_MAX;
962 if (cArgs == 1)
963 {
964 if (paArgs[0].enmType != DBGCVAR_TYPE_NUMBER)
965 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
966 cMessages = paArgs[0].u.u64Number <= UINT32_MAX ? (uint32_t)paArgs[0].u.u64Number : UINT32_MAX;
967 }
968
969 /*
970 * Query the interface.
971 */
972 int rc;
973 PDBGFOSIDMESG pDmesg = (PDBGFOSIDMESG)DBGFR3OSQueryInterface(pUVM, DBGFOSINTERFACE_DMESG);
974 if (pDmesg)
975 {
976 size_t cbActual;
977 size_t cbBuf = _512K;
978 char *pszBuf = (char *)RTMemAlloc(cbBuf);
979 if (pszBuf)
980 {
981 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
982
983 uint32_t cTries = 10;
984 while (rc == VERR_BUFFER_OVERFLOW && cbBuf < 16*_1M && cTries-- > 0)
985 {
986 RTMemFree(pszBuf);
987 cbBuf = RT_ALIGN_Z(cbActual + _4K, _4K);
988 pszBuf = (char *)RTMemAlloc(cbBuf);
989 if (RT_UNLIKELY(!pszBuf))
990 {
991 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
992 break;
993 }
994 rc = pDmesg->pfnQueryKernelLog(pDmesg, pUVM, 0 /*fFlags*/, cMessages, pszBuf, cbBuf, &cbActual);
995 }
996 if (RT_SUCCESS(rc))
997 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\n", pszBuf);
998 else if (rc == VERR_BUFFER_OVERFLOW && pszBuf)
999 rc = DBGCCmdHlpPrintf(pCmdHlp, "%s\nWarning: incomplete\n", pszBuf);
1000 else
1001 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "pfnQueryKernelLog failed: %Rrc\n", rc);
1002 RTMemFree(pszBuf);
1003 }
1004 else
1005 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "Error allocating %#zu bytes.\n", cbBuf);
1006 }
1007 else
1008 rc = DBGCCmdHlpFail(pCmdHlp, pCmd, "The dmesg interface isn't implemented by guest OS.\n");
1009 return rc;
1010}
1011
1012
1013/**
1014 * @callback_method_impl{FNDBGCCMD, The 'cpu' command.}
1015 */
1016static DECLCALLBACK(int) dbgcCmdCpu(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1017{
1018 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1019
1020 /* check that the parser did what it's supposed to do. */
1021 if ( cArgs != 0
1022 && ( cArgs != 1
1023 || paArgs[0].enmType != DBGCVAR_TYPE_NUMBER))
1024 return DBGCCmdHlpPrintf(pCmdHlp, "parser error\n");
1025 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1026
1027 int rc;
1028 if (!cArgs)
1029 rc = DBGCCmdHlpPrintf(pCmdHlp, "Current CPU ID: %u\n", pDbgc->idCpu);
1030 else
1031 {
1032 VMCPUID cCpus = DBGFR3CpuGetCount(pUVM);
1033 if (paArgs[0].u.u64Number >= cCpus)
1034 rc = DBGCCmdHlpPrintf(pCmdHlp, "error: idCpu %u is out of range! Highest ID is %u.\n",
1035 paArgs[0].u.u64Number, cCpus-1);
1036 else
1037 {
1038 rc = DBGCCmdHlpPrintf(pCmdHlp, "Changed CPU from %u to %u.\n",
1039 pDbgc->idCpu, (VMCPUID)paArgs[0].u.u64Number);
1040 pDbgc->idCpu = (VMCPUID)paArgs[0].u.u64Number;
1041 }
1042 }
1043 return rc;
1044}
1045
1046
1047/**
1048 * @callback_method_impl{FNDBGCCMD, The 'info' command.}
1049 */
1050static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1051{
1052 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1053
1054 /*
1055 * Validate input.
1056 */
1057 if ( cArgs < 1
1058 || cArgs > 2
1059 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
1060 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
1061 return DBGCCmdHlpPrintf(pCmdHlp, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
1062 DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM);
1063
1064 /*
1065 * Dump it.
1066 */
1067 int rc = DBGFR3InfoEx(pUVM, pDbgc->idCpu,
1068 paArgs[0].u.pszString,
1069 cArgs == 2 ? paArgs[1].u.pszString : NULL,
1070 DBGCCmdHlpGetDbgfOutputHlp(pCmdHlp));
1071 if (RT_FAILURE(rc))
1072 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3InfoEx()\n");
1073
1074 NOREF(pCmd);
1075 return 0;
1076}
1077
1078
1079/**
1080 * @callback_method_impl{FNDBGCCMD, The 'log' command.}
1081 */
1082static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1083{
1084 int rc;
1085 if (cArgs == 0)
1086 {
1087 char szBuf[_64K];
1088 rc = RTLogGetGroupSettings(NULL, szBuf, sizeof(szBuf));
1089 if (RT_FAILURE(rc))
1090 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1091 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG=%s\n", szBuf);
1092 }
1093 else
1094 {
1095 rc = DBGFR3LogModifyGroups(pUVM, paArgs[0].u.pszString);
1096 if (RT_FAILURE(rc))
1097 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1098 }
1099 NOREF(pCmd);
1100 return VINF_SUCCESS;
1101}
1102
1103
1104/**
1105 * @callback_method_impl{FNDBGCCMD, The 'logdest' command.}
1106 */
1107static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1108{
1109 int rc;
1110 if (cArgs == 0)
1111 {
1112 char szBuf[_16K];
1113 rc = RTLogGetDestinations(NULL, szBuf, sizeof(szBuf));
1114 if (RT_FAILURE(rc))
1115 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetDestinations(NULL,,%#zx)\n", sizeof(szBuf));
1116 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_DEST=%s\n", szBuf);
1117 }
1118 else
1119 {
1120 rc = DBGFR3LogModifyDestinations(pUVM, paArgs[0].u.pszString);
1121 if (RT_FAILURE(rc))
1122 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1123 }
1124 NOREF(pCmd);
1125 return VINF_SUCCESS;
1126}
1127
1128
1129/**
1130 * @callback_method_impl{FNDBGCCMD, The 'logflags' command.}
1131 */
1132static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1133{
1134 int rc;
1135 if (cArgs == 0)
1136 {
1137 char szBuf[_16K];
1138 rc = RTLogGetFlags(NULL, szBuf, sizeof(szBuf));
1139 if (RT_FAILURE(rc))
1140 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "RTLogGetFlags(NULL,,%#zx)\n", sizeof(szBuf));
1141 DBGCCmdHlpPrintf(pCmdHlp, "VBOX_LOG_FLAGS=%s\n", szBuf);
1142 }
1143 else
1144 {
1145 rc = DBGFR3LogModifyFlags(pUVM, paArgs[0].u.pszString);
1146 if (RT_FAILURE(rc))
1147 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pUVM, paArgs[0].u.pszString);
1148 }
1149
1150 NOREF(pCmd);
1151 return rc;
1152}
1153
1154
1155/**
1156 * @callback_method_impl{FNDBGCCMD, The 'logflush' command.}
1157 */
1158static DECLCALLBACK(int) dbgcCmdLogFlush(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1159{
1160 RT_NOREF3(pCmdHlp, pUVM, paArgs);
1161
1162 RTLogFlush(NULL);
1163 PRTLOGGER pLogRel = RTLogRelGetDefaultInstance();
1164 if (pLogRel)
1165 RTLogFlush(pLogRel);
1166
1167 NOREF(pCmd); NOREF(cArgs);
1168 return VINF_SUCCESS;
1169}
1170
1171
1172/**
1173 * @callback_method_impl{FNDBGCCMD, The 'format' command.}
1174 */
1175static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1176{
1177 LogFlow(("dbgcCmdFormat\n"));
1178 static const char *apszRangeDesc[] =
1179 {
1180 "none", "bytes", "elements"
1181 };
1182 int rc;
1183
1184 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1185 {
1186 switch (paArgs[iArg].enmType)
1187 {
1188 case DBGCVAR_TYPE_UNKNOWN:
1189 rc = DBGCCmdHlpPrintf(pCmdHlp,
1190 "Unknown variable type!\n");
1191 break;
1192 case DBGCVAR_TYPE_GC_FLAT:
1193 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1194 rc = DBGCCmdHlpPrintf(pCmdHlp,
1195 "Guest flat address: %%%08x range %lld %s\n",
1196 paArgs[iArg].u.GCFlat,
1197 paArgs[iArg].u64Range,
1198 apszRangeDesc[paArgs[iArg].enmRangeType]);
1199 else
1200 rc = DBGCCmdHlpPrintf(pCmdHlp,
1201 "Guest flat address: %%%08x\n",
1202 paArgs[iArg].u.GCFlat);
1203 break;
1204 case DBGCVAR_TYPE_GC_FAR:
1205 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1206 rc = DBGCCmdHlpPrintf(pCmdHlp,
1207 "Guest far address: %04x:%08x range %lld %s\n",
1208 paArgs[iArg].u.GCFar.sel,
1209 paArgs[iArg].u.GCFar.off,
1210 paArgs[iArg].u64Range,
1211 apszRangeDesc[paArgs[iArg].enmRangeType]);
1212 else
1213 rc = DBGCCmdHlpPrintf(pCmdHlp,
1214 "Guest far address: %04x:%08x\n",
1215 paArgs[iArg].u.GCFar.sel,
1216 paArgs[iArg].u.GCFar.off);
1217 break;
1218 case DBGCVAR_TYPE_GC_PHYS:
1219 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1220 rc = DBGCCmdHlpPrintf(pCmdHlp,
1221 "Guest physical address: %%%%%08x range %lld %s\n",
1222 paArgs[iArg].u.GCPhys,
1223 paArgs[iArg].u64Range,
1224 apszRangeDesc[paArgs[iArg].enmRangeType]);
1225 else
1226 rc = DBGCCmdHlpPrintf(pCmdHlp,
1227 "Guest physical address: %%%%%08x\n",
1228 paArgs[iArg].u.GCPhys);
1229 break;
1230 case DBGCVAR_TYPE_HC_FLAT:
1231 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1232 rc = DBGCCmdHlpPrintf(pCmdHlp,
1233 "Host flat address: %%%08x range %lld %s\n",
1234 paArgs[iArg].u.pvHCFlat,
1235 paArgs[iArg].u64Range,
1236 apszRangeDesc[paArgs[iArg].enmRangeType]);
1237 else
1238 rc = DBGCCmdHlpPrintf(pCmdHlp,
1239 "Host flat address: %%%08x\n",
1240 paArgs[iArg].u.pvHCFlat);
1241 break;
1242 case DBGCVAR_TYPE_HC_PHYS:
1243 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1244 rc = DBGCCmdHlpPrintf(pCmdHlp,
1245 "Host physical address: %RHp range %lld %s\n",
1246 paArgs[iArg].u.HCPhys,
1247 paArgs[iArg].u64Range,
1248 apszRangeDesc[paArgs[iArg].enmRangeType]);
1249 else
1250 rc = DBGCCmdHlpPrintf(pCmdHlp,
1251 "Host physical address: %RHp\n",
1252 paArgs[iArg].u.HCPhys);
1253 break;
1254
1255 case DBGCVAR_TYPE_STRING:
1256 rc = DBGCCmdHlpPrintf(pCmdHlp,
1257 "String, %lld bytes long: %s\n",
1258 paArgs[iArg].u64Range,
1259 paArgs[iArg].u.pszString);
1260 break;
1261
1262 case DBGCVAR_TYPE_SYMBOL:
1263 rc = DBGCCmdHlpPrintf(pCmdHlp,
1264 "Symbol, %lld bytes long: %s\n",
1265 paArgs[iArg].u64Range,
1266 paArgs[iArg].u.pszString);
1267 break;
1268
1269 case DBGCVAR_TYPE_NUMBER:
1270 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1271 rc = DBGCCmdHlpPrintf(pCmdHlp,
1272 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1273 paArgs[iArg].u.u64Number,
1274 paArgs[iArg].u.u64Number,
1275 paArgs[iArg].u.u64Number,
1276 paArgs[iArg].u64Range,
1277 apszRangeDesc[paArgs[iArg].enmRangeType]);
1278 else
1279 rc = DBGCCmdHlpPrintf(pCmdHlp,
1280 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1281 paArgs[iArg].u.u64Number,
1282 paArgs[iArg].u.u64Number,
1283 paArgs[iArg].u.u64Number);
1284 break;
1285
1286 default:
1287 rc = DBGCCmdHlpPrintf(pCmdHlp,
1288 "Invalid argument type %d\n",
1289 paArgs[iArg].enmType);
1290 break;
1291 }
1292 } /* arg loop */
1293
1294 NOREF(pCmd); NOREF(pUVM);
1295 return 0;
1296}
1297
1298
1299/**
1300 * @callback_method_impl{FNDBGCCMD, The 'loadimage' command.}
1301 */
1302static DECLCALLBACK(int) dbgcCmdLoadImage(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1303{
1304 /*
1305 * Validate the parsing and make sense of the input.
1306 * This is a mess as usual because we don't trust the parser yet.
1307 */
1308 AssertReturn( cArgs >= 2
1309 && cArgs <= 3
1310 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1311 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1312 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1313
1314 const char *pszFilename = paArgs[0].u.pszString;
1315
1316 DBGFADDRESS ModAddress;
1317 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1318 if (RT_FAILURE(rc))
1319 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1320
1321 const char *pszModName = NULL;
1322 if (cArgs >= 3)
1323 {
1324 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1325 pszModName = paArgs[2].u.pszString;
1326 }
1327
1328 /*
1329 * Determine the desired image arch from the load command used.
1330 */
1331 RTLDRARCH enmArch = RTLDRARCH_WHATEVER;
1332 if (pCmd->pszCmd[sizeof("loadimage") - 1] == '3')
1333 enmArch = RTLDRARCH_X86_32;
1334 else if (pCmd->pszCmd[sizeof("loadimage") - 1] == '6')
1335 enmArch = RTLDRARCH_AMD64;
1336
1337 /*
1338 * Try create a module for it.
1339 */
1340 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1341 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, enmArch, &ModAddress, NIL_RTDBGSEGIDX, 0 /*fFlags*/);
1342 if (RT_FAILURE(rc))
1343 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1344 pszFilename, pszModName, &paArgs[1]);
1345
1346 return VINF_SUCCESS;
1347}
1348
1349
1350/**
1351 * @callback_method_impl{FNDBGCCMD, The 'loadmap' command.}
1352 */
1353static DECLCALLBACK(int) dbgcCmdLoadMap(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1354{
1355 /*
1356 * Validate the parsing and make sense of the input.
1357 * This is a mess as usual because we don't trust the parser yet.
1358 */
1359 AssertReturn( cArgs >= 2
1360 && cArgs <= 5
1361 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1362 && DBGCVAR_ISPOINTER(paArgs[1].enmType),
1363 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1364
1365 const char *pszFilename = paArgs[0].u.pszString;
1366
1367 DBGFADDRESS ModAddress;
1368 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1369 if (RT_FAILURE(rc))
1370 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1371
1372 const char *pszModName = NULL;
1373 if (cArgs >= 3)
1374 {
1375 AssertReturn(paArgs[2].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1376 pszModName = paArgs[2].u.pszString;
1377 }
1378
1379 RTGCUINTPTR uSubtrahend = 0;
1380 if (cArgs >= 4)
1381 {
1382 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1383 uSubtrahend = paArgs[3].u.u64Number;
1384 }
1385
1386 RTDBGSEGIDX iModSeg = NIL_RTDBGSEGIDX;
1387 if (cArgs >= 5)
1388 {
1389 AssertReturn(paArgs[4].enmType == DBGCVAR_TYPE_NUMBER, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1390 iModSeg = (RTDBGSEGIDX)paArgs[4].u.u64Number;
1391 if ( iModSeg != paArgs[4].u.u64Number
1392 || iModSeg > RTDBGSEGIDX_LAST)
1393 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1394 }
1395
1396 /*
1397 * Try create a module for it.
1398 */
1399 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1400 rc = DBGFR3AsLoadMap(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, &ModAddress, NIL_RTDBGSEGIDX, uSubtrahend, 0 /*fFlags*/);
1401 if (RT_FAILURE(rc))
1402 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsLoadMap(,,'%s','%s',%Dv,)\n",
1403 pszFilename, pszModName, &paArgs[1]);
1404
1405 NOREF(pCmd);
1406 return VINF_SUCCESS;
1407}
1408
1409
1410/**
1411 * @callback_method_impl{FNDBGCCMD, The 'loadseg' command.}
1412 */
1413static DECLCALLBACK(int) dbgcCmdLoadSeg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1414{
1415 /*
1416 * Validate the parsing and make sense of the input.
1417 * This is a mess as usual because we don't trust the parser yet.
1418 */
1419 AssertReturn( cArgs >= 3
1420 && cArgs <= 4
1421 && paArgs[0].enmType == DBGCVAR_TYPE_STRING
1422 && DBGCVAR_ISPOINTER(paArgs[1].enmType)
1423 && paArgs[2].enmType == DBGCVAR_TYPE_NUMBER,
1424 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1425
1426 const char *pszFilename = paArgs[0].u.pszString;
1427
1428 DBGFADDRESS ModAddress;
1429 int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, &paArgs[1], &ModAddress);
1430 if (RT_FAILURE(rc))
1431 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "pfnVarToDbgfAddr: %Dv\n", &paArgs[1]);
1432
1433 RTDBGSEGIDX iModSeg = (RTDBGSEGIDX)paArgs[1].u.u64Number;
1434 if ( iModSeg != paArgs[2].u.u64Number
1435 || iModSeg > RTDBGSEGIDX_LAST)
1436 return DBGCCmdHlpPrintf(pCmdHlp, "Segment index out of range: %Dv; range={0..%#x}\n", &paArgs[1], RTDBGSEGIDX_LAST);
1437
1438 const char *pszModName = NULL;
1439 if (cArgs >= 4)
1440 {
1441 AssertReturn(paArgs[3].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1442 pszModName = paArgs[3].u.pszString;
1443 }
1444
1445 /*
1446 * Call the debug info manager about this loading.
1447 */
1448 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1449 rc = DBGFR3AsLoadImage(pUVM, pDbgc->hDbgAs, pszFilename, pszModName, RTLDRARCH_WHATEVER, &ModAddress, iModSeg, 0 /*fFlags*/);
1450 if (RT_FAILURE(rc))
1451 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3ModuleLoadImage(,,'%s','%s',%Dv,)\n",
1452 pszFilename, pszModName, &paArgs[1]);
1453
1454 NOREF(pCmd);
1455 return VINF_SUCCESS;
1456}
1457
1458
1459/**
1460 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1461 */
1462static DECLCALLBACK(int) dbgcCmdUnload(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1463{
1464 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1465
1466 /*
1467 * Validate the parsing and make sense of the input.
1468 * This is a mess as usual because we don't trust the parser yet.
1469 */
1470 AssertReturn( cArgs >= 1
1471 && paArgs[0].enmType == DBGCVAR_TYPE_STRING,
1472 VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1473 for (unsigned i = 0; i < cArgs; i++)
1474 {
1475 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_STRING, VERR_DBGC_PARSE_INCORRECT_ARG_TYPE);
1476
1477 int rc = DBGFR3AsUnlinkModuleByName(pUVM, pDbgc->hDbgAs, paArgs[i].u.pszString);
1478 if (RT_FAILURE(rc))
1479 return DBGCCmdHlpVBoxError(pCmdHlp, rc, "DBGFR3AsUnlinkModuleByName(,,'%s')\n", paArgs[i].u.pszString);
1480 }
1481
1482 NOREF(pCmd);
1483 return VINF_SUCCESS;
1484}
1485
1486
1487/**
1488 * @callback_method_impl{FNDBGCCMD, The 'set' command.}
1489 */
1490static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1491{
1492 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1493
1494 /* parse sanity check. */
1495 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1496 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1497 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1498
1499
1500 /*
1501 * A variable must start with an alpha chars and only contain alpha numerical chars.
1502 */
1503 const char *pszVar = paArgs[0].u.pszString;
1504 if (!RT_C_IS_ALPHA(*pszVar) || *pszVar == '_')
1505 return DBGCCmdHlpPrintf(pCmdHlp,
1506 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!",
1507 paArgs[0].u.pszString);
1508
1509 while (RT_C_IS_ALNUM(*pszVar) || *pszVar == '_')
1510 pszVar++;
1511 if (*pszVar)
1512 return DBGCCmdHlpPrintf(pCmdHlp,
1513 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!",
1514 paArgs[0].u.pszString);
1515
1516
1517 /*
1518 * Calc variable size.
1519 */
1520 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1521 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1522 cbVar += 1 + (size_t)paArgs[1].u64Range;
1523
1524 /*
1525 * Look for existing one.
1526 */
1527 pszVar = paArgs[0].u.pszString;
1528 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1529 {
1530 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1531 {
1532 /*
1533 * Update existing variable.
1534 */
1535 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1536 if (!pv)
1537 return VERR_DBGC_PARSE_NO_MEMORY;
1538 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1539
1540 pVar->Var = paArgs[1];
1541 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1542 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1543 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1544 return 0;
1545 }
1546 }
1547
1548 /*
1549 * Allocate another.
1550 */
1551 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1552
1553 pVar->Var = paArgs[1];
1554 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1555 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1556 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1557
1558 /* need to reallocate the pointer array too? */
1559 if (!(pDbgc->cVars % 0x20))
1560 {
1561 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1562 if (!pv)
1563 {
1564 RTMemFree(pVar);
1565 return VERR_DBGC_PARSE_NO_MEMORY;
1566 }
1567 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1568 }
1569 pDbgc->papVars[pDbgc->cVars++] = pVar;
1570
1571 NOREF(pCmd); NOREF(pUVM); NOREF(cArgs);
1572 return 0;
1573}
1574
1575
1576/**
1577 * @callback_method_impl{FNDBGCCMD, The 'unset' command.}
1578 */
1579static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1580{
1581 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1582 for (unsigned i = 0; i < cArgs; i++)
1583 AssertReturn(paArgs[i].enmType == DBGCVAR_TYPE_SYMBOL, VERR_DBGC_PARSE_BUG);
1584
1585 /*
1586 * Iterate the variables and unset them.
1587 */
1588 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1589 {
1590 const char *pszVar = paArgs[iArg].u.pszString;
1591
1592 /*
1593 * Look up the variable.
1594 */
1595 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1596 {
1597 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1598 {
1599 /*
1600 * Shuffle the array removing this entry.
1601 */
1602 void *pvFree = pDbgc->papVars[iVar];
1603 if (iVar + 1 < pDbgc->cVars)
1604 memmove(&pDbgc->papVars[iVar],
1605 &pDbgc->papVars[iVar + 1],
1606 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1607 pDbgc->papVars[--pDbgc->cVars] = NULL;
1608
1609 RTMemFree(pvFree);
1610 }
1611 } /* lookup */
1612 } /* arg loop */
1613
1614 NOREF(pCmd); NOREF(pUVM);
1615 return 0;
1616}
1617
1618
1619/**
1620 * @callback_method_impl{FNDBGCCMD, The 'loadvars' command.}
1621 */
1622static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1623{
1624 /*
1625 * Don't trust the parser.
1626 */
1627 if ( cArgs != 1
1628 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1629 {
1630 AssertMsgFailed(("Expected one string exactly!\n"));
1631 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1632 }
1633
1634 /*
1635 * Iterate the variables and unset them.
1636 */
1637 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1638 if (pFile)
1639 {
1640 char szLine[4096];
1641 while (fgets(szLine, sizeof(szLine), pFile))
1642 {
1643 /* Strip it. */
1644 char *psz = szLine;
1645 while (RT_C_IS_BLANK(*psz))
1646 psz++;
1647 int i = (int)strlen(psz) - 1;
1648 while (i >= 0 && RT_C_IS_SPACE(psz[i]))
1649 psz[i--] ='\0';
1650 /* Execute it if not comment or empty line. */
1651 if ( *psz != '\0'
1652 && *psz != '#'
1653 && *psz != ';')
1654 {
1655 DBGCCmdHlpPrintf(pCmdHlp, "dbg: set %s", psz);
1656 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1657 }
1658 }
1659 fclose(pFile);
1660 }
1661 else
1662 return DBGCCmdHlpPrintf(pCmdHlp, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1663
1664 NOREF(pCmd); NOREF(pUVM);
1665 return 0;
1666}
1667
1668
1669/**
1670 * @callback_method_impl{FNDBGCCMD, The 'showvars' command.}
1671 */
1672static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1673{
1674 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1675
1676 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1677 {
1678 int rc = DBGCCmdHlpPrintf(pCmdHlp, "%-20s ", &pDbgc->papVars[iVar]->szName);
1679 if (!rc)
1680 rc = dbgcCmdFormat(pCmd, pCmdHlp, pUVM, &pDbgc->papVars[iVar]->Var, 1);
1681 if (rc)
1682 return rc;
1683 }
1684
1685 NOREF(paArgs); NOREF(cArgs);
1686 return 0;
1687}
1688
1689
1690/**
1691 * @callback_method_impl{FNDBGCCMD, The 'loadplugin' command.}
1692 */
1693static DECLCALLBACK(int) dbgcCmdLoadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1694{
1695 RT_NOREF1(pUVM);
1696 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1697
1698 /*
1699 * Loop thru the plugin names.
1700 */
1701 for (unsigned i = 0; i < cArgs; i++)
1702 {
1703 char szPlugIn[128];
1704 RTERRINFOSTATIC ErrInfo;
1705 szPlugIn[0] = '\0';
1706 int rc = DBGFR3PlugInLoad(pDbgc->pUVM, paArgs[i].u.pszString, szPlugIn, sizeof(szPlugIn), RTErrInfoInitStatic(&ErrInfo));
1707 if (RT_SUCCESS(rc))
1708 DBGCCmdHlpPrintf(pCmdHlp, "Loaded plug-in '%s' (%s)\n", szPlugIn, paArgs[i].u.pszString);
1709 else if (rc == VERR_ALREADY_EXISTS)
1710 DBGCCmdHlpPrintf(pCmdHlp, "A plug-in named '%s' is already loaded\n", szPlugIn);
1711 else if (szPlugIn[0])
1712 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s' ('%s'): %s",
1713 szPlugIn, paArgs[i].u.pszString, ErrInfo.szMsg);
1714 else
1715 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInLoad failed for '%s': %s",
1716 paArgs[i].u.pszString, ErrInfo.szMsg);
1717 }
1718
1719 return VINF_SUCCESS;
1720}
1721
1722
1723/**
1724 * @callback_method_impl{FNDBGCCMD, The 'unload' command.}
1725 */
1726static DECLCALLBACK(int) dbgcCmdUnloadPlugIn(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1727{
1728 RT_NOREF1(pUVM);
1729 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1730
1731 /*
1732 * Loop thru the given plug-in names.
1733 */
1734 for (unsigned i = 0; i < cArgs; i++)
1735 {
1736 int rc = DBGFR3PlugInUnload(pDbgc->pUVM, paArgs[i].u.pszString);
1737 if (RT_SUCCESS(rc))
1738 DBGCCmdHlpPrintf(pCmdHlp, "Unloaded plug-in '%s'\n", paArgs[i].u.pszString);
1739 else if (rc == VERR_NOT_FOUND)
1740 return DBGCCmdHlpFail(pCmdHlp, pCmd, "'%s' was not found\n", paArgs[i].u.pszString);
1741 else
1742 return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "DBGFR3PlugInUnload failed for '%s'", paArgs[i].u.pszString);
1743 }
1744
1745 return VINF_SUCCESS;
1746}
1747
1748
1749/**
1750 * @callback_method_impl{FNDBGCCMD, The 'harakiri' command.}
1751 */
1752static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1753{
1754 Log(("dbgcCmdHarakiri\n"));
1755 for (;;)
1756 exit(126);
1757 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pUVM); NOREF(paArgs); NOREF(cArgs);
1758}
1759
1760
1761/**
1762 * @callback_method_impl{FNDBGCCMD, The 'writecore' command.}
1763 */
1764static DECLCALLBACK(int) dbgcCmdWriteCore(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)
1765{
1766 Log(("dbgcCmdWriteCore\n"));
1767
1768 /*
1769 * Validate input, lots of paranoia here.
1770 */
1771 if ( cArgs != 1
1772 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1773 {
1774 AssertMsgFailed(("Expected one string exactly!\n"));
1775 return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE;
1776 }
1777
1778 const char *pszDumpPath = paArgs[0].u.pszString;
1779 if (!pszDumpPath)
1780 return DBGCCmdHlpFail(pCmdHlp, pCmd, "Missing file path.\n");
1781
1782 int rc = DBGFR3CoreWrite(pUVM, pszDumpPath, true /*fReplaceFile*/);
1783 if (RT_FAILURE(rc))
1784 return DBGCCmdHlpFail(pCmdHlp, pCmd, "DBGFR3WriteCore failed. rc=%Rrc\n", rc);
1785
1786 return VINF_SUCCESS;
1787}
1788
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