VirtualBox

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

Last change on this file since 44399 was 44399, checked in by vboxsync, 12 years ago

DBGF,DBGC,++: PVM -> PUVM. Some refactoring and cleanup as well.

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