VirtualBox

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

Last change on this file since 8170 was 8155, checked in by vboxsync, 17 years ago

The Big Sun Rebranding Header Change

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