VirtualBox

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

Last change on this file since 55881 was 55881, checked in by vboxsync, 10 years ago

DBGF,DBGC: Moved the plug-ins from DBGC to DBGF so we can make use of them via IMachineDebugger.

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