VirtualBox

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

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

The Giant CDDL Dual-License Header Change.

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