VirtualBox

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

Last change on this file since 11725 was 8800, checked in by vboxsync, 17 years ago

Started digging into the solaris guest kernel. Added DBGFR3MemRead.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.3 KB
Line 
1/** $Id: DBGCCommands.cpp 8800 2008-05-14 03:03:54Z vboxsync $ */
2/** @file
3 * DBGC - Debugger Console, Native Commands.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22/*******************************************************************************
23* Header Files *
24*******************************************************************************/
25#define LOG_GROUP LOG_GROUP_DBGC
26#include <VBox/dbg.h>
27#include <VBox/dbgf.h>
28#include <VBox/vm.h>
29#include <VBox/vmm.h>
30#include <VBox/mm.h>
31#include <VBox/pgm.h>
32#include <VBox/selm.h>
33#include <VBox/dis.h>
34#include <VBox/param.h>
35#include <VBox/err.h>
36#include <VBox/log.h>
37
38#include <iprt/alloc.h>
39#include <iprt/alloca.h>
40#include <iprt/string.h>
41#include <iprt/assert.h>
42#include <iprt/ctype.h>
43
44#include <stdlib.h>
45#include <stdio.h>
46
47#include "DBGCInternal.h"
48
49
50/*******************************************************************************
51* Internal Functions *
52*******************************************************************************/
53static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
54static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
55static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
56static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
57static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
58static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
59static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
60static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
61static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
62static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
63static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
64static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
65static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
66static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
67static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
68static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
69static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
70
71
72/*******************************************************************************
73* Global Variables *
74*******************************************************************************/
75/** One argument of any kind. */
76static const DBGCVARDESC g_aArgAny[] =
77{
78 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
79 { 0, 1, DBGCVAR_CAT_ANY, 0, "var", "Any type of argument." },
80};
81
82/** Multiple string arguments (min 1). */
83static const DBGCVARDESC g_aArgMultiStr[] =
84{
85 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
86 { 1, ~0, DBGCVAR_CAT_STRING, 0, "strings", "One or more strings." },
87};
88
89/** Filename string. */
90static const DBGCVARDESC g_aArgFilename[] =
91{
92 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
93 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },
94};
95
96
97/** 'help' arguments. */
98static const DBGCVARDESC g_aArgHelp[] =
99{
100 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
101 { 0, ~0, DBGCVAR_CAT_STRING, 0, "cmd/op", "Zero or more command or operator names." },
102};
103
104
105/** 'info' arguments. */
106static const DBGCVARDESC g_aArgInfo[] =
107{
108 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
109 { 1, 1, DBGCVAR_CAT_STRING, 0, "info", "The name of the info to display." },
110 { 0, 1, DBGCVAR_CAT_STRING, 0, "args", "String arguments to the handler." },
111};
112
113
114/** loadsyms arguments. */
115static const DBGCVARDESC g_aArgLoadSyms[] =
116{
117 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
118 { 1, 1, DBGCVAR_CAT_STRING, 0, "path", "Filename string." },
119 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "delta", "Delta to add to the loaded symbols. (optional)" },
120 { 0, 1, DBGCVAR_CAT_STRING, 0, "module name", "Module name." },
121 { 0, 1, DBGCVAR_CAT_POINTER, DBGCVD_FLAGS_DEP_PREV, "module address", "Module address." },
122 { 0, 1, DBGCVAR_CAT_NUMBER, 0, "module size", "The module size. (optional)" },
123};
124
125
126/** log arguments. */
127static const DBGCVARDESC g_aArgLog[] =
128{
129 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
130 { 1, 1, DBGCVAR_CAT_STRING, 0, "groups", "Group modifier string (quote it!)." }
131};
132
133
134/** logdest arguments. */
135static const DBGCVARDESC g_aArgLogDest[] =
136{
137 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
138 { 1, 1, DBGCVAR_CAT_STRING, 0, "dests", "Destination modifier string (quote it!)." }
139};
140
141
142/** logflags arguments. */
143static const DBGCVARDESC g_aArgLogFlags[] =
144{
145 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
146 { 1, 1, DBGCVAR_CAT_STRING, 0, "flags", "Flag modifier string (quote it!)." }
147};
148
149
150/** 'set' arguments */
151static const DBGCVARDESC g_aArgSet[] =
152{
153 /* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
154 { 1, 1, DBGCVAR_CAT_STRING, 0, "var", "Variable name." },
155 { 1, 1, DBGCVAR_CAT_ANY, 0, "value", "Value to assign to the variable." },
156};
157
158
159
160
161
162/** Command descriptors for the basic commands. */
163const DBGCCMD g_aCmds[] =
164{
165 /* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
166 { "bye", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
167 { "echo", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdEcho, "<str1> [str2..[strN]]", "Displays the strings separated by one blank space and the last one followed by a newline." },
168 { "exit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
169 { "format", 1, 1, &g_aArgAny[0], ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },
170 { "detect", 0, 0, NULL, 0, NULL, 0, dbgcCmdDetect, "", "Detects or re-detects the guest os and starts the OS specific digger." },
171 { "harakiri", 0, 0, NULL, 0, NULL, 0, dbgcCmdHarakiri, "", "Kills debugger process." },
172 { "help", 0, ~0, &g_aArgHelp[0], ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'info help'." },
173 { "info", 1, 2, &g_aArgInfo[0], ELEMENTS(g_aArgInfo), NULL, 0, dbgcCmdInfo, "<info> [args]", "Display info register in the DBGF. For a list of info items try 'info help'." },
174 { "loadsyms", 1, 5, &g_aArgLoadSyms[0], ELEMENTS(g_aArgLoadSyms), NULL, 0, dbgcCmdLoadSyms, "<filename> [delta] [module] [module address]", "Loads symbols from a text file. Optionally giving a delta and a module." },
175 { "loadvars", 1, 1, &g_aArgFilename[0], ELEMENTS(g_aArgFilename), NULL, 0, dbgcCmdLoadVars, "<filename>", "Load variables from file. One per line, same as the args to the set command." },
176 { "log", 1, 1, &g_aArgLog[0], ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },
177 { "logdest", 1, 1, &g_aArgLogDest[0], ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },
178 { "logflags", 1, 1, &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags), NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },
179 { "quit", 0, 0, NULL, 0, NULL, 0, dbgcCmdQuit, "", "Exits the debugger." },
180 { "runscript", 1, 1, &g_aArgFilename[0], ELEMENTS(g_aArgFilename), NULL, 0, dbgcCmdRunScript, "<filename>", "Runs the command listed in the script. Lines starting with '#' (after removing blanks) are comment. blank lines are ignored. Stops on failure." },
181 { "set", 2, 2, &g_aArgSet[0], ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },
182 { "showvars", 0, 0, NULL, 0, NULL, 0, dbgcCmdShowVars, "", "List all the defined variables." },
183 { "stop", 0, 0, NULL, 0, NULL, 0, dbgcCmdStop, "", "Stop execution." },
184 { "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
185};
186
187/** The number of native commands. */
188const unsigned g_cCmds = RT_ELEMENTS(g_aCmds);
189
190
191/**
192 * Pointer to head of the list of external commands.
193 */
194static PDBGCEXTCMDS g_pExtCmdsHead; /** @todo rw protect g_pExtCmdsHead! */
195/** Locks the g_pExtCmdsHead list for reading. */
196#define DBGCEXTCMDS_LOCK_RD() do { } while (0)
197/** Locks the g_pExtCmdsHead list for writing. */
198#define DBGCEXTCMDS_LOCK_WR() do { } while (0)
199/** UnLocks the g_pExtCmdsHead list after reading. */
200#define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)
201/** UnLocks the g_pExtCmdsHead list after writing. */
202#define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)
203
204
205
206
207/**
208 * Finds a routine.
209 *
210 * @returns Pointer to the command descriptor.
211 * If the request was for an external command, the caller is responsible for
212 * unlocking the external command list.
213 * @returns NULL if not found.
214 * @param pDbgc The debug console instance.
215 * @param pachName Pointer to the routine string (not terminated).
216 * @param cchName Length of the routine name.
217 * @param fExternal Whether or not the routine is external.
218 */
219PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
220{
221 if (!fExternal)
222 {
223 /* emulation first, so commands can be overloaded (info ++). */
224 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
225 unsigned cLeft = pDbgc->cEmulationCmds;
226 while (cLeft-- > 0)
227 {
228 if ( !strncmp(pachName, pCmd->pszCmd, cchName)
229 && !pCmd->pszCmd[cchName])
230 return pCmd;
231 pCmd++;
232 }
233
234 for (unsigned iCmd = 0; iCmd < ELEMENTS(g_aCmds); iCmd++)
235 {
236 if ( !strncmp(pachName, g_aCmds[iCmd].pszCmd, cchName)
237 && !g_aCmds[iCmd].pszCmd[cchName])
238 return &g_aCmds[iCmd];
239 }
240 }
241 else
242 {
243 DBGCEXTCMDS_LOCK_RD();
244 for (PDBGCEXTCMDS pExtCmds = g_pExtCmdsHead; pExtCmds; pExtCmds = pExtCmds->pNext)
245 {
246 for (unsigned iCmd = 0; iCmd < pExtCmds->cCmds; iCmd++)
247 {
248 if ( !strncmp(pachName, pExtCmds->paCmds[iCmd].pszCmd, cchName)
249 && !pExtCmds->paCmds[iCmd].pszCmd[cchName])
250 return &pExtCmds->paCmds[iCmd];
251 }
252 }
253 DBGCEXTCMDS_UNLOCK_RD();
254 }
255
256 NOREF(pDbgc);
257 return NULL;
258}
259
260
261/**
262 * Register one or more external commands.
263 *
264 * @returns VBox status.
265 * @param paCommands Pointer to an array of command descriptors.
266 * The commands must be unique. It's not possible
267 * to register the same commands more than once.
268 * @param cCommands Number of commands.
269 */
270DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
271{
272 /*
273 * Lock the list.
274 */
275 DBGCEXTCMDS_LOCK_WR();
276 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
277 while (pCur)
278 {
279 if (paCommands == pCur->paCmds)
280 {
281 DBGCEXTCMDS_UNLOCK_WR();
282 AssertMsgFailed(("Attempt at re-registering %d command(s)!\n", cCommands));
283 return VWRN_DBGC_ALREADY_REGISTERED;
284 }
285 pCur = pCur->pNext;
286 }
287
288 /*
289 * Allocate new chunk.
290 */
291 int rc = 0;
292 pCur = (PDBGCEXTCMDS)RTMemAlloc(sizeof(*pCur));
293 if (pCur)
294 {
295 pCur->cCmds = cCommands;
296 pCur->paCmds = paCommands;
297 pCur->pNext = g_pExtCmdsHead;
298 g_pExtCmdsHead = pCur;
299 }
300 else
301 rc = VERR_NO_MEMORY;
302 DBGCEXTCMDS_UNLOCK_WR();
303
304 return rc;
305}
306
307
308/**
309 * Deregister one or more external commands previously registered by
310 * DBGCRegisterCommands().
311 *
312 * @returns VBox status.
313 * @param paCommands Pointer to an array of command descriptors
314 * as given to DBGCRegisterCommands().
315 * @param cCommands Number of commands.
316 */
317DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands)
318{
319 /*
320 * Lock the list.
321 */
322 DBGCEXTCMDS_LOCK_WR();
323 PDBGCEXTCMDS pPrev = NULL;
324 PDBGCEXTCMDS pCur = g_pExtCmdsHead;
325 while (pCur)
326 {
327 if (paCommands == pCur->paCmds)
328 {
329 if (pPrev)
330 pPrev->pNext = pCur->pNext;
331 else
332 g_pExtCmdsHead = pCur->pNext;
333 DBGCEXTCMDS_UNLOCK_WR();
334
335 RTMemFree(pCur);
336 return VINF_SUCCESS;
337 }
338 pPrev = pCur;
339 pCur = pCur->pNext;
340 }
341 DBGCEXTCMDS_UNLOCK_WR();
342
343 NOREF(cCommands);
344 return VERR_DBGC_COMMANDS_NOT_REGISTERED;
345}
346
347
348
349
350/**
351 * Prints full command help.
352 */
353static int dbgcPrintHelp(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, bool fExternal)
354{
355 int rc;
356
357 /* the command */
358 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
359 "%s%-*s %-30s %s",
360 fExternal ? "." : "",
361 fExternal ? 10 : 11,
362 pCmd->pszCmd,
363 pCmd->pszSyntax,
364 pCmd->pszDescription);
365 if (!pCmd->cArgsMin && pCmd->cArgsMin == pCmd->cArgsMax)
366 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <no args>\n");
367 else if (pCmd->cArgsMin == pCmd->cArgsMax)
368 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u args>\n", pCmd->cArgsMin);
369 else if (pCmd->cArgsMax == ~0U)
370 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+ args>\n", pCmd->cArgsMin);
371 else
372 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u to %u args>\n", pCmd->cArgsMin, pCmd->cArgsMax);
373
374 /* argument descriptions. */
375 for (unsigned i = 0; i < pCmd->cArgDescs; i++)
376 {
377 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
378 " %-12s %s",
379 pCmd->paArgDescs[i].pszName,
380 pCmd->paArgDescs[i].pszDescription);
381 if (!pCmd->paArgDescs[i].cTimesMin)
382 {
383 if (pCmd->paArgDescs[i].cTimesMax == ~0U)
384 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional+>\n");
385 else
386 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <optional-%u>\n", pCmd->paArgDescs[i].cTimesMax);
387 }
388 else
389 {
390 if (pCmd->paArgDescs[i].cTimesMax == ~0U)
391 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u+>\n", pCmd->paArgDescs[i].cTimesMin);
392 else
393 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
394 }
395 }
396 return rc;
397}
398
399
400/**
401 * The 'help' command.
402 *
403 * @returns VBox status.
404 * @param pCmd Pointer to the command descriptor (as registered).
405 * @param pCmdHlp Pointer to command helper functions.
406 * @param pVM Pointer to the current VM (if any).
407 * @param paArgs Pointer to (readonly) array of arguments.
408 * @param cArgs Number of arguments in the array.
409 */
410static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
411{
412 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
413 int rc = VINF_SUCCESS;
414 unsigned i;
415
416 if (!cArgs)
417 {
418 /*
419 * All the stuff.
420 */
421 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
422 "VirtualBox Debugger\n"
423 "-------------------\n"
424 "\n"
425 "Commands and Functions:\n");
426 for (i = 0; i < ELEMENTS(g_aCmds); i++)
427 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
428 "%-11s %-30s %s\n",
429 g_aCmds[i].pszCmd,
430 g_aCmds[i].pszSyntax,
431 g_aCmds[i].pszDescription);
432 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
433 "\n"
434 "Emulation: %s\n", pDbgc->pszEmulation);
435 PCDBGCCMD pCmd = pDbgc->paEmulationCmds;
436 for (i = 0; i < pDbgc->cEmulationCmds; i++, pCmd++)
437 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
438 "%-11s %-30s %s\n",
439 pCmd->pszCmd,
440 pCmd->pszSyntax,
441 pCmd->pszDescription);
442
443 if (g_pExtCmdsHead)
444 {
445 DBGCEXTCMDS_LOCK_RD();
446 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
447 "\n"
448 "External Commands and Functions:\n");
449 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
450 for (i = 0; i < pExtCmd->cCmds; i++)
451 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
452 ".%-10s %-30s %s\n",
453 pExtCmd->paCmds[i].pszCmd,
454 pExtCmd->paCmds[i].pszSyntax,
455 pExtCmd->paCmds[i].pszDescription);
456 DBGCEXTCMDS_UNLOCK_RD();
457 }
458
459 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
460 "\n"
461 "Operators:\n");
462 unsigned iPrecedence = 0;
463 unsigned cLeft = g_cOps;
464 while (cLeft > 0)
465 {
466 for (i = 0; i < g_cOps; i++)
467 if (g_aOps[i].iPrecedence == iPrecedence)
468 {
469 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
470 "%-10s %s %s\n",
471 g_aOps[i].szName,
472 g_aOps[i].fBinary ? "Binary" : "Unary ",
473 g_aOps[i].pszDescription);
474 cLeft--;
475 }
476 iPrecedence++;
477 }
478 }
479 else
480 {
481 /*
482 * Search for the arguments (strings).
483 */
484 for (unsigned iArg = 0; iArg < cArgs; iArg++)
485 {
486 Assert(paArgs[iArg].enmType == DBGCVAR_TYPE_STRING);
487 bool fFound = false;
488
489 /* lookup in the emulation command list first */
490 for (i = 0; i < pDbgc->cEmulationCmds; i++)
491 if (!strcmp(pDbgc->paEmulationCmds[i].pszCmd, paArgs[iArg].u.pszString))
492 {
493 rc = dbgcPrintHelp(pCmdHlp, &pDbgc->paEmulationCmds[i], false);
494 fFound = true;
495 break;
496 }
497
498 /* lookup in the command list (even when found in the emulation) */
499 for (i = 0; i < ELEMENTS(g_aCmds); i++)
500 if (!strcmp(g_aCmds[i].pszCmd, paArgs[iArg].u.pszString))
501 {
502 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], false);
503 fFound = true;
504 break;
505 }
506
507 /* external commands */
508 if ( !fFound
509 && g_pExtCmdsHead
510 && paArgs[iArg].u.pszString[0] == '.')
511 {
512 DBGCEXTCMDS_LOCK_RD();
513 for (PDBGCEXTCMDS pExtCmd = g_pExtCmdsHead; pExtCmd; pExtCmd = pExtCmd->pNext)
514 for (i = 0; i < pExtCmd->cCmds; i++)
515 if (!strcmp(pExtCmd->paCmds[i].pszCmd, paArgs[iArg].u.pszString + 1))
516 {
517 rc = dbgcPrintHelp(pCmdHlp, &g_aCmds[i], true);
518 fFound = true;
519 break;
520 }
521 DBGCEXTCMDS_UNLOCK_RD();
522 }
523
524 /* operators */
525 if (!fFound && strlen(paArgs[iArg].u.pszString) < sizeof(g_aOps[i].szName))
526 {
527 for (i = 0; i < g_cOps; i++)
528 if (!strcmp(g_aOps[i].szName, paArgs[iArg].u.pszString))
529 {
530 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
531 "%-10s %s %s\n",
532 g_aOps[i].szName,
533 g_aOps[i].fBinary ? "Binary" : "Unary ",
534 g_aOps[i].pszDescription);
535 fFound = true;
536 break;
537 }
538 }
539
540 /* found? */
541 if (!fFound)
542 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
543 "error: '%s' was not found!\n",
544 paArgs[iArg].u.pszString);
545 } /* foreach argument */
546 }
547
548 NOREF(pCmd);
549 NOREF(pVM);
550 NOREF(pResult);
551 return rc;
552}
553
554
555/**
556 * The 'quit', 'exit' and 'bye' commands.
557 *
558 * @returns VBox status.
559 * @param pCmd Pointer to the command descriptor (as registered).
560 * @param pCmdHlp Pointer to command helper functions.
561 * @param pVM Pointer to the current VM (if any).
562 * @param paArgs Pointer to (readonly) array of arguments.
563 * @param cArgs Number of arguments in the array.
564 */
565static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
566{
567 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Quitting console...\n");
568 NOREF(pCmd);
569 NOREF(pVM);
570 NOREF(paArgs);
571 NOREF(cArgs);
572 NOREF(pResult);
573 return VERR_DBGC_QUIT;
574}
575
576
577/**
578 * The 'stop' command.
579 *
580 * @returns VBox status.
581 * @param pCmd Pointer to the command descriptor (as registered).
582 * @param pCmdHlp Pointer to command helper functions.
583 * @param pVM Pointer to the current VM (if any).
584 * @param paArgs Pointer to (readonly) array of arguments.
585 * @param cArgs Number of arguments in the array.
586 */
587static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
588{
589 /*
590 * Check if the VM is halted or not before trying to halt it.
591 */
592 int rc;
593 if (DBGFR3IsHalted(pVM))
594 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "warning: The VM is already halted...\n");
595 else
596 {
597 rc = DBGFR3Halt(pVM);
598 if (VBOX_SUCCESS(rc))
599 rc = VWRN_DBGC_CMD_PENDING;
600 else
601 rc = pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3Halt().");
602 }
603
604 NOREF(pCmd); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
605 return rc;
606}
607
608
609/**
610 * The 'echo' command.
611 *
612 * @returns VBox status.
613 * @param pCmd Pointer to the command descriptor (as registered).
614 * @param pCmdHlp Pointer to command helper functions.
615 * @param pVM Pointer to the current VM (if any).
616 * @param paArgs Pointer to (readonly) array of arguments.
617 * @param cArgs Number of arguments in the array.
618 */
619static DECLCALLBACK(int) dbgcCmdEcho(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
620{
621 /*
622 * Loop thru the arguments and print them with one space between.
623 */
624 int rc = 0;
625 for (unsigned i = 0; i < cArgs; i++)
626 {
627 if (paArgs[i].enmType == DBGCVAR_TYPE_STRING)
628 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " %s" : "%s", paArgs[i].u.pszString);
629 else
630 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, i ? " <parser error>" : "<parser error>");
631 if (VBOX_FAILURE(rc))
632 return rc;
633 }
634 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
635 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "\n");
636}
637
638
639/**
640 * The 'runscript' command.
641 *
642 * @returns VBox status.
643 * @param pCmd Pointer to the command descriptor (as registered).
644 * @param pCmdHlp Pointer to command helper functions.
645 * @param pVM Pointer to the current VM (if any).
646 * @param paArgs Pointer to (readonly) array of arguments.
647 * @param cArgs Number of arguments in the array.
648 */
649static DECLCALLBACK(int) dbgcCmdRunScript(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
650{
651 /* check that the parser did what it's supposed to do. */
652 if ( cArgs != 1
653 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
654 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
655
656 /*
657 * Try open the script.
658 */
659 const char *pszFilename = paArgs[0].u.pszString;
660 FILE *pFile = fopen(pszFilename, "r");
661 if (!pFile)
662 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open '%s'.\n", pszFilename);
663
664 /*
665 * Execute it line by line.
666 */
667 int rc = 0;
668 unsigned iLine = 0;
669 char szLine[8192];
670 while (fgets(szLine, sizeof(szLine), pFile))
671 {
672 /* check that the line isn't too long. */
673 char *pszEnd = strchr(szLine, '\0');
674 if (pszEnd == &szLine[sizeof(szLine) - 1])
675 {
676 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long\n", iLine);
677 break;
678 }
679 iLine++;
680
681 /* strip leading blanks and check for comment / blank line. */
682 char *psz = RTStrStripL(szLine);
683 if ( *psz == '\0'
684 || *psz == '\n'
685 || *psz == '#')
686 continue;
687
688 /* strip trailing blanks and check for empty line (\r case). */
689 while ( pszEnd > psz
690 && isspace(pszEnd[-1])) /* isspace includes \n and \r normally. */
691 *--pszEnd = '\0';
692
693 /** @todo check for Control-C / Cancel at this point... */
694
695 /*
696 * Execute the command.
697 *
698 * This is a bit wasteful with scratch space btw., can fix it later.
699 * The whole return code crap should be fixed too, so that it's possible
700 * to know whether a command succeeded (VBOX_SUCCESS()) or failed, and
701 * more importantly why it failed.
702 */
703 rc = pCmdHlp->pfnExec(pCmdHlp, "%s", psz);
704 if (VBOX_FAILURE(rc))
705 {
706 if (rc == VERR_BUFFER_OVERFLOW)
707 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: Line #%u is too long (exec overflowed)\n", iLine);
708 break;
709 }
710 if (rc == VWRN_DBGC_CMD_PENDING)
711 {
712 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "runscript error: VWRN_DBGC_CMD_PENDING on line #%u, script terminated\n", iLine);
713 break;
714 }
715 }
716
717 fclose(pFile);
718
719 NOREF(pCmd); NOREF(pResult); NOREF(pVM);
720 return rc;
721}
722
723
724/**
725 * The 'detect' command.
726 *
727 * @returns VBox status.
728 * @param pCmd Pointer to the command descriptor (as registered).
729 * @param pCmdHlp Pointer to command helper functions.
730 * @param pVM Pointer to the current VM (if any).
731 * @param paArgs Pointer to (readonly) array of arguments.
732 * @param cArgs Number of arguments in the array.
733 */
734static DECLCALLBACK(int) dbgcCmdDetect(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
735{
736 /* check that the parser did what it's supposed to do. */
737 if (cArgs != 0)
738 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "parser error\n");
739
740 /*
741 * Perform the detection.
742 */
743 char szName[64];
744 int rc = DBGFR3OSDetect(pVM, szName, sizeof(szName));
745 if (RT_FAILURE(rc))
746 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Executing DBGFR3OSDetect().");
747 if (rc == VINF_SUCCESS)
748 {
749 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Guest OS: %s\n", szName);
750 char szVersion[64];
751 int rc2 = DBGFR3OSQueryNameAndVersion(pVM, NULL, 0, szVersion, sizeof(szVersion));
752 if (RT_SUCCESS(rc2))
753 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Version : %s\n", szVersion);
754 }
755 else
756 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Unable to figure out which guest OS it is, sorry.\n");
757 NOREF(pCmd); NOREF(pResult); NOREF(paArgs);
758 return rc;
759}
760
761
762/**
763 * Print formatted string.
764 *
765 * @param pHlp Pointer to this structure.
766 * @param pszFormat The format string.
767 * @param ... Arguments.
768 */
769static DECLCALLBACK(void) dbgcCmdInfo_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
770{
771 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
772 va_list args;
773 va_start(args, pszFormat);
774 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
775 va_end(args);
776}
777
778
779/**
780 * Print formatted string.
781 *
782 * @param pHlp Pointer to this structure.
783 * @param pszFormat The format string.
784 * @param args Argument list.
785 */
786static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
787{
788 PDBGCCMDHLP pCmdHlp = *(PDBGCCMDHLP *)(pHlp + 1);
789 pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, args);
790}
791
792
793/**
794 * The 'info' command.
795 *
796 * @returns VBox status.
797 * @param pCmd Pointer to the command descriptor (as registered).
798 * @param pCmdHlp Pointer to command helper functions.
799 * @param pVM Pointer to the current VM (if any).
800 * @param paArgs Pointer to (readonly) array of arguments.
801 * @param cArgs Number of arguments in the array.
802 */
803static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
804{
805 /*
806 * Validate input.
807 */
808 if ( cArgs < 1
809 || cArgs > 2
810 || paArgs[0].enmType != DBGCVAR_TYPE_STRING
811 || paArgs[cArgs - 1].enmType != DBGCVAR_TYPE_STRING)
812 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
813 if (!pVM)
814 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: No VM.\n");
815
816 /*
817 * Dump it.
818 */
819 struct
820 {
821 DBGFINFOHLP Hlp;
822 PDBGCCMDHLP pCmdHlp;
823 } Hlp = { { dbgcCmdInfo_Printf, dbgcCmdInfo_PrintfV }, pCmdHlp };
824 int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
825 if (VBOX_FAILURE(rc))
826 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3Info()\n");
827
828 NOREF(pCmd); NOREF(pResult);
829 return 0;
830}
831
832
833/**
834 * The 'log' command.
835 *
836 * @returns VBox status.
837 * @param pCmd Pointer to the command descriptor (as registered).
838 * @param pCmdHlp Pointer to command helper functions.
839 * @param pVM Pointer to the current VM (if any).
840 * @param paArgs Pointer to (readonly) array of arguments.
841 * @param cArgs Number of arguments in the array.
842 */
843static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
844{
845 int rc = DBGFR3LogModifyGroups(pVM, paArgs[0].u.pszString);
846 if (VBOX_SUCCESS(rc))
847 return VINF_SUCCESS;
848 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
849 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
850}
851
852
853/**
854 * The 'logdest' command.
855 *
856 * @returns VBox status.
857 * @param pCmd Pointer to the command descriptor (as registered).
858 * @param pCmdHlp Pointer to command helper functions.
859 * @param pVM Pointer to the current VM (if any).
860 * @param paArgs Pointer to (readonly) array of arguments.
861 * @param cArgs Number of arguments in the array.
862 */
863static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
864{
865 int rc = DBGFR3LogModifyDestinations(pVM, paArgs[0].u.pszString);
866 if (VBOX_SUCCESS(rc))
867 return VINF_SUCCESS;
868 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
869 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
870}
871
872
873/**
874 * The 'logflags' command.
875 *
876 * @returns VBox status.
877 * @param pCmd Pointer to the command descriptor (as registered).
878 * @param pCmdHlp Pointer to command helper functions.
879 * @param pVM Pointer to the current VM (if any).
880 * @param paArgs Pointer to (readonly) array of arguments.
881 * @param cArgs Number of arguments in the array.
882 */
883static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
884{
885 int rc = DBGFR3LogModifyFlags(pVM, paArgs[0].u.pszString);
886 if (VBOX_SUCCESS(rc))
887 return VINF_SUCCESS;
888 NOREF(pCmd); NOREF(cArgs); NOREF(pResult);
889 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
890}
891
892
893/**
894 * The 'format' command.
895 *
896 * @returns VBox status.
897 * @param pCmd Pointer to the command descriptor (as registered).
898 * @param pCmdHlp Pointer to command helper functions.
899 * @param pVM Pointer to the current VM (if any).
900 * @param paArgs Pointer to (readonly) array of arguments.
901 * @param cArgs Number of arguments in the array.
902 */
903static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
904{
905 LogFlow(("dbgcCmdFormat\n"));
906 static const char *apszRangeDesc[] =
907 {
908 "none", "bytes", "elements"
909 };
910 int rc;
911
912 for (unsigned iArg = 0; iArg < cArgs; iArg++)
913 {
914 switch (paArgs[iArg].enmType)
915 {
916 case DBGCVAR_TYPE_UNKNOWN:
917 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
918 "Unknown variable type!\n");
919 break;
920 case DBGCVAR_TYPE_GC_FLAT:
921 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
922 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
923 "Guest flat address: %%%08x range %lld %s\n",
924 paArgs[iArg].u.GCFlat,
925 paArgs[iArg].u64Range,
926 apszRangeDesc[paArgs[iArg].enmRangeType]);
927 else
928 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
929 "Guest flat address: %%%08x\n",
930 paArgs[iArg].u.GCFlat);
931 break;
932 case DBGCVAR_TYPE_GC_FAR:
933 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
934 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
935 "Guest far address: %04x:%08x range %lld %s\n",
936 paArgs[iArg].u.GCFar.sel,
937 paArgs[iArg].u.GCFar.off,
938 paArgs[iArg].u64Range,
939 apszRangeDesc[paArgs[iArg].enmRangeType]);
940 else
941 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
942 "Guest far address: %04x:%08x\n",
943 paArgs[iArg].u.GCFar.sel,
944 paArgs[iArg].u.GCFar.off);
945 break;
946 case DBGCVAR_TYPE_GC_PHYS:
947 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
948 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
949 "Guest physical address: %%%%%08x range %lld %s\n",
950 paArgs[iArg].u.GCPhys,
951 paArgs[iArg].u64Range,
952 apszRangeDesc[paArgs[iArg].enmRangeType]);
953 else
954 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
955 "Guest physical address: %%%%%08x\n",
956 paArgs[iArg].u.GCPhys);
957 break;
958 case DBGCVAR_TYPE_HC_FLAT:
959 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
960 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
961 "Host flat address: %%%08x range %lld %s\n",
962 paArgs[iArg].u.pvHCFlat,
963 paArgs[iArg].u64Range,
964 apszRangeDesc[paArgs[iArg].enmRangeType]);
965 else
966 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
967 "Host flat address: %%%08x\n",
968 paArgs[iArg].u.pvHCFlat);
969 break;
970 case DBGCVAR_TYPE_HC_FAR:
971 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
972 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
973 "Host far address: %04x:%08x range %lld %s\n",
974 paArgs[iArg].u.HCFar.sel,
975 paArgs[iArg].u.HCFar.off,
976 paArgs[iArg].u64Range,
977 apszRangeDesc[paArgs[iArg].enmRangeType]);
978 else
979 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
980 "Host far address: %04x:%08x\n",
981 paArgs[iArg].u.HCFar.sel,
982 paArgs[iArg].u.HCFar.off);
983 break;
984 case DBGCVAR_TYPE_HC_PHYS:
985 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
986 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
987 "Host physical address: %VHp range %lld %s\n",
988 paArgs[iArg].u.HCPhys,
989 paArgs[iArg].u64Range,
990 apszRangeDesc[paArgs[iArg].enmRangeType]);
991 else
992 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
993 "Host physical address: %VHp\n",
994 paArgs[iArg].u.HCPhys);
995 break;
996
997 case DBGCVAR_TYPE_STRING:
998 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
999 "String, %lld bytes long: %s\n",
1000 paArgs[iArg].u64Range,
1001 paArgs[iArg].u.pszString);
1002 break;
1003
1004 case DBGCVAR_TYPE_NUMBER:
1005 if (paArgs[iArg].enmRangeType != DBGCVAR_RANGE_NONE)
1006 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1007 "Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
1008 paArgs[iArg].u.u64Number,
1009 paArgs[iArg].u.u64Number,
1010 paArgs[iArg].u.u64Number,
1011 paArgs[iArg].u64Range,
1012 apszRangeDesc[paArgs[iArg].enmRangeType]);
1013 else
1014 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1015 "Number: hex %llx dec 0i%lld oct 0t%llo\n",
1016 paArgs[iArg].u.u64Number,
1017 paArgs[iArg].u.u64Number,
1018 paArgs[iArg].u.u64Number);
1019 break;
1020
1021 default:
1022 rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1023 "Invalid argument type %d\n",
1024 paArgs[iArg].enmType);
1025 break;
1026 }
1027 } /* arg loop */
1028
1029 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1030 return 0;
1031}
1032
1033
1034/**
1035 * The 'loadsyms' command.
1036 *
1037 * @returns VBox status.
1038 * @param pCmd Pointer to the command descriptor (as registered).
1039 * @param pCmdHlp Pointer to command helper functions.
1040 * @param pVM Pointer to the current VM (if any).
1041 * @param paArgs Pointer to (readonly) array of arguments.
1042 * @param cArgs Number of arguments in the array.
1043 */
1044static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1045{
1046 /*
1047 * Validate the parsing and make sense of the input.
1048 * This is a mess as usual because we don't trust the parser yet.
1049 */
1050 if ( cArgs < 1
1051 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1052 {
1053 AssertMsgFailed(("Parse error, first argument required to be string!\n"));
1054 return VERR_PARSE_INCORRECT_ARG_TYPE;
1055 }
1056 DBGCVAR AddrVar;
1057 RTGCUINTPTR Delta = 0;
1058 const char *pszModule = NULL;
1059 RTGCUINTPTR ModuleAddress = 0;
1060 unsigned cbModule = 0;
1061 if (cArgs > 1)
1062 {
1063 unsigned iArg = 1;
1064 if (paArgs[iArg].enmType == DBGCVAR_TYPE_NUMBER)
1065 {
1066 Delta = (RTGCUINTPTR)paArgs[iArg].u.u64Number;
1067 iArg++;
1068 }
1069 if (iArg < cArgs)
1070 {
1071 if (paArgs[iArg].enmType != DBGCVAR_TYPE_STRING)
1072 {
1073 AssertMsgFailed(("Parse error, module argument required to be string!\n"));
1074 return VERR_PARSE_INCORRECT_ARG_TYPE;
1075 }
1076 pszModule = paArgs[iArg].u.pszString;
1077 iArg++;
1078 if (iArg < cArgs)
1079 {
1080 if (DBGCVAR_ISPOINTER(paArgs[iArg].enmType))
1081 {
1082 AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
1083 return VERR_PARSE_INCORRECT_ARG_TYPE;
1084 }
1085 int rc = pCmdHlp->pfnEval(pCmdHlp, &AddrVar, "%%(%Dv)", &paArgs[iArg]);
1086 if (VBOX_FAILURE(rc))
1087 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "Module address cast %%(%Dv) failed.", &paArgs[iArg]);
1088 ModuleAddress = paArgs[iArg].u.GCFlat;
1089 iArg++;
1090 if (iArg < cArgs)
1091 {
1092 if (paArgs[iArg].enmType != DBGCVAR_TYPE_NUMBER)
1093 {
1094 AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
1095 return VERR_PARSE_INCORRECT_ARG_TYPE;
1096 }
1097 cbModule = (unsigned)paArgs[iArg].u.u64Number;
1098 iArg++;
1099 if (iArg < cArgs)
1100 {
1101 AssertMsgFailed(("Parse error, too many arguments!\n"));
1102 return VERR_PARSE_TOO_MANY_ARGUMENTS;
1103 }
1104 }
1105 }
1106 }
1107 }
1108
1109 /*
1110 * Call the debug info manager about this loading...
1111 */
1112 int rc = DBGFR3ModuleLoad(pVM, paArgs[0].u.pszString, Delta, pszModule, ModuleAddress, cbModule);
1113 if (VBOX_FAILURE(rc))
1114 return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGInfoSymbolLoad(, '%s', %VGv, '%s', %VGv, 0)\n",
1115 paArgs[0].u.pszString, Delta, pszModule, ModuleAddress);
1116
1117 NOREF(pCmd); NOREF(pResult);
1118 return VINF_SUCCESS;
1119}
1120
1121
1122/**
1123 * The 'set' command.
1124 *
1125 * @returns VBox status.
1126 * @param pCmd Pointer to the command descriptor (as registered).
1127 * @param pCmdHlp Pointer to command helper functions.
1128 * @param pVM Pointer to the current VM (if any).
1129 * @param paArgs Pointer to (readonly) array of arguments.
1130 * @param cArgs Number of arguments in the array.
1131 */
1132static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1133{
1134 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1135
1136 /* parse sanity check. */
1137 AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
1138 if (paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1139 return VERR_PARSE_INCORRECT_ARG_TYPE;
1140
1141
1142 /*
1143 * A variable must start with an alpha chars and only contain alpha numerical chars.
1144 */
1145 const char *pszVar = paArgs[0].u.pszString;
1146 if (!isalpha(*pszVar) || *pszVar == '_')
1147 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1148 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
1149
1150 while (isalnum(*pszVar) || *pszVar == '_')
1151 *pszVar++;
1152 if (*pszVar)
1153 return pCmdHlp->pfnPrintf(pCmdHlp, NULL,
1154 "syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
1155
1156
1157 /*
1158 * Calc variable size.
1159 */
1160 size_t cbVar = (size_t)paArgs[0].u64Range + sizeof(DBGCNAMEDVAR);
1161 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1162 cbVar += 1 + (size_t)paArgs[1].u64Range;
1163
1164 /*
1165 * Look for existing one.
1166 */
1167 pszVar = paArgs[0].u.pszString;
1168 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1169 {
1170 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1171 {
1172 /*
1173 * Update existing variable.
1174 */
1175 void *pv = RTMemRealloc(pDbgc->papVars[iVar], cbVar);
1176 if (!pv)
1177 return VERR_PARSE_NO_MEMORY;
1178 PDBGCNAMEDVAR pVar = pDbgc->papVars[iVar] = (PDBGCNAMEDVAR)pv;
1179
1180 pVar->Var = paArgs[1];
1181 memcpy(pVar->szName, paArgs[0].u.pszString, (size_t)paArgs[0].u64Range + 1);
1182 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1183 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1184 return 0;
1185 }
1186 }
1187
1188 /*
1189 * Allocate another.
1190 */
1191 PDBGCNAMEDVAR pVar = (PDBGCNAMEDVAR)RTMemAlloc(cbVar);
1192
1193 pVar->Var = paArgs[1];
1194 memcpy(pVar->szName, pszVar, (size_t)paArgs[0].u64Range + 1);
1195 if (paArgs[1].enmType == DBGCVAR_TYPE_STRING)
1196 pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
1197
1198 /* need to reallocate the pointer array too? */
1199 if (!(pDbgc->cVars % 0x20))
1200 {
1201 void *pv = RTMemRealloc(pDbgc->papVars, (pDbgc->cVars + 0x20) * sizeof(pDbgc->papVars[0]));
1202 if (!pv)
1203 {
1204 RTMemFree(pVar);
1205 return VERR_PARSE_NO_MEMORY;
1206 }
1207 pDbgc->papVars = (PDBGCNAMEDVAR *)pv;
1208 }
1209 pDbgc->papVars[pDbgc->cVars++] = pVar;
1210
1211 NOREF(pCmd); NOREF(pVM); NOREF(cArgs); NOREF(pResult);
1212 return 0;
1213}
1214
1215
1216/**
1217 * The 'unset' command.
1218 *
1219 * @returns VBox status.
1220 * @param pCmd Pointer to the command descriptor (as registered).
1221 * @param pCmdHlp Pointer to command helper functions.
1222 * @param pVM Pointer to the current VM (if any).
1223 * @param paArgs Pointer to (readonly) array of arguments.
1224 * @param cArgs Number of arguments in the array.
1225 */
1226static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1227{
1228 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1229
1230 /*
1231 * Don't trust the parser.
1232 */
1233 for (unsigned i = 0; i < cArgs; i++)
1234 if (paArgs[i].enmType != DBGCVAR_TYPE_STRING)
1235 {
1236 AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
1237 return VERR_PARSE_INCORRECT_ARG_TYPE;
1238 }
1239
1240 /*
1241 * Iterate the variables and unset them.
1242 */
1243 for (unsigned iArg = 0; iArg < cArgs; iArg++)
1244 {
1245 const char *pszVar = paArgs[iArg].u.pszString;
1246
1247 /*
1248 * Look up the variable.
1249 */
1250 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1251 {
1252 if (!strcmp(pszVar, pDbgc->papVars[iVar]->szName))
1253 {
1254 /*
1255 * Shuffle the array removing this entry.
1256 */
1257 void *pvFree = pDbgc->papVars[iVar];
1258 if (iVar + 1 < pDbgc->cVars)
1259 memmove(&pDbgc->papVars[iVar],
1260 &pDbgc->papVars[iVar + 1],
1261 (pDbgc->cVars - iVar - 1) * sizeof(pDbgc->papVars[0]));
1262 pDbgc->papVars[--pDbgc->cVars] = NULL;
1263
1264 RTMemFree(pvFree);
1265 }
1266 } /* lookup */
1267 } /* arg loop */
1268
1269 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1270 return 0;
1271}
1272
1273
1274/**
1275 * The 'loadvars' command.
1276 *
1277 * @returns VBox status.
1278 * @param pCmd Pointer to the command descriptor (as registered).
1279 * @param pCmdHlp Pointer to command helper functions.
1280 * @param pVM Pointer to the current VM (if any).
1281 * @param paArgs Pointer to (readonly) array of arguments.
1282 * @param cArgs Number of arguments in the array.
1283 */
1284static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1285{
1286 /*
1287 * Don't trust the parser.
1288 */
1289 if ( cArgs != 1
1290 || paArgs[0].enmType != DBGCVAR_TYPE_STRING)
1291 {
1292 AssertMsgFailed(("Expected one string exactly!\n"));
1293 return VERR_PARSE_INCORRECT_ARG_TYPE;
1294 }
1295
1296 /*
1297 * Iterate the variables and unset them.
1298 */
1299 FILE *pFile = fopen(paArgs[0].u.pszString, "r");
1300 if (pFile)
1301 {
1302 char szLine[4096];
1303 while (fgets(szLine, sizeof(szLine), pFile))
1304 {
1305 /* Strip it. */
1306 char *psz = szLine;
1307 while (isblank(*psz))
1308 psz++;
1309 int i = (int)strlen(psz) - 1;
1310 while (i >= 0 && isspace(psz[i]))
1311 psz[i--] ='\0';
1312 /* Execute it if not comment or empty line. */
1313 if ( *psz != '\0'
1314 && *psz != '#'
1315 && *psz != ';')
1316 {
1317 pCmdHlp->pfnPrintf(pCmdHlp, NULL, "dbg: set %s", psz);
1318 pCmdHlp->pfnExec(pCmdHlp, "set %s", psz);
1319 }
1320 }
1321 fclose(pFile);
1322 }
1323 else
1324 return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to open file '%s'.\n", paArgs[0].u.pszString);
1325
1326 NOREF(pCmd); NOREF(pVM); NOREF(pResult);
1327 return 0;
1328}
1329
1330
1331/**
1332 * The 'showvars' command.
1333 *
1334 * @returns VBox status.
1335 * @param pCmd Pointer to the command descriptor (as registered).
1336 * @param pCmdHlp Pointer to command helper functions.
1337 * @param pVM Pointer to the current VM (if any).
1338 * @param paArgs Pointer to (readonly) array of arguments.
1339 * @param cArgs Number of arguments in the array.
1340 */
1341static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1342{
1343 PDBGC pDbgc = DBGC_CMDHLP2DBGC(pCmdHlp);
1344
1345 for (unsigned iVar = 0; iVar < pDbgc->cVars; iVar++)
1346 {
1347 int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%-20s ", &pDbgc->papVars[iVar]->szName);
1348 if (!rc)
1349 rc = dbgcCmdFormat(pCmd, pCmdHlp, pVM, &pDbgc->papVars[iVar]->Var, 1, NULL);
1350 if (rc)
1351 return rc;
1352 }
1353
1354 NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1355 return 0;
1356}
1357
1358
1359/**
1360 * The 'harakiri' command.
1361 *
1362 * @returns VBox status.
1363 * @param pCmd Pointer to the command descriptor (as registered).
1364 * @param pCmdHlp Pointer to command helper functions.
1365 * @param pVM Pointer to the current VM (if any).
1366 * @param paArgs Pointer to (readonly) array of arguments.
1367 * @param cArgs Number of arguments in the array.
1368 */
1369static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
1370{
1371 Log(("dbgcCmdHarakiri\n"));
1372 for (;;)
1373 exit(126);
1374 NOREF(pCmd); NOREF(pCmdHlp); NOREF(pVM); NOREF(paArgs); NOREF(cArgs); NOREF(pResult);
1375}
1376
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