VirtualBox

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

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

The Giant CDDL Dual-License Header Change, fixes.

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