VirtualBox

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

Last change on this file since 47281 was 47281, checked in by vboxsync, 11 years ago

Debugger: Added logflush. Made log, logflags, and logdest display the settings if no arguments are given.

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