DBGConsole.cpp revision 677833bc953b6cb418c701facbdcf4aa18d6c44e
/** @file
*
* Debugger Console.
*/
/*
* Copyright (C) 2006 InnoTek Systemberatung GmbH
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License as published by the Free Software Foundation,
* in version 2 as it comes in the "COPYING" file of the VirtualBox OSE
* distribution. VirtualBox OSE is distributed in the hope that it will
* be useful, but WITHOUT ANY WARRANTY of any kind.
*
* If you received this file as part of a commercial VirtualBox
* distribution, then only the terms of your commercial VirtualBox
* license agreement apply instead of the previous paragraph.
*/
/** @page pg_dbgc DBGC - The Debug Console
*
* The debugger console is a first attempt to make some interactive
* debugging facilities for the VirtualBox backend (i.e. the VM). At a later
* stage we'll make a fancy gui around this, but for the present a telnet (or
* serial terminal) will have to suffice.
*
* The debugger is only built into the VM with debug builds or when
* VBOX_WITH_DEBUGGER is defined. There might be need for \#ifdef'ing on this
* define to enable special debugger hooks, but the general approach is to
* make generic interfaces. The individual components also can register
* external commands, and such code must be within \#ifdef.
*
*
* @section sec_dbgc_op Operation (intentions)
*
* The console will process commands in a manner similar to the OS/2 and
* windows kernel debuggers. This means ';' is a command separator and
* that when possible we'll use the same command names as these two uses.
*
*
* @subsection sec_dbg_op_numbers Numbers
*
* Numbers are hexadecimal unless specified with a prefix indicating
* elsewise. Prefixes:
* - '0x' - hexadecimal.
* - '0i' - decimal
* - '0t' - octal.
* - '0y' - binary.
*
*
* @subsection sec_dbg_op_address Addressing modes
*
* - Default is flat. For compatability '%' also means flat.
* - Segmented addresses are specified selector:offset.
* - Physical addresses are specified using '%%'.
* - The default target for the addressing is the guest context, the '#'
* will override this and set it to the host.
*
*
* @subsection sec_dbg_op_evalution Evaluation
*
* As time permits support will be implemented support for a subset of the C
* binary operators, starting with '+', '-', '*' and '/'. Support for variables
* are provided thru commands 'set' and 'unset' and the unary operator '$'. The
* unary '@' operator will indicate function calls. The debugger needs a set of
* memory read functions, but we might later extend this to allow registration of
* external functions too.
*
* A special command '?' will then be added which evalutates a given expression
* and prints it in all the different formats.
*
*
* @subsection sec_dbg_op_registers Registers
*
* Registers are addressed using their name. Some registers which have several fields
* (like gdtr) will have separate names indicating the different fields. The default
* register set is the guest one. To access the hypervisor register one have to
* prefix the register names with '.'.
*
*
* @subsection sec_dbg_op_commands Commands
*
* The commands are all lowercase, case sensitive, and starting with a letter. We will
* later add some special commands ('?' for evaulation) and perhaps command classes ('.', '!')
*
*
* @section sec_dbg_tasks Tasks
*
* To implement DBGT and instrument VMM for basic state inspection and log
* viewing, the follwing task must be executed:
*
* -# Basic threading layer in RT.
* -# Basic tcpip server abstration in RT.
* -# Write DBGC.
* -# Write DBCTCP.
* -# Integrate with VMM and the rest.
* -# Start writing DBGF (VMM).
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DBGC
#include <stdlib.h>
#include <stdio.h>
/* to err.h! */
#define VERR_DBGC_QUIT (-11999)
#define VERR_PARSE_FIRST (-11000)
#define VERR_PARSE_TOO_FEW_ARGUMENTS (VERR_PARSE_FIRST - 0)
#define VWRN_DBGC_CMD_PENDING 12000
#define VWRN_DBGC_ALREADY_REGISTERED 12001
#define VERR_DBGC_COMMANDS_NOT_REGISTERED (-12002)
#define VERR_DBGC_BP_NOT_FOUND (-12003)
#define VERR_DBGC_BP_EXISTS (-12004)
#define VINF_DBGC_BP_NO_COMMAND 12005
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Makes a DBGC variable type pair.
* Typically used by binary operators. */
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Debugger console per breakpoint data.
*/
typedef struct DBGCBP
{
/** Pointer to the next breakpoint in the list. */
/** The breakpoint identifier. */
/** The size of the command. */
/** The command to execute when the breakpoint is hit. */
char szCmd[1];
} DBGCBP;
/** Pointer to a breakpoint. */
/**
* Named variable.
*
* Always allocated from heap in one signle block.
*/
typedef struct DBGCNAMEDVAR
{
/** The variable. */
/** It's name. */
char szName[1];
} DBGCNAMEDVAR;
/** Pointer to named variable. */
typedef DBGCNAMEDVAR *PDBGCNAMEDVAR;
/**
* Debugger console status
*/
typedef enum DBGCSTATUS
{
/** Normal status, .*/
} DBGCSTATUS;
/**
* Debugger console instance data.
*/
typedef struct DBGC
{
/** Command helpers. */
/** Pointer to backend callback structure. */
/** Log indicator. (If set we're writing the log to the console.) */
bool fLog;
/** Pointer to the current VM. */
/** Indicates whether or we're ready for input. */
bool fReady;
/** Indicates whether we're in guest (true) or hypervisor (false) register context. */
bool fRegCtxGuest;
/** Indicates whether the register are terse or sparse. */
bool fRegTerse;
/** Input buffer. */
char achInput[2048];
/** To ease debugging. */
unsigned uInputZero;
/** Write index in the input buffer. */
unsigned iWrite;
/** Read index in the input buffer. */
unsigned iRead;
/** The number of lines in the buffer. */
unsigned cInputLines;
/** Indicates that we have a buffer overflow condition.
* This means that input is ignored up to the next newline. */
bool fInputOverflow;
/** Scratch buffer position. */
char *pszScratch;
/** Scratch buffer. */
char achScratch[16384];
/** Argument array position. */
unsigned iArg;
/** Array of argument variables. */
/** rc from last dbgcHlpPrintfV(). */
int rcOutput;
/** Number of variables in papVars. */
unsigned cVars;
/** Array of global variables.
* Global variables can be referenced using the $ operator and set
* and unset using command with those names. */
/** Current dissassembler position. */
/** Current source position. (flat GC) */
/** Current memory dump position. */
/** Size of the previous dump element. */
unsigned cbDumpElement;
/** The list of breakpoints. (singly linked) */
} DBGC;
/** Pointer to debugger console instance data. */
/** Converts a Command Helper pointer to a pointer to DBGC instance data. */
/**
* Chunk of external commands.
*/
typedef struct DBGCEXTCMDS
{
/** Number of commands descriptors. */
unsigned cCmds;
/** Pointer to array of command descriptors. */
/** Pointer to the next chunk. */
struct DBGCEXTCMDS *pNext;
} DBGCEXTCMDS;
/** Pointer to chunk of external commands. */
typedef DBGCEXTCMDS *PDBGCEXTCMDS;
/**
* Unary operator handler function.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
/** Pointer to a unary operator handler function. */
typedef FNDBGCOPUNARY *PFNDBGCOPUNARY;
/**
* Binary operator handler function.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
typedef DECLCALLBACK(int) FNDBGCOPBINARY(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
/** Pointer to a binary operator handler function. */
typedef FNDBGCOPBINARY *PFNDBGCOPBINARY;
/**
* Operator descriptor.
*/
typedef struct DBGCOP
{
/** Operator mnemonic. */
char szName[4];
/** Length of name. */
const unsigned cchName;
/** Whether or not this is a binary operator.
* Unary operators are evaluated right-to-left while binary are left-to-right. */
bool fBinary;
/** Precedence level. */
unsigned iPrecedence;
/** Unary operator handler. */
/** Binary operator handler. */
/** Operator description. */
const char *pszDescription;
} DBGCOP;
/** Pointer to an operator descriptor. */
/** Pointer to a const operator descriptor. */
/** Pointer to symbol descriptor. */
/** Pointer to const symbol descriptor. */
/**
* Get builtin symbol.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pSymDesc Pointer to the symbol descriptor.
* @param pCmdHlp Pointer to the command callback structure.
* @param enmType The result type.
* @param pResult Where to store the result.
*/
typedef DECLCALLBACK(int) FNDBGCSYMGET(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
/** Pointer to get function for a builtin symbol. */
typedef FNDBGCSYMGET *PFNDBGCSYMGET;
/**
* Set builtin symbol.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pSymDesc Pointer to the symbol descriptor.
* @param pCmdHlp Pointer to the command callback structure.
* @param pValue The value to assign the symbol.
*/
/** Pointer to set function for a builtin symbol. */
typedef FNDBGCSYMSET *PFNDBGCSYMSET;
/**
* Symbol description (for builtin symbols).
*/
typedef struct DBGCSYM
{
/** Symbol name. */
const char *pszName;
/** Get function. */
/** Set function. (NULL if readonly) */
/** User data. */
unsigned uUser;
} DBGCSYM;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDisasm(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpDiv(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpMod(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpAdd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpSub(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult);
static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult);
static int dbgcSymbolGet(PDBGC pDbgc, const char *pszSymbol, DBGCVARTYPE enmType, PDBGCVAR pResult);
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/**
* Pointer to head of the list of external commands.
*/
/** Locks the g_pExtCmdsHead list for reading. */
#define DBGCEXTCMDS_LOCK_RD() do { } while (0)
/** Locks the g_pExtCmdsHead list for writing. */
#define DBGCEXTCMDS_LOCK_WR() do { } while (0)
/** UnLocks the g_pExtCmdsHead list after reading. */
#define DBGCEXTCMDS_UNLOCK_RD() do { } while (0)
/** UnLocks the g_pExtCmdsHead list after writing. */
#define DBGCEXTCMDS_UNLOCK_WR() do { } while (0)
/** One argument of any kind. */
static const DBGCVARDESC g_aArgAny[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** Multiple string arguments (min 1). */
static const DBGCVARDESC g_aArgMultiStr[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** Filename string. */
static const DBGCVARDESC g_aArgFilename[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'ba' arguments. */
static const DBGCVARDESC g_aArgBrkAcc[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 1, 1, DBGCVAR_CAT_STRING, 0, "access", "The access type: x=execute, rw=read/write (alias r), w=write, i=not implemented." },
{ 1, 1, DBGCVAR_CAT_NUMBER, 0, "size", "The access size: 1, 2, 4, or 8. 'x' access requires 1, and 8 requires amd64 long mode." },
{ 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
{ 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
{ 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
};
/** 'bc', 'bd', 'be' arguments. */
static const DBGCVARDESC g_aArgBrks[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'bp' arguments. */
static const DBGCVARDESC g_aArgBrkSet[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
{ 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
{ 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
};
/** 'br' arguments. */
static const DBGCVARDESC g_aArgBrkREM[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 0, 1, DBGCVAR_CAT_NUMBER, 0, "passes", "The number of passes before we trigger the breakpoint. (0 is default)" },
{ 0, 1, DBGCVAR_CAT_NUMBER, DBGCVD_FLAGS_DEP_PREV, "max passes", "The number of passes after which we stop triggering the breakpoint. (~0 is default)" },
{ 0, 1, DBGCVAR_CAT_STRING, 0, "cmds", "String of commands to be executed when the breakpoint is hit. Quote it!" },
};
/** 'd?' arguments. */
static const DBGCVARDESC g_aArgDumpMem[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'dpd*' arguments. */
static const DBGCVARDESC g_aArgDumpPD[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from. Range is applied to the page directory." },
};
/** 'dpda' arguments. */
static const DBGCVARDESC g_aArgDumpPDAddr[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 0, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page directory entry to start dumping from." },
};
/** 'dpt?' arguments. */
static const DBGCVARDESC g_aArgDumpPT[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address which page directory entry to start dumping from." },
};
/** 'dpta' arguments. */
static const DBGCVARDESC g_aArgDumpPTAddr[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
{ 1, 1, DBGCVAR_CAT_POINTER, 0, "address", "Address of the page table entry to start dumping from." },
};
/** 'help' arguments. */
static const DBGCVARDESC g_aArgHelp[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'info' arguments. */
static const DBGCVARDESC g_aArgInfo[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'ln' arguments. */
static const DBGCVARDESC g_aArgListNear[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'ln' return. */
static const DBGCVARDESC g_RetListNear =
{
};
/** loadsyms arguments. */
static const DBGCVARDESC g_aArgLoadSyms[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** log arguments. */
static const DBGCVARDESC g_aArgLog[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** logdest arguments. */
static const DBGCVARDESC g_aArgLogDest[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** logflags arguments. */
static const DBGCVARDESC g_aArgLogFlags[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'm' argument. */
static const DBGCVARDESC g_aArgMemoryInfo[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'r' arguments. */
static const DBGCVARDESC g_aArgReg[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 's' arguments. */
static const DBGCVARDESC g_aArgSource[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'set' arguments */
static const DBGCVARDESC g_aArgSet[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** 'u' arguments. */
static const DBGCVARDESC g_aArgDisasm[] =
{
/* cTimesMin, cTimesMax, enmCategory, fFlags, pszName, pszDescription */
};
/** Command descriptors. */
{
/* pszCmd, cArgsMin, cArgsMax, paArgDescs, cArgDescs, pResultDesc, fFlags, pfnHandler pszSyntax, ....pszDescription */
{ "ba", 3, 6, &g_aArgBrkAcc[0], ELEMENTS(g_aArgBrkAcc), NULL, 0, dbgcCmdBrkAccess, "<access> <size> <address> [passes [max passes]] [cmds]",
"Sets a data access breakpoint." },
{ "bc", 1, ~0, &g_aArgBrks[0], ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkClear, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
{ "bd", 1, ~0, &g_aArgBrks[0], ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkDisable, "all | <bp#> [bp# []]", "Disables a set of breakpoints." },
{ "be", 1, ~0, &g_aArgBrks[0], ELEMENTS(g_aArgBrks), NULL, 0, dbgcCmdBrkEnable, "all | <bp#> [bp# []]", "Enabled a set of breakpoints." },
{ "bp", 1, 4, &g_aArgBrkSet[0], ELEMENTS(g_aArgBrkSet), NULL, 0, dbgcCmdBrkSet, "<address> [passes [max passes]] [cmds]",
"Sets a breakpoint (int 3)." },
{ "br", 1, 4, &g_aArgBrkREM[0], ELEMENTS(g_aArgBrkREM), NULL, 0, dbgcCmdBrkREM, "<address> [passes [max passes]] [cmds]",
"Sets a recompiler specific breakpoint." },
{ "d", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory using last element size." },
{ "da", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory as ascii string." },
{ "db", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in bytes." },
{ "dd", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in double words." },
{ "dpd", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the default context." },
{ "dpda", 0, 1, &g_aArgDumpPDAddr[0],ELEMENTS(g_aArgDumpPDAddr),NULL, 0, dbgcCmdDumpPageDir, "[addr]", "Dumps specified page directory." },
{ "dpdb", 1, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDirBoth, "[addr] [index]", "Dumps page directory entries of the guest and the hypervisor. " },
{ "dpdg", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the guest." },
{ "dpdh", 0, 1, &g_aArgDumpPD[0], ELEMENTS(g_aArgDumpPD), NULL, 0, dbgcCmdDumpPageDir, "[addr] [index]", "Dumps page directory entries of the hypervisor. " },
{ "dpt", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the default context." },
{ "dpta", 1, 1, &g_aArgDumpPTAddr[0],ELEMENTS(g_aArgDumpPTAddr), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps specified page table." },
{ "dptb", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTableBoth,"<addr>", "Dumps page table entries of the guest and the hypervisor." },
{ "dptg", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the guest." },
{ "dpth", 1, 1, &g_aArgDumpPT[0], ELEMENTS(g_aArgDumpPT), NULL, 0, dbgcCmdDumpPageTable,"<addr>", "Dumps page table entries of the hypervisor." },
{ "dq", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in quad words." },
{ "dw", 0, 1, &g_aArgDumpMem[0], ELEMENTS(g_aArgDumpMem), NULL, 0, dbgcCmdDumpMem, "[addr]", "Dump memory in words." },
{ "format", 1, 1, &g_aArgAny[0], ELEMENTS(g_aArgAny), NULL, 0, dbgcCmdFormat, "", "Evaluates an expression and formats it." },
{ "help", 0, ~0, &g_aArgHelp[0], ELEMENTS(g_aArgHelp), NULL, 0, dbgcCmdHelp, "[cmd/op [..]]", "Display help. For help about info items try 'help info'." },
{ "info", 1, 2, &g_aArgInfo[0], ELEMENTS(g_aArgInfo), NULL, 0, dbgcCmdInfo, "<info> [args]", "Display info register in the DBGF." },
{ "ln", 0, ~0, &g_aArgListNear[0], ELEMENTS(g_aArgListNear), &g_RetListNear, 0, dbgcCmdListNear, "[addr/sym [..]]", "List symbols near to the address. Default address is CS:EIP." },
{ "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." },
{ "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." },
{ "log", 1, 1, &g_aArgLog[0], ELEMENTS(g_aArgLog), NULL, 0, dbgcCmdLog, "<group string>", "Modifies the logging group settings (VBOX_LOG)" },
{ "logdest", 1, 1, &g_aArgLogDest[0], ELEMENTS(g_aArgLogDest), NULL, 0, dbgcCmdLogDest, "<dest string>", "Modifies the logging destination (VBOX_LOG_DEST)." },
{ "logflags", 1, 1, &g_aArgLogFlags[0], ELEMENTS(g_aArgLogFlags), NULL, 0, dbgcCmdLogFlags, "<flags string>", "Modifies the logging flags (VBOX_LOG_FLAGS)." },
{ "m", 1, 1, &g_aArgMemoryInfo[0],ELEMENTS(g_aArgMemoryInfo),NULL, 0, dbgcCmdMemoryInfo, "<addr>", "Display information about that piece of memory." },
{ "r", 0, 2, &g_aArgReg[0], ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdReg, "[reg [newval]]", "Show or set register(s) - active reg set." },
{ "rg", 0, 2, &g_aArgReg[0], ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegGuest, "[reg [newval]]", "Show or set register(s) - guest reg set." },
{ "rh", 0, 2, &g_aArgReg[0], ELEMENTS(g_aArgReg), NULL, 0, dbgcCmdRegHyper, "[reg [newval]]", "Show or set register(s) - hypervisor reg set." },
{ "s", 0, 1, &g_aArgSource[0], ELEMENTS(g_aArgSource), NULL, 0, dbgcCmdSource, "[addr]", "Source." },
{ "set", 2, 2, &g_aArgSet[0], ELEMENTS(g_aArgSet), NULL, 0, dbgcCmdSet, "<var> <value>", "Sets a global variable." },
{ "u", 0, 1, &g_aArgDisasm[0], ELEMENTS(g_aArgDisasm), NULL, 0, dbgcCmdDisasm, "[addr]", "Disassemble." },
{ "unset", 1, ~0, &g_aArgMultiStr[0], ELEMENTS(g_aArgMultiStr), NULL, 0, dbgcCmdUnset, "<var1> [var1..[varN]]", "Unsets (delete) one or more global variables." },
};
/** Operators. */
{
/* szName is initialized as a 4 char array because of M$C elsewise optimizing it away in /Ox mode (the 'const char' vs 'char' problem). */
/* szName, cchName, fBinary, iPrecedence, pfnHandlerUnary, pfnHandlerBitwise */
};
/** Register symbol uUser value.
* @{
*/
/** If set the register set is the hypervisor and not the guest one. */
/** If set a far conversion of the value will use the high 16 bit for the selector.
* If clear the low 16 bit will be used. */
/** The shift value to calc the size of a register symbol from the uUser value. */
#define SYMREG_SIZE_SHIFT (24)
/** Get the offset */
/** Get the size. */
/** 1 byte. */
/** 2 byte. */
/** 4 byte. */
/** 6 byte. */
/** 8 byte. */
/** 12 byte. */
/** 16 byte. */
/** @} */
/** Builtin Symbols.
* ASSUMES little endian register representation!
*/
{
/* hypervisor */
{".eax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".ax", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".al", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".ah", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eax) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".ebx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".bx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".bl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".bh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".ecx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".cx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".cl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".ch", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ecx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".edx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".dx", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".dl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".dh", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edx) + 1 | SYMREG_SIZE_1 | SYMREG_FLAGS_HYPER },
{".edi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".di", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, edi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".esi", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".si", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esi) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".ebp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".bp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ebp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".esp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".sp", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, esp) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".eip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".ip", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eip) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".efl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".eflags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".fl", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".flags", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, eflags) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".cr0", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr0) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".cr2", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr2) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".cr3", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr3) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".cr4", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, cr4) | SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".ldtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, ldtr) | SYMREG_SIZE_2 | SYMREG_FLAGS_HYPER },
{".gdtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
{".gdtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.cbGdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
{".gdtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, gdtr.pGdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
{".idtr", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr) | SYMREG_SIZE_6 | SYMREG_FLAGS_HYPER },
{".idtr.limit", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.cbIdt)| SYMREG_SIZE_2| SYMREG_FLAGS_HYPER },
{".idtr.base", dbgcSymGetReg, dbgcSymSetReg, offsetof(CPUMCTX, idtr.pIdt)| SYMREG_SIZE_4 | SYMREG_FLAGS_HYPER },
};
/**
* Prints full command help.
*/
{
int rc;
/* the command */
"%s%-*s %-30s %s",
else
/* argument descriptions. */
{
" %-12s %s",
{
else
}
else
{
else
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " <%u-%u>\n", pCmd->paArgDescs[i].cTimesMin, pCmd->paArgDescs[i].cTimesMax);
}
}
return rc;
}
/**
* The 'help' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdHelp(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
int rc = VINF_SUCCESS;
unsigned i;
if (!cArgs)
{
/*
* All the stuff.
*/
"VirtualBox Debugger\n"
"-------------------\n"
"\n"
"Commands and Functions:\n");
"%-11s %-30s %s\n",
g_aCmds[i].pszDescription);
if (g_pExtCmdsHead)
{
"\n"
"External Commands and Functions:\n");
".%-10s %-30s %s\n",
}
"\n"
"Operators:\n");
unsigned iPrecedence = 0;
while (cLeft > 0)
{
{
"%-10s %s %s\n",
g_aOps[i].pszDescription);
cLeft--;
}
iPrecedence++;
}
}
else
{
/*
* Search for the arguments (strings).
*/
{
/* lookup in the command list */
bool fFound = false;
{
fFound = true;
break;
}
/* external commands */
if ( !fFound
{
{
fFound = true;
break;
}
}
/* operators */
{
{
"%-10s %s %s\n",
g_aOps[i].pszDescription);
fFound = true;
break;
}
}
/* found? */
if (!fFound)
"error: '%s' was not found!\n",
} /* foreach argument */
}
return rc;
}
/**
* The 'quit', 'exit' and 'bye' commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdQuit(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
return VERR_DBGC_QUIT;
}
/**
* The 'go' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdGo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Check if the VM is halted or not before trying to resume it.
*/
if (!DBGFR3IsHalted(pVM))
else
{
if (VBOX_FAILURE(rc))
}
return 0;
}
/**
* The 'stop' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdStop(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Check if the VM is halted or not before trying to halt it.
*/
int rc;
if (DBGFR3IsHalted(pVM))
else
{
if (VBOX_SUCCESS(rc))
else
}
return rc;
}
/**
* The 'ba' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkAccess(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Interpret access type.
*/
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access type '%s' for '%s'. Valid types are 'e', 'r', 'w' and 'i'.\n",
{
}
/*
* Validate size.
*/
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid access size %RX64 for '%s'. 'x' access type requires size 1!\n",
{
case 1:
case 2:
case 4:
break;
/*case 8: - later*/
default:
}
/*
* Convert the pointer to a DBGF address.
*/
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[2], rc);
/*
* Pick out the optional arguments.
*/
uint64_t iHitTrigger = 0;
uint64_t iHitDisable = ~0;
unsigned iArg = 3;
{
iArg++;
{
iArg++;
}
}
{
iArg++;
}
/*
* Try set the breakpoint.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Set access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
if (rc == VERR_DBGC_BP_EXISTS)
{
if (VBOX_SUCCESS(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated access breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
}
}
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set access breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
}
/**
* The 'bc' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkClear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Enumerate the arguments.
*/
int rc = VINF_SUCCESS;
{
{
/* one */
{
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
break;
}
if (VBOX_FAILURE(rc2))
}
{
/* all */
while (pBp)
{
if (VBOX_FAILURE(rc2))
}
}
else
{
/* invalid parameter */
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
break;
}
}
return rc;
}
/**
* The 'bd' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkDisable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Enumerate the arguments.
*/
int rc = VINF_SUCCESS;
{
{
/* one */
{
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
break;
}
if (VBOX_FAILURE(rc))
}
{
/* all */
{
if (VBOX_FAILURE(rc))
}
}
else
{
/* invalid parameter */
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
break;
}
}
return rc;
}
/**
* The 'be' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkEnable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Enumerate the arguments.
*/
int rc = VINF_SUCCESS;
{
{
/* one */
{
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Breakpoint id %RX64 is too large!\n", paArgs[iArg].u.u64Number);
break;
}
if (VBOX_FAILURE(rc))
}
{
/* all */
{
if (VBOX_FAILURE(rc))
}
}
else
{
/* invalid parameter */
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Invalid argument '%s' to '%s'!\n", paArgs[iArg].u.pszString, pCmd->pszCmd);
break;
}
}
return rc;
}
/**
* Breakpoint enumeration callback function.
*
* @returns VBox status code. Any failure will stop the enumeration.
* @param pVM The VM handle.
* @param pvUser The user argument.
* @param pBp Pointer to the breakpoint information. (readonly)
*/
{
/*
* BP type and size.
*/
char chType;
char cb = 1;
{
case DBGFBPTYPE_INT3:
chType = 'p';
break;
case DBGFBPTYPE_REG:
{
default: chType = '?'; break;
}
break;
case DBGFBPTYPE_REM:
chType = 'r';
break;
default:
chType = '?';
break;
}
else
/*
* Try resolve the address.
*/
if (VBOX_SUCCESS(rc))
{
if (!off)
else if (off > 0)
else
}
/*
* The commands.
*/
if (pDbgcBp)
{
else
}
else
return VINF_SUCCESS;
}
/**
* The 'bl' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkList(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR /*paArgs*/, unsigned /*cArgs*/, PDBGCVAR /*pResult*/)
{
/*
* Enumerate the breakpoints.
*/
if (VBOX_FAILURE(rc))
return rc;
}
/**
* The 'bp' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkSet(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Convert the pointer to a DBGF address.
*/
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
/*
* Pick out the optional arguments.
*/
uint64_t iHitTrigger = 0;
uint64_t iHitDisable = ~0;
unsigned iArg = 1;
{
iArg++;
{
iArg++;
}
}
{
iArg++;
}
/*
* Try set the breakpoint.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
if (rc == VERR_DBGC_BP_EXISTS)
{
if (VBOX_SUCCESS(rc))
}
}
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
}
/**
* The 'br' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdBrkREM(PCDBGCCMD /*pCmd*/, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR /*pResult*/)
{
/*
* Convert the pointer to a DBGF address.
*/
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Couldn't convert '%DV' to a DBGF address, rc=%Vrc.\n", &paArgs[0], rc);
/*
* Pick out the optional arguments.
*/
uint64_t iHitTrigger = 0;
uint64_t iHitDisable = ~0;
unsigned iArg = 1;
{
iArg++;
{
iArg++;
}
}
{
iArg++;
}
/*
* Try set the breakpoint.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
if (rc == VERR_DBGC_BP_EXISTS)
{
if (VBOX_SUCCESS(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Updated REM breakpoint %u at %VGv\n", iBp, Address.FlatPtr);
}
}
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Failed to set REM breakpoint at %VGv, rc=%Vrc.\n", Address.FlatPtr, rc);
}
/**
* The 'u' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDisasm(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs > 1
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
/*
* Find address.
*/
unsigned fFlags = DBGF_DISAS_FLAGS_NO_ADDRESS;
if (!cArgs)
{
{
if (pDbgc->fRegCtxGuest)
else
}
}
else
/*
* Range.
*/
{
case DBGCVAR_RANGE_NONE:
break;
case DBGCVAR_RANGE_ELEMENTS:
break;
case DBGCVAR_RANGE_BYTES:
break;
default:
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DisasmPos.enmRangeType);
}
/*
* Convert physical and host addresses to guest addresses.
*/
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
break;
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_HC_FAR:
{
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: failed to evaluate '%%(%Dv)' -> %Vrc .\n", pDbgc->DisasmPos, rc);
break;
}
default: AssertFailed(); break;
}
/*
* Print address.
* todo: Change to list near.
*/
#if 0
if (VBOX_FAILURE(rc))
return rc;
#endif
/*
* Do the disassembling.
*/
unsigned cTries = 32;
if (iRangeLeft == 0) /* klugde for 'r'. */
iRangeLeft = -1;
for (;;)
{
/*
* Disassemble the instruction.
*/
char szDis[256];
rc = DBGFR3DisasInstrEx(pVM, DBGF_SEL_FLAT, pDbgc->DisasmPos.u.GCFlat, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
else
rc = DBGFR3DisasInstrEx(pVM, pDbgc->DisasmPos.u.GCFar.sel, pDbgc->DisasmPos.u.GCFar.off, fFlags, &szDis[0], sizeof(szDis), &cbInstr);
if (VBOX_SUCCESS(rc))
{
/* print it */
if (VBOX_FAILURE(rc))
return rc;
}
else
{
/* bitch. */
int rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Failed to disassemble instruction, skipping one byte.\n");
if (VBOX_FAILURE(rc))
return rc;
if (cTries-- > 0)
cbInstr = 1;
}
/* advance */
if (iRangeLeft < 0) /* 'r' */
break;
iRangeLeft--;
else
iRangeLeft -= cbInstr;
if (VBOX_FAILURE(rc))
if (iRangeLeft <= 0)
break;
}
return 0;
}
/**
* The 's' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdSource(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs > 1
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
/*
* Find address.
*/
if (!cArgs)
{
{
}
}
else
/*
* Ensure the the source address is flat GC.
*/
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_HC_FAR:
{
if (VBOX_FAILURE(rc))
break;
}
default: AssertFailed(); break;
}
/*
* Range.
*/
{
case DBGCVAR_RANGE_NONE:
break;
case DBGCVAR_RANGE_ELEMENTS:
break;
case DBGCVAR_RANGE_BYTES:
break;
default:
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->SourcePos.enmRangeType);
}
/*
* Do the disassembling.
*/
bool fFirst = 1;
if (iRangeLeft == 0) /* klugde for 'r'. */
iRangeLeft = -1;
for (;;)
{
/*
* Get line info.
*/
if (VBOX_FAILURE(rc))
return VINF_SUCCESS;
unsigned cLines = 0;
{
/*
* Print filenamename
*/
fFirst = true;
if (fFirst)
{
if (VBOX_FAILURE(rc))
return rc;
}
/*
* Try open the file and read the line.
*/
if (phFile)
{
/* Skip ahead to the desired line. */
char szLine[4096];
if (cBefore > 7)
cBefore = 0;
while (cLeft > 0)
{
szLine[0] = '\0';
break;
cLeft--;
}
if (!cLeft)
{
/* print the before lines */
for (;;)
{
while (cch > 0 && (szLine[cch - 1] == '\r' || szLine[cch - 1] == '\n' || isspace(szLine[cch - 1])) )
if (cBefore-- <= 0)
break;
szLine[0] = '\0';
cLines++;
}
/* print the actual line */
}
if (VBOX_FAILURE(rc))
return rc;
fFirst = false;
}
else
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "Warning: couldn't open source file '%s'\n", Line.szFilename);
}
/*
* Advance
*/
if (iRangeLeft < 0) /* 'r' */
break;
iRangeLeft -= cLines;
else
iRangeLeft -= 1;
if (VBOX_FAILURE(rc))
if (iRangeLeft <= 0)
break;
}
return 0;
}
/**
* The 'r' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdReg(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (pDbgc->fRegCtxGuest)
else
}
/**
* Common worker for the dbgcCmdReg*() commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
* @param pszPrefix The symbol prefix.
*/
static DECLCALLBACK(int) dbgcCmdRegCommon(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult, const char *pszPrefix)
{
/*
* cArgs == 0: Show all
*/
if (cArgs == 0)
{
/*
* Get register context.
*/
int rc;
if (!*pszPrefix)
{
}
else
{
}
if (VBOX_FAILURE(rc))
/*
* Format the flags.
*/
static struct
{
} aFlags[] =
{
};
char szEFlags[80];
{
if (pszAdd)
{
*psz++ = ' ';
}
}
/*
* Format the registers.
*/
{
"%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
"%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
"%scs=%04x %sds=%04x %ses=%04x %sfs=%04x %sgs=%04x %sss=%04x %seflags=%08x\n",
pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->edi, pszPrefix, pCtxCore->esi,
pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 34 : 31, szEFlags,
pszPrefix, (RTSEL)pCtxCore->fs, pszPrefix, (RTSEL)pCtxCore->gs, pszPrefix, (RTSEL)pCtxCore->ss, pszPrefix, efl);
}
else
{
"%seax=%08x %sebx=%08x %secx=%08x %sedx=%08x %sesi=%08x %sedi=%08x\n"
"%seip=%08x %sesp=%08x %sebp=%08x %siopl=%d %*s\n"
"%scs={%04x base=%08x limit=%08x flags=%08x} %sdr0=%08x %sdr1=%08x\n"
"%sds={%04x base=%08x limit=%08x flags=%08x} %sdr2=%08x %sdr3=%08x\n"
"%ses={%04x base=%08x limit=%08x flags=%08x} %sdr4=%08x %sdr5=%08x\n"
"%sfs={%04x base=%08x limit=%08x flags=%08x} %sdr6=%08x %sdr7=%08x\n"
"%sgs={%04x base=%08x limit=%08x flags=%08x} %scr0=%08x %scr2=%08x\n"
"%sss={%04x base=%08x limit=%08x flags=%08x} %scr3=%08x %scr4=%08x\n"
"%sgdtr=%08x:%04x %sidtr=%08x:%04x %seflags=%08x\n"
"%sldtr={%04x base=%08x limit=%08x flags=%08x}\n"
"%str ={%04x base=%08x limit=%08x flags=%08x}\n"
"%sSysEnter={cs=%04llx eip=%08llx esp=%08llx}\n"
"%sFCW=%04x %sFSW=%04x %sFTW=%04x\n"
,
pszPrefix, pCtxCore->eax, pszPrefix, pCtxCore->ebx, pszPrefix, pCtxCore->ecx, pszPrefix, pCtxCore->edx, pszPrefix, pCtxCore->edi, pszPrefix, pCtxCore->esi,
pszPrefix, pCtxCore->eip, pszPrefix, pCtxCore->esp, pszPrefix, pCtxCore->ebp, pszPrefix, X86_EFL_GET_IOPL(efl), *pszPrefix ? 33 : 31, szEFlags,
pszPrefix, (RTSEL)pCtxCore->cs, pCtx->csHid.u32Base, pCtx->csHid.u32Limit, pCtx->csHid.Attr.u, pszPrefix, pCtx->dr0, pszPrefix, pCtx->dr1,
pszPrefix, (RTSEL)pCtxCore->ds, pCtx->dsHid.u32Base, pCtx->dsHid.u32Limit, pCtx->dsHid.Attr.u, pszPrefix, pCtx->dr2, pszPrefix, pCtx->dr3,
pszPrefix, (RTSEL)pCtxCore->es, pCtx->esHid.u32Base, pCtx->esHid.u32Limit, pCtx->esHid.Attr.u, pszPrefix, pCtx->dr4, pszPrefix, pCtx->dr5,
pszPrefix, (RTSEL)pCtxCore->fs, pCtx->fsHid.u32Base, pCtx->fsHid.u32Limit, pCtx->fsHid.Attr.u, pszPrefix, pCtx->dr6, pszPrefix, pCtx->dr7,
pszPrefix, (RTSEL)pCtxCore->gs, pCtx->gsHid.u32Base, pCtx->gsHid.u32Limit, pCtx->gsHid.Attr.u, pszPrefix, pCtx->cr0, pszPrefix, pCtx->cr2,
pszPrefix, (RTSEL)pCtxCore->ss, pCtx->ssHid.u32Base, pCtx->ssHid.u32Limit, pCtx->ssHid.Attr.u, pszPrefix, pCtx->cr3, pszPrefix, pCtx->cr4,
pszPrefix, pCtx->gdtr.pGdt,pCtx->gdtr.cbGdt, pszPrefix, pCtx->idtr.pIdt, pCtx->idtr.cbIdt, pszPrefix, pCtxCore->eflags,
}
/*
* Disassemble one instruction at cs:eip.
*/
}
/*
* cArgs == 1: Show the register.
* cArgs == 2: Modify the register.
*/
if ( cArgs == 1
|| cArgs == 2)
{
/* locate the register symbol. */
if ( *pszPrefix
{
/* prepend the prefix. */
}
if (!pSym)
return pCmdHlp->pfnVBoxError(pCmdHlp, VERR_INVALID_PARAMETER /* VERR_DBGC_INVALID_REGISTER */, "Invalid register name '%s'.\n", pszReg);
/* show the register */
if (cArgs == 1)
{
if (VBOX_FAILURE(rc))
}
/* change the register */
if (VBOX_FAILURE(rc))
return VINF_SUCCESS;
}
}
/**
* The 'rg' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdRegGuest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
}
/**
* The 'rh' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdRegHyper(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
}
/**
* The 'rt' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdRegTerse(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, pDbgc->fRegTerse ? "info: Terse register info.\n" : "info: Verbose register info.\n");
}
/**
* The 't' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdTrace(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (VBOX_SUCCESS(rc))
else
rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to single step VM %p\n", pDbgc->pVM);
return rc;
}
/**
* The 'k', 'kg' and 'kh' commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdStack(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Figure which context we're called for.
*/
int rc;
if (fGuest)
else
if (VBOX_FAILURE(rc))
/*
* Print header.
* 12345678 12345678 0023:87654321 12345678 87654321 12345678 87654321 symbol
*/
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "EBP Ret EBP Ret CS:EIP Arg0 Arg1 Arg2 Arg3 CS:EIP / Symbol [line]\n");
if (VBOX_FAILURE(rc))
return rc;
do
{
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%08RX32 %08RX32 %04RX32:%08RX32 %08RX32 %08RX32 %08RX32 %08RX32",
if (VBOX_FAILURE(rc))
return rc;
else
{
RTGCINTPTR offDisp = Frame.AddrPC.FlatPtr - Frame.pSymPC->Value; /** @todo this isn't 100% correct for segemnted stuff. */
if (offDisp > 0)
else if (offDisp < 0)
else
}
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, " [%s @ 0i%d]", Frame.pLinePC->szFilename, Frame.pLinePC->uLineNo);
if (VBOX_SUCCESS(rc))
if (VBOX_FAILURE(rc))
return rc;
/* next */
} while (VBOX_SUCCESS(rc));
return VINF_SUCCESS;
}
/**
* The 'dd', 'dw' and 'db' commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDumpMem(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs > 1
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
if (!pVM)
/*
* Figure out the element size.
*/
bool fAscii = false;
{
default:
case 'a':
cbElement = 1;
fAscii = true;
break;
case '\0':
if (!cbElement)
cbElement = 1;
break;
}
/*
* Find address.
*/
if (!cArgs)
else
/*
* Range.
*/
{
case DBGCVAR_RANGE_NONE:
break;
case DBGCVAR_RANGE_ELEMENTS:
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "error: Too many elements requested. Max is 2048 elements.\n");
break;
case DBGCVAR_RANGE_BYTES:
break;
default:
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: Unknown range type %d.\n", pDbgc->DumpPos.enmRangeType);
}
/*
* Do the dumping.
*/
for (;;)
{
/*
* Read memory.
*/
char achBuffer[16];
if (VBOX_FAILURE(rc))
{
}
/*
* Display it.
*/
if (!fAscii)
{
unsigned i;
{
const char *pszSpace = " ";
pszSpace = "-";
switch (cbElement)
{
case 8: pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%s%016llx", pszSpace, *(uint64_t *)&achBuffer[i]); break;
}
}
/* chars column */
{
while (i < sizeof(achBuffer))
{
else
}
}
}
else
{
/*
* We print up to the first zero and stop there.
* Only printables + '\t' and '\n' are printed.
*/
if (!u8Prev)
unsigned i;
for (i = 0; i < cb; i++)
{
if ( u8 < 127
|| u8 == '\t'
|| u8 == '\n'))
else if (!u8)
break;
else
}
if (u8 == '\0')
}
/*
* Advance
*/
if (VBOX_FAILURE(rc))
if (cbLeft <= 0)
break;
}
return VINF_SUCCESS;
}
/**
* The 'dpd*' commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDumpPageDir(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs > 1
|| (cArgs == 1 && pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
)
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
if (!pVM)
/*
* Where to start dumping page directory entries?
*/
int rc;
unsigned off = ~0;
{
/*
* Get defaults.
*/
off = 0;
{
}
else
{
/** @todo fix hypervisor CR4 value! */
//u32CR4 = CPUMGetHyperCR4(pVM);
}
if (VBOX_FAILURE(rc))
if (cArgs > 0)
{
cEntries = 3;
{
/*
* Add index.
*/
rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE));
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, paArgs[0].u.u64Number * sizeof(VBOXPTE));
off = ~0;
else
{
}
}
else
{
/*
* Pointer which we want the page directory entry for.
* Start by making sure it's a GC pointer.
*/
if (VBOX_FAILURE(rc))
rc = pCmdHlp->pfnEval(pCmdHlp, &VarAddr, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE));
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%DV + %#x", &VarAddr, (VarTmp.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPTE));
}
}
}
else
/*
* Range.
*/
unsigned i = cArgs;
while (i-- > 0)
{
{
break;
}
{
break;
}
}
/*
* Dump loop.
*/
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (index %#x):\n" : "%DV:\n", &VarAddr, off);
if (VBOX_FAILURE(rc))
return rc;
for (;;)
{
/*
* Read.
*/
if (VBOX_FAILURE(rc))
/*
* Display.
*/
if (off != ~0U)
{
off++;
}
"%08x big phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
else
"%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
if (VBOX_FAILURE(rc))
return rc;
/*
* Next
*/
if (cEntries-- <= 1)
break;
if (VBOX_FAILURE(rc))
}
return VINF_SUCCESS;
}
/**
* The 'dpdb' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDumpPageDirBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (!pVM)
if (VBOX_FAILURE(rc1))
return rc1;
return rc2;
}
/**
* The 'dpg*' commands.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDumpPageTable(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs != 1
|| (pCmd->pszCmd[3] != 'a' && !(paArgs[0].enmType == DBGCVAR_TYPE_NUMBER || DBGCVAR_ISPOINTER(paArgs[0].enmType)))
)
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. It might help to use the '%%' operator.\n");
if (!pVM)
/*
* Where to start dumping page directory entries?
*/
int rc;
unsigned off = ~0;
{
/*
* Get page directory and cr4.
*/
bool fHyper;
off = 0;
{
fHyper = false;
}
else
{
/** @todo fix hypervisor CR4 value! */
//u32CR4 = CPUMGetHyperCR4(pVM);
fHyper = true;
}
if (VBOX_FAILURE(rc))
/*
* Find page directory entry for the address.
* Make sure it's a flat address first.
*/
if (VBOX_FAILURE(rc))
rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, "%Dv + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE));
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "%Dv + %#x", &VarPTEAddr, (VarGCPtr.u.GCFlat >> PGDIR_SHIFT) * sizeof(VBOXPDE));
/*
* Now read the page directory entry for this GC address.
*/
if (VBOX_FAILURE(rc))
/*
* Check for presentness and handle big using dpd[gh].
*/
/*
* Calc page table address and setup offset and counts.
*/
rc = pCmdHlp->pfnEval(pCmdHlp, &VarPTEAddr, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK);
if (VBOX_FAILURE(rc))
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, fHyper ? "#%%%%%#x" : "%%%%%#x", Pde.u & X86_PDE_PG_MASK);
cEntries = 10;
}
else
VarPTEAddr = paArgs[0];
/*
* Range.
*/
unsigned i = cArgs;
while (i-- > 0)
{
{
break;
}
{
break;
}
}
/*
* Dump loop.
*/
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, off != ~0U ? "%DV (base %DV / index %#x):\n" : "%DV:\n", &VarPTEAddr, &VarGCPtr, off);
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
for (;;)
{
/*
* Read.
*/
if (VBOX_FAILURE(rc))
/*
* Display.
*/
if (off != ~0U)
{
off++;
}
"%08x 4kb phys=%08x %s %s %s %s %s avl=%02x %s %s %s %s\n",
if (VBOX_FAILURE(rc))
return rc;
/*
* Next
*/
if (cEntries-- <= 1)
break;
if (VBOX_FAILURE(rc))
if (VBOX_FAILURE(rc))
}
return VINF_SUCCESS;
}
/**
* The 'dptb' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdDumpPageTableBoth(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (!pVM)
if (VBOX_FAILURE(rc1))
return rc1;
return rc2;
}
/**
* The 'm' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdMemoryInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (!pVM)
if (VBOX_FAILURE(rc1))
return rc1;
if (VBOX_FAILURE(rc2))
return rc2;
if (VBOX_FAILURE(rc3))
return rc3;
return rc4;
}
/**
* Print formatted string.
*
* @param pHlp Pointer to this structure.
* @param pszFormat The format string.
* @param ... Arguments.
*/
{
}
/**
* Print formatted string.
*
* @param pHlp Pointer to this structure.
* @param pszFormat The format string.
* @param args Argument list.
*/
static DECLCALLBACK(void) dbgcCmdInfo_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
{
}
/**
* The 'info' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdInfo(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate input.
*/
if ( cArgs < 1
|| cArgs > 2
return pCmdHlp->pfnPrintf(pCmdHlp, NULL, "internal error: The parser doesn't do its job properly yet.. quote the string.\n");
if (!pVM)
/*
* Dump it.
*/
struct
{
int rc = DBGFR3Info(pVM, paArgs[0].u.pszString, cArgs == 2 ? paArgs[1].u.pszString : NULL, &Hlp.Hlp);
if (VBOX_FAILURE(rc))
return 0;
}
/**
* The 'log' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdLog(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (VBOX_SUCCESS(rc))
return VINF_SUCCESS;
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyGroups(%p,'%s')\n", pVM, paArgs[0].u.pszString);
}
/**
* The 'logdest' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdLogDest(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (VBOX_SUCCESS(rc))
return VINF_SUCCESS;
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyDestinations(%p,'%s')\n", pVM, paArgs[0].u.pszString);
}
/**
* The 'logflags' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdLogFlags(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
if (VBOX_SUCCESS(rc))
return VINF_SUCCESS;
return pCmdHlp->pfnVBoxError(pCmdHlp, rc, "DBGFR3LogModifyFlags(%p,'%s')\n", pVM, paArgs[0].u.pszString);
}
/**
* The 'format' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdFormat(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
LogFlow(("dbgcCmdFormat\n"));
static const char *apszRangeDesc[] =
{
"none", "bytes", "elements"
};
int rc;
{
{
case DBGCVAR_TYPE_UNKNOWN:
"Unknown variable type!\n");
break;
case DBGCVAR_TYPE_GC_FLAT:
"Guest flat address: %%%08x range %lld %s\n",
else
"Guest flat address: %%%08x\n",
break;
case DBGCVAR_TYPE_GC_FAR:
"Guest far address: %04x:%08x range %lld %s\n",
else
"Guest far address: %04x:%08x\n",
break;
case DBGCVAR_TYPE_GC_PHYS:
"Guest physical address: %%%%%08x range %lld %s\n",
else
"Guest physical address: %%%%%08x\n",
break;
case DBGCVAR_TYPE_HC_FLAT:
"Host flat address: %%%08x range %lld %s\n",
else
"Host flat address: %%%08x\n",
break;
case DBGCVAR_TYPE_HC_FAR:
"Host far address: %04x:%08x range %lld %s\n",
else
"Host far address: %04x:%08x\n",
break;
case DBGCVAR_TYPE_HC_PHYS:
"Host physical address: %VHp range %lld %s\n",
else
"Host physical address: %VHp\n",
break;
case DBGCVAR_TYPE_STRING:
"String, %lld bytes long: %s\n",
break;
case DBGCVAR_TYPE_NUMBER:
"Number: hex %llx dec 0i%lld oct 0t%llo range %lld %s\n",
else
"Number: hex %llx dec 0i%lld oct 0t%llo\n",
break;
default:
"Invalid argument type %d\n",
break;
}
} /* arg loop */
return 0;
}
/**
* List near symbol.
*
* @returns VBox status code.
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param pArg Pointer to the address or symbol to lookup.
*/
{
dbgcVarSetGCFlat(pResult, 0);
int rc;
{
/*
* Lookup the symbol address.
*/
if (VBOX_FAILURE(rc))
rc = pCmdHlp->pfnPrintf(pCmdHlp, NULL, "%VGv %s\n", (RTGCUINTPTR)Symbol.Value, Symbol.szName); /** @todo remove the RTUINGCPTR cast once DBGF got correct interfaces! */
}
else
{
/*
* Convert it to a flat GC address and lookup that address.
*/
if (VBOX_FAILURE(rc))
RTGCINTPTR offDisp = 0;
if (VBOX_FAILURE(rc))
if (!offDisp)
else if (offDisp > 0)
else
{
}
else
{
}
}
return rc;
}
/**
* The 'ln' (listnear) command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdListNear(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
dbgcVarSetGCFlat(pResult, 0);
if (!cArgs)
{
/*
* Current cs:eip symbol.
*/
if (VBOX_FAILURE(rc))
}
/*
* Iterate arguments.
*/
{
if (VBOX_FAILURE(rc))
return rc;
}
return VINF_SUCCESS;
}
/**
* The 'loadsyms' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdLoadSyms(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Validate the parsing and make sense of the input.
* This is a mess as usual because we don't trust the parser yet.
*/
if ( cArgs < 1
{
AssertMsgFailed(("Parse error, first argument required to be string!\n"));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
RTGCUINTPTR Delta = 0;
RTGCUINTPTR ModuleAddress = 0;
unsigned cbModule = 0;
if (cArgs > 1)
{
unsigned iArg = 1;
{
iArg++;
}
{
{
AssertMsgFailed(("Parse error, module argument required to be string!\n"));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
iArg++;
{
{
AssertMsgFailed(("Parse error, module argument required to be GC pointer!\n"));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
if (VBOX_FAILURE(rc))
iArg++;
{
{
AssertMsgFailed(("Parse error, module argument required to be an interger!\n"));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
iArg++;
{
AssertMsgFailed(("Parse error, too many arguments!\n"));
return VERR_PARSE_TOO_MANY_ARGUMENTS;
}
}
}
}
}
/*
* Call the debug info manager about this loading...
*/
if (VBOX_FAILURE(rc))
return VINF_SUCCESS;
}
/**
* The 'set' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdSet(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/* parse sanity check. */
AssertMsg(paArgs[0].enmType == DBGCVAR_TYPE_STRING, ("expected string not %d as first arg!\n", paArgs[0].enmType));
return VERR_PARSE_INCORRECT_ARG_TYPE;
/*
* A variable must start with an alpha chars and only contain alpha numerical chars.
*/
"syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*'!", paArgs[0].u.pszString);
*pszVar++;
if (*pszVar)
"syntax error: Invalid variable name '%s'. Variable names must match regex '[_a-zA-Z][_a-zA-Z0-9*]'!", paArgs[0].u.pszString);
/*
* Calc variable size.
*/
/*
* Look for existing one.
*/
{
{
/*
* Update existing variable.
*/
if (!pv)
return VERR_PARSE_NO_MEMORY;
pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
return 0;
}
}
/*
* Allocate another.
*/
pVar->Var.u.pszString = (char *)memcpy(&pVar->szName[paArgs[0].u64Range + 1], paArgs[1].u.pszString, (size_t)paArgs[1].u64Range + 1);
/* need to reallocate the pointer array too? */
{
if (!pv)
{
return VERR_PARSE_NO_MEMORY;
}
}
return 0;
}
/**
* The 'unset' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdUnset(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Don't trust the parser.
*/
for (unsigned i = 0; i < cArgs; i++)
{
AssertMsgFailed(("expected strings only. (arg=%d)!\n", i));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
/*
* Iterate the variables and unset them.
*/
{
/*
* Look up the variable.
*/
{
{
/*
* Shuffle the array removing this entry.
*/
}
} /* lookup */
} /* arg loop */
return 0;
}
/**
* The 'loadvars' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdLoadVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
/*
* Don't trust the parser.
*/
if ( cArgs != 1
{
AssertMsgFailed(("Expected one string exactly!\n"));
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
/*
* Iterate the variables and unset them.
*/
if (pFile)
{
char szLine[4096];
{
/* Strip it. */
psz++;
psz[i--] ='\0';
/* Execute it if not comment or empty line. */
if ( *psz != '\0'
&& *psz != '#'
&& *psz != ';')
{
}
}
}
else
return 0;
}
/**
* The 'showvars' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdShowVars(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
{
if (!rc)
if (rc)
return rc;
}
return 0;
}
/**
* The 'harakiri' command.
*
* @returns VBox status.
* @param pCmd Pointer to the command descriptor (as registered).
* @param pCmdHlp Pointer to command helper functions.
* @param pVM Pointer to the current VM (if any).
* @param paArgs Pointer to (readonly) array of arguments.
* @param cArgs Number of arguments in the array.
*/
static DECLCALLBACK(int) dbgcCmdHarakiri(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PVM pVM, PCDBGCVAR paArgs, unsigned cArgs, PDBGCVAR pResult)
{
Log(("dbgcCmdHarakiri\n"));
for (;;)
exit(126);
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// B u l t i n S y m b o l s
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/**
* Get builtin register symbol.
*
* The uUser is special for these symbol descriptors. See the SYMREG_* \#defines.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pSymDesc Pointer to the symbol descriptor.
* @param pCmdHlp Pointer to the command callback structure.
* @param enmType The result type.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcSymGetReg(PCDBGCSYM pSymDesc, PDBGCCMDHLP pCmdHlp, DBGCVARTYPE enmType, PDBGCVAR pResult)
{
/*
* pVM is required.
*/
/*
* Get the right CPU context.
*/
int rc;
else
if (VBOX_FAILURE(rc))
return rc;
/*
* Get the value.
*/
{
case 6: u64 = *(uint32_t *)pvValue | ((uint64_t)*(uint16_t *)((char *)pvValue + sizeof(uint32_t)) << 32); break;
default:
return VERR_PARSE_NOT_IMPLEMENTED;
}
/*
* Construct the desired result.
*/
if (enmType == DBGCVAR_TYPE_ANY)
switch (enmType)
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_FAR:
{
case 4:
{
}
else
{
}
break;
case 6:
{
}
else
{
}
break;
default:
return VERR_PARSE_BAD_RESULT_TYPE;
}
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_FAR:
{
case 4:
{
}
else
{
}
break;
case 6:
{
}
else
{
}
break;
default:
return VERR_PARSE_BAD_RESULT_TYPE;
}
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_BAD_RESULT_TYPE;
}
return 0;
}
/**
* Set builtin register symbol.
*
* The uUser is special for these symbol descriptors. See the SYMREG_* #defines.
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pSymDesc Pointer to the symbol descriptor.
* @param pCmdHlp Pointer to the command callback structure.
* @param pValue The value to assign the symbol.
*/
{
/*
* pVM is required.
*/
/*
* Get the right CPU context.
*/
int rc;
else
if (VBOX_FAILURE(rc))
return rc;
/*
* Check the new value.
*/
/*
* Set the value.
*/
{
case 1:
break;
case 2:
break;
case 4:
break;
case 6:
break;
case 8:
break;
default:
return VERR_PARSE_NOT_IMPLEMENTED;
}
return VINF_SUCCESS;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// O p e r a t o r s
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/**
* Minus (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpMinus\n"));
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_FAR:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_FAR:
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_STRING:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Pluss (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpPluss\n"));
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_STRING:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Boolean not (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpBooleanNot\n"));
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_FAR:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_FAR:
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_STRING:
break;
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Bitwise not (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpBitwiseNot\n"));
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_FAR:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_FAR:
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_STRING:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Reference variable (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpVar: %s\n", pArg->u.pszString));
/*
* Parse sanity.
*/
return VERR_PARSE_INCORRECT_ARG_TYPE;
/*
* Lookup the variable.
*/
{
{
return 0;
}
}
return VERR_PARSE_VARIABLE_NOT_FOUND;
}
/**
* Flat address (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpAddrFlat\n"));
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
return 0;
case DBGCVAR_TYPE_GC_FAR:
if (VBOX_SUCCESS(rc))
return 0;
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_PHYS:
//rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
return VERR_PARSE_INCORRECT_ARG_TYPE;
case DBGCVAR_TYPE_HC_FLAT:
return 0;
case DBGCVAR_TYPE_HC_FAR:
return VERR_PARSE_INCORRECT_ARG_TYPE;
case DBGCVAR_TYPE_HC_PHYS:
if (VBOX_SUCCESS(rc))
return 0;
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_NUMBER:
return 0;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
}
/**
* Physical address (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpAddrPhys\n"));
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types! */
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_FAR:
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types! */
}
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_PHYS:
return 0;
case DBGCVAR_TYPE_HC_FLAT:
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types! */
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_HC_FAR:
return VERR_PARSE_INCORRECT_ARG_TYPE;
case DBGCVAR_TYPE_HC_PHYS:
return 0;
case DBGCVAR_TYPE_NUMBER:
return 0;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Physical host address (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpAddrPhys\n"));
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types. */
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_FAR:
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types. */
}
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_PHYS:
if (VBOX_SUCCESS(rc))
return 0;
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_HC_FLAT:
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types! */
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_HC_FAR:
return VERR_PARSE_INCORRECT_ARG_TYPE;
case DBGCVAR_TYPE_HC_PHYS:
return 0;
case DBGCVAR_TYPE_NUMBER:
return 0;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Host address (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpAddrHost\n"));
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types. */
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_FAR:
if (VBOX_SUCCESS(rc))
{
if (VBOX_SUCCESS(rc))
return 0;
/** @todo more memory types. */
}
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_GC_PHYS:
if (VBOX_SUCCESS(rc))
return 0;
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_HC_FLAT:
return 0;
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
/** @todo !*/
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_NUMBER:
return 0;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
}
/**
* Bitwise not (unary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg The argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpAddrFar(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
// LogFlow(("dbgcOpAddrFar\n"));
int rc;
{
case DBGCVAR_TYPE_STRING:
if (VBOX_FAILURE(rc))
return rc;
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
/* common code for the two types we support. */
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_STRING:
{
if (VBOX_FAILURE(rc))
return rc;
break;
}
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_UNKNOWN:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
return 0;
}
/**
* Multiplication operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpMult(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpMult\n"));
return -1;
}
/**
* Division operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
{
LogFlow(("dbgcOpDiv\n"));
return -1;
}
/**
* Modulus operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
{
LogFlow(("dbgcOpMod\n"));
return -1;
}
/**
* Addition operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpAdd\n"));
/*
* An addition operation will return (when possible) the left side type in the
* expression. We make an omission for numbers, where we'll take the right side
* type instead. An expression where only the left hand side is a string we'll
* use the right hand type assuming that the string is a symbol.
*/
{
}
{
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
}
int rc;
{
/*
* GC Flat
*/
case DBGCVAR_TYPE_GC_FLAT:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
default:
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* GC Far
*/
case DBGCVAR_TYPE_GC_FAR:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
case DBGCVAR_TYPE_NUMBER:
break;
default:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* GC Phys
*/
case DBGCVAR_TYPE_GC_PHYS:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
default:
if (VBOX_FAILURE(rc))
return rc;
return VERR_PARSE_INVALID_OPERATION;
break;
}
break;
/*
* HC Flat
*/
case DBGCVAR_TYPE_HC_FLAT:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
/*
* HC Far
*/
case DBGCVAR_TYPE_HC_FAR:
{
case DBGCVAR_TYPE_NUMBER:
break;
default:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* HC Phys
*/
case DBGCVAR_TYPE_HC_PHYS:
if (VBOX_FAILURE(rc))
return rc;
break;
/*
* Numbers (see start of function)
*/
case DBGCVAR_TYPE_NUMBER:
{
case DBGCVAR_TYPE_STRING:
if (VBOX_FAILURE(rc))
return rc;
case DBGCVAR_TYPE_NUMBER:
break;
default:
return VERR_PARSE_INVALID_OPERATION;
}
break;
default:
return VERR_PARSE_INVALID_OPERATION;
}
return 0;
}
/**
* Subtration operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
{
// LogFlow(("dbgcOpSub\n"));
/*
* An subtraction operation will return the left side type in the expression.
* However, if the left hand side is a number and the right hand a pointer of
* some kind we'll convert the left hand side to the same type as the right hand.
* Any strings will be attempted resolved as symbols.
*/
{
if (VBOX_FAILURE(rc))
return rc;
}
{
{
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_GC_FAR:
break;
case DBGCVAR_TYPE_HC_FAR:
break;
default:
case DBGCVAR_TYPE_STRING:
AssertMsgFailed(("Can't happen\n"));
break;
}
if (enmType != DBGCVAR_TYPE_STRING)
{
if (VBOX_FAILURE(rc))
return rc;
}
}
{
{
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
default:
case DBGCVAR_TYPE_STRING:
AssertMsgFailed(("Can't happen\n"));
break;
}
if (pOp)
{
if (VBOX_FAILURE(rc))
return rc;
}
}
/*
* Normal processing.
*/
int rc;
{
/*
* GC Flat
*/
case DBGCVAR_TYPE_GC_FLAT:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
default:
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* GC Far
*/
case DBGCVAR_TYPE_GC_FAR:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
case DBGCVAR_TYPE_NUMBER:
break;
default:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* GC Phys
*/
case DBGCVAR_TYPE_GC_PHYS:
{
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_INVALID_OPERATION;
default:
if (VBOX_FAILURE(rc))
return rc;
return VERR_PARSE_INVALID_OPERATION;
break;
}
break;
/*
* HC Flat
*/
case DBGCVAR_TYPE_HC_FLAT:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
/*
* HC Far
*/
case DBGCVAR_TYPE_HC_FAR:
{
case DBGCVAR_TYPE_NUMBER:
break;
default:
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
if (VBOX_FAILURE(rc))
return rc;
break;
}
break;
/*
* HC Phys
*/
case DBGCVAR_TYPE_HC_PHYS:
if (VBOX_FAILURE(rc))
return rc;
break;
/*
* Numbers (see start of function)
*/
case DBGCVAR_TYPE_NUMBER:
{
case DBGCVAR_TYPE_STRING:
if (VBOX_FAILURE(rc))
return rc;
case DBGCVAR_TYPE_NUMBER:
break;
default:
return VERR_PARSE_INVALID_OPERATION;
}
break;
default:
return VERR_PARSE_INVALID_OPERATION;
}
return 0;
}
/**
* Bitwise shift left operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBitwiseShiftLeft(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBitwiseShiftLeft\n"));
return -1;
}
/**
* Bitwise shift right operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBitwiseShiftRight(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBitwiseShiftRight\n"));
return -1;
}
/**
* Bitwise and operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBitwiseAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBitwiseAnd\n"));
return -1;
}
/**
* Bitwise exclusive or operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBitwiseXor(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBitwiseXor\n"));
return -1;
}
/**
* Bitwise inclusive or operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBitwiseOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBitwiseOr\n"));
return -1;
}
/**
* Boolean and operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBooleanAnd(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBooleanAnd\n"));
return -1;
}
/**
* Boolean or operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpBooleanOr(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
LogFlow(("dbgcOpBooleanOr\n"));
return -1;
}
/**
* Range to operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpRangeLength(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
// LogFlow(("dbgcOpRangeLength\n"));
/*
* Make result. Strings needs to be resolved into symbols.
*/
{
if (VBOX_FAILURE(rc))
return rc;
}
else
/*
* Convert 2nd argument to element count.
*/
{
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_STRING:
{
if (VBOX_FAILURE(rc))
return rc;
break;
}
default:
return VERR_PARSE_INVALID_OPERATION;
}
return VINF_SUCCESS;
}
/**
* Range to operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpRangeLengthBytes(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
// LogFlow(("dbgcOpRangeLengthBytes\n"));
if (VBOX_SUCCESS(rc))
return rc;
}
/**
* Range to operator (binary).
*
* @returns 0 on success.
* @returns VBox evaluation / parsing error code on failure.
* The caller does the bitching.
* @param pDbgc Debugger console instance data.
* @param pArg1 The first argument.
* @param pArg2 The 2nd argument.
* @param pResult Where to store the result.
*/
static DECLCALLBACK(int) dbgcOpRangeTo(PDBGC pDbgc, PCDBGCVAR pArg1, PCDBGCVAR pArg2, PDBGCVAR pResult)
{
// LogFlow(("dbgcOpRangeTo\n"));
/*
* Calc number of bytes between the two args.
*/
if (VBOX_FAILURE(rc))
return rc;
/*
* Use the diff as the range of Arg1.
*/
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_FLAT:
break;
case DBGCVAR_TYPE_HC_PHYS:
break;
case DBGCVAR_TYPE_NUMBER:
break;
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_HC_FAR:
default:
AssertMsgFailed(("Impossible!\n"));
return VERR_PARSE_INVALID_OPERATION;
}
return 0;
}
/**
* Output callback.
*
* @returns number of bytes written.
* @param pvArg User argument.
* @param pachChars Pointer to an array of utf-8 characters.
* @param cbChars Number of bytes in the character array pointed to by pachChars.
*/
{
if (cbChars)
{
if (VBOX_FAILURE(rc))
{
cbChars = 0;
}
}
return cbChars;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// C a l l b a c k H e l p e r s
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/**
* Command helper for writing text to the debug console.
*
* @returns VBox status.
* @param pCmdHlp Pointer to the command callback structure.
* @param pvBuf What to write.
* @param cbBuf Number of bytes to write.
* @param pcbWritten Where to store the number of bytes actually written.
* If NULL the entire buffer must be successfully written.
*/
static DECLCALLBACK(int) dbgcHlpWrite(PDBGCCMDHLP pCmdHlp, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)
{
}
/**
* Command helper for writing formatted text to the debug console.
*
* @returns VBox status.
* @param pCmdHlp Pointer to the command callback structure.
* @param pcb Where to store the number of bytes written.
* @param pszFormat The format string.
* This is using the log formatter, so it's format extensions can be used.
* @param ... Arguments specified in the format string.
*/
static DECLCALLBACK(int) dbgcHlpPrintf(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, ...)
{
/*
* Do the formatting and output.
*/
return rc;
}
/**
* Callback to format non-standard format specifiers.
*
* @returns The number of bytes formatted.
* @param pvArg Formatter argument.
* @param pfnOutput Pointer to output function.
* @param pvArgOutput Argument for the output function.
* @param ppszFormat Pointer to the format string pointer. Advance this till the char
* after the format specifier.
* @param pArgs Pointer to the argument list. Use this to fetch the arguments.
* @param cchWidth Format Width. -1 if not specified.
* @param cchPrecision Format Precision. -1 if not specified.
* @param fFlags Flags (RTSTR_NTFS_*).
* @param chArgSize The argument size specifier, 'l' or 'L'.
*/
static DECLCALLBACK(int) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
const char **ppszFormat, va_list *pArgs, int cchWidth, int cchPrecision, unsigned fFlags, char chArgSize)
{
if (**ppszFormat != 'D')
{
(*ppszFormat)++;
return 0;
}
(*ppszFormat)++;
switch (**ppszFormat)
{
/*
* Print variable without range.
* The argument is a const pointer to the variable.
*/
case 'V':
{
(*ppszFormat)++;
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x", pVar->u.GCFar.sel, pVar->u.GCFar.off);
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x", pVar->u.HCFar.sel, pVar->u.HCFar.off);
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_NUMBER:
case DBGCVAR_TYPE_UNKNOWN:
default:
}
}
/*
* Print variable with range.
* The argument is a const pointer to the variable.
*/
case 'v':
{
(*ppszFormat)++;
char szRange[32];
switch (pVar->enmRangeType)
{
case DBGCVAR_RANGE_NONE:
szRange[0] = '\0';
break;
case DBGCVAR_RANGE_ELEMENTS:
break;
case DBGCVAR_RANGE_BYTES:
break;
}
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%04x:%08x%s", pVar->u.GCFar.sel, pVar->u.GCFar.off, szRange);
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "%%#%VHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
case DBGCVAR_TYPE_HC_FAR:
return RTStrFormat(pfnOutput, pvArgOutput, NULL, 0, "#%04x:%08x%s", pVar->u.HCFar.sel, pVar->u.HCFar.off, szRange);
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_NUMBER:
case DBGCVAR_TYPE_UNKNOWN:
default:
}
}
default:
return 0;
}
}
/**
* Command helper for writing formatted text to the debug console.
*
* @returns VBox status.
* @param pCmdHlp Pointer to the command callback structure.
* @param pcb Where to store the number of bytes written.
* @param pszFormat The format string.
* This is using the log formatter, so it's format extensions can be used.
* @param args Arguments specified in the format string.
*/
static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
{
/*
* Do the formatting and output.
*/
if (pcbWritten)
*pcbWritten = cb;
}
/**
* Reports an error from a DBGF call.
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to command helpers.
* @param rc The VBox status code returned by a DBGF call.
* @param pszFormat Format string for additional messages. Can be NULL.
* @param ... Format arguments, optional.
*/
static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
{
switch (rc)
{
case VINF_SUCCESS:
break;
default:
break;
}
return rc;
}
/**
* Reports an error from a DBGF call.
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to command helpers.
* @param rc The VBox status code returned by a DBGF call.
* @param pszFormat Format string for additional messages. Can be NULL.
* @param ... Format arguments, optional.
*/
{
return rcRet;
}
/**
* Command helper for reading memory specified by a DBGC variable.
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to the command callback structure.
* @param pVM VM handle if GC or physical HC address.
* @param pvBuffer Where to store the read data.
* @param cbRead Number of bytes to read.
* @param pVarPointer DBGC variable specifying where to start reading.
* @param pcbRead Where to store the number of bytes actually read.
* This optional, but it's useful when read GC virtual memory where a
* page in the requested range might not be present.
* If not specified not-present failure or end of a HC physical page
* will cause failure.
*/
static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
{
/*
* Dummy check.
*/
if (cbRead == 0)
{
if (*pcbRead)
*pcbRead = 0;
return VINF_SUCCESS;
}
/*
* Convert Far addresses getting size and the correct base address.
*/
switch (pVarPointer->enmType)
{
case DBGCVAR_TYPE_GC_FAR:
{
if (VBOX_FAILURE(rc))
return rc;
{
if (!pcbRead)
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
break;
}
case DBGCVAR_TYPE_HC_FAR:
/* not supported yet! */
return VERR_NOT_IMPLEMENTED;
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
break;
default:
return VERR_NOT_IMPLEMENTED;
}
/*
* Copy page by page.
*/
for (;;)
{
/*
* Calc read size.
*/
switch (pVarPointer->enmType)
{
case DBGCVAR_TYPE_HC_FLAT: cb = RT_MIN(cb, PAGE_SIZE - ((uintptr_t)Var.u.pvHCFlat & PAGE_OFFSET_MASK)); break;
case DBGCVAR_TYPE_HC_PHYS: cb = RT_MIN(cb, PAGE_SIZE - ((size_t)Var.u.HCPhys & PAGE_OFFSET_MASK)); break; /* size_t: MSC has braindead loss of data warnings! */
default: break;
}
/*
* Perform read.
*/
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
{
if (VBOX_SUCCESS(rc))
{
/** @todo protect this!!! */
rc = 0;
}
else
break;
}
default:
}
/*
* Check for failure.
*/
if (VBOX_FAILURE(rc))
{
return VINF_SUCCESS;
return rc;
}
/*
* Next.
*/
if (!cbLeft)
break;
if (VBOX_FAILURE(rc))
{
return VINF_SUCCESS;
return rc;
}
}
/*
* Done
*/
if (pcbRead)
return 0;
}
/**
* Command helper for writing memory specified by a DBGC variable.
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to the command callback structure.
* @param pVM VM handle if GC or physical HC address.
* @param pvBuffer What to write.
* @param cbWrite Number of bytes to write.
* @param pVarPointer DBGC variable specifying where to start reading.
* @param pcbWritten Where to store the number of bytes written.
* This is optional. If NULL be aware that some of the buffer
* might have been written to the specified address.
*/
static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
{
return VERR_NOT_IMPLEMENTED;
}
/**
* Evaluates an expression.
* (Hopefully the parser and functions are fully reentrant.)
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to the command callback structure.
* @param pResult Where to store the result.
* @param pszExpr The expression. Format string with the format DBGC extensions.
* @param ... Format arguments.
*/
static DECLCALLBACK(int) dbgcHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...)
{
/*
* Format the expression.
*/
char szExprFormatted[2048];
size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, args);
/* ignore overflows. */
}
/**
* Executes one command expression.
* (Hopefully the parser and functions are fully reentrant.)
*
* @returns VBox status code appropriate to return from a command.
* @param pCmdHlp Pointer to the command callback structure.
* @param pszExpr The expression. Format string with the format DBGC extensions.
* @param ... Format arguments.
*/
{
/* Save the scratch state. */
/*
* Format the expression.
*/
size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, pDbgc->pszScratch, cbScratch, pszExpr, args);
return VERR_BUFFER_OVERFLOW;
/*
* Execute the command.
* We save and restore the arg index and scratch buffer pointer.
*/
/* Restore the scratch state. */
return rc;
}
/**
* Converts a DBGC variable to a DBGF address structure.
*
* @returns VBox status code.
* @param pCmdHlp Pointer to the command callback structure.
* @param pVar The variable to convert.
* @param pAddress The target address.
*/
static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
{
}
/**
* Converts a DBGC variable to a boolean.
*
* @returns VBox status code.
* @param pCmdHlp Pointer to the command callback structure.
* @param pVar The variable to convert.
* @param pf Where to store the boolean.
*/
{
{
case DBGCVAR_TYPE_STRING:
{
*pf = true;
return VINF_SUCCESS;
}
{
*pf = false;
return VINF_SUCCESS;
}
return VERR_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_SYMBOL:
default:
return VERR_PARSE_INCORRECT_ARG_TYPE;
}
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// V a r i a b l e M a n i p u l a t i o n
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/** @todo move me!*/
{
if (pVar)
{
}
}
/** @todo move me!*/
{
if (pVar)
{
}
}
/** @todo move me!*/
{
if (pVar)
{
if (pVar2)
else
{
}
}
}
/** @todo move me!*/
{
if (pVar)
{
}
}
/** @todo move me!*/
{
if (pVar)
{
}
}
/**
* Converts a DBGC variable to a DBGF address.
*
* @returns VBox status code.
* @param pDbgc The DBGC instance.
* @param pVar The variable.
* @param pAddress Where to store the address.
*/
{
{
case DBGCVAR_TYPE_GC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
{
if (VBOX_FAILURE(rc))
return rc;
}
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
default:
return VERR_PARSE_CONVERSION_FAILED;
}
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// B r e a k p o i n t M a n a g e m e n t
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/**
* Adds a breakpoint to the DBGC breakpoint list.
*/
{
/*
* Check if it already exists.
*/
if (pBp)
return VERR_DBGC_BP_EXISTS;
/*
* Add the breakpoint.
*/
if (pszCmd)
if (!pBp)
return VERR_NO_MEMORY;
if (cchCmd)
else
return VINF_SUCCESS;
}
/**
* Updates the a breakpoint.
*
* @returns VBox status code.
* @param pDbgc The DBGC instance.
* @param iBp The breakpoint to update.
* @param pszCmd The new command.
*/
{
/*
* Find the breakpoint.
*/
if (!pBp)
return VERR_DBGC_BP_NOT_FOUND;
/*
* Do we need to reallocate?
*/
if (pszCmd)
else
{
{
}
else
{
/*
* Yes, let's do it the simple way...
*/
}
}
return VINF_SUCCESS;
}
/**
* Deletes a breakpoint.
*
* @returns VBox status code.
* @param pDbgc The DBGC instance.
* @param iBp The breakpoint to delete.
*/
{
/*
* Search thru the list, when found unlink and free it.
*/
{
{
if (pBpPrev)
else
return VINF_SUCCESS;
}
}
return VERR_DBGC_BP_NOT_FOUND;
}
/**
* Get a breakpoint.
*
* @returns Pointer to the breakpoint.
* @returns NULL if the breakpoint wasn't found.
* @param pDbgc The DBGC instance.
* @param iBp The breakpoint to get.
*/
{
/*
* Enumerate the list.
*/
return pBp;
return NULL;
}
/**
* Executes the command of a breakpoint.
*
* @returns VINF_DBGC_BP_NO_COMMAND if there is no command associated with the breakpoint.
* @returns VERR_DBGC_BP_NOT_FOUND if the breakpoint wasn't found.
* @returns VERR_BUFFER_OVERFLOW if the is not enough space in the scratch buffer for the command.
* @returns VBox status code from dbgcProcessCommand() other wise.
* @param pDbgc The DBGC instance.
* @param iBp The breakpoint to execute.
*/
{
/*
* Find the breakpoint.
*/
if (!pBp)
return VERR_DBGC_BP_NOT_FOUND;
/*
* Anything to do?
*/
return VINF_DBGC_BP_NO_COMMAND;
/*
* Execute the command.
* This means copying it to the scratch buffer and process it as if it
* were user input. We must save and restore the state of the scratch buffer.
*/
/* Save the scratch state. */
/* Copy the command to the scratch buffer. */
return VERR_BUFFER_OVERFLOW;
/* Execute the command. */
/* Restore the scratch state. */
return rc;
}
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
//
//
// I n p u t , p a r s i n g a n d l o g g i n g
//
//
//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//\\//
/**
* Prints any log lines from the log buffer.
*
* The caller must not call function this unless pDbgc->fLog is set.
*
* @returns VBox status. (output related)
* @param pDbgc Debugger console instance data.
*/
{
/** @todo */
return 0;
}
/**
* Handle input buffer overflow.
*
* Will read any available input looking for a '\n' to reset the buffer on.
*
* @returns VBox status.
* @param pDbgc Debugger console instance data.
*/
{
/*
* Assert overflow status and reset the input buffer.
*/
if (!pDbgc->fInputOverflow)
{
pDbgc->fInputOverflow = true;
pDbgc->cInputLines = 0;
}
/*
* Eat input till no more or there is a '\n'.
* When finding a '\n' we'll continue normal processing.
*/
{
int rc = pDbgc->pBack->pfnRead(pDbgc->pBack, &pDbgc->achInput[0], sizeof(pDbgc->achInput) - 1, &cbRead);
if (VBOX_FAILURE(rc))
return rc;
if (psz)
{
pDbgc->fInputOverflow = false;
pDbgc->cInputLines = 0;
break;
}
}
return 0;
}
/**
* Read input and do some preprocessing.
*
* @returns VBox status.
* In addition to the iWrite and achInput, cInputLines is maintained.
* In case of an input overflow the fInputOverflow flag will be set.
* @param pDbgc Debugger console instance data.
*/
{
/*
* We have ready input.
* Read it till we don't have any or we have a full input buffer.
*/
int rc = 0;
do
{
/*
* More available buffer space?
*/
else
if (!cbLeft)
{
/* overflow? */
if (!pDbgc->cInputLines)
break;
}
/*
* Read one char and interpret it.
*/
char achRead[128];
if (VBOX_FAILURE(rc))
return rc;
while (cbRead-- > 0)
{
switch (ch)
{
/*
* Ignore.
*/
case '\0':
case '\r':
case '\a':
break;
/*
* Backspace.
*/
case '\b':
Log2(("DBGC: backspace\n"));
{
else
}
break;
/*
* Add char to buffer.
*/
case '\t':
case '\n':
case ';':
switch (ch)
{
}
default:
break;
}
}
/* Terminate it to make it easier to read in the debugger. */
return rc;
}
/**
* Finds a builtin symbol.
* @returns Pointer to symbol descriptor on success.
* @returns NULL on failure.
* @param pDbgc The debug console instance.
* @param pszSymbol The symbol name.
*/
{
/** @todo externally registered symbols. */
return NULL;
}
/**
* Resolves a symbol (or tries to do so at least).
*
* @returns 0 on success.
* @returns VBox status on failure.
* @param pDbgc The debug console instance.
* @param pszSymbol The symbol name.
* @param enmType The result type.
* @param pResult Where to store the result.
*/
{
/*
* Builtin?
*/
if (pSymDesc)
{
return VERR_PARSE_WRITEONLY_SYMBOL;
}
/*
* Ask PDM.
*/
/** @todo resolve symbols using PDM. */
/*
* Ask the debug info manager.
*/
if (VBOX_SUCCESS(rc))
{
/*
* Default return is a flat gc address.
*/
switch (enmType)
{
/* nothing to do. */
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_ANY:
return VINF_SUCCESS;
/* simply make it numeric. */
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
/* cast it. */
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
default:
return VERR_INVALID_PARAMETER;
}
}
return VERR_PARSE_NOT_IMPLEMENTED;
}
/**
* Finds a routine.
*
* @returns Pointer to the command descriptor.
* If the request was for an external command, the caller is responsible for
* unlocking the external command list.
* @returns NULL if not found.
* @param pDbgc The debug console instance.
* @param pachName Pointer to the routine string (not terminated).
* @param cchName Length of the routine name.
* @param fExternal Whether or not the routine is external.
*/
static PCDBGCCMD dbgcRoutineLookup(PDBGC pDbgc, const char *pachName, size_t cchName, bool fExternal)
{
if (!fExternal)
{
{
}
}
else
{
{
{
}
}
}
return NULL;
}
/**
* Searches for an operator descriptor which matches the start of
* the expression given us.
*
* @returns Pointer to the operator on success.
* @param pDbgc The debug console instance.
* @param pszExpr Pointer to the expression string which might start with an operator.
* @param fPreferBinary Whether to favour binary or unary operators.
* Caller must assert that it's the disired type! Both types will still
* be returned, this is only for resolving duplicates.
* @param chPrev The previous char. Some operators requires a blank in front of it.
*/
static PCDBGCOP dbgcOperatorLookup(PDBGC pDbgc, const char *pszExpr, bool fPreferBinary, char chPrev)
{
{
{
/*
* Check that we don't mistake it for some other operator which have more chars.
*/
unsigned j;
break;
continue; /* we'll catch it later. (for theoretical +,++,+++ cases.) */
/*
* Prefered type?
*/
break;
}
}
if (pOp)
return pOp;
}
{
/*
* Removing any quoting and escapings.
*/
{
return VERR_PARSE_UNBALANCED_QUOTE;
cchExpr--;
pszExpr++;
/** @todo string unescaping. */
}
/*
* Make the argument.
*/
return 0;
}
{
/*
* Convert to number.
*/
char ch;
{
unsigned u = ch - '0';
if (u < 10 && u < uBase)
else
return VERR_PARSE_INVALID_NUMBER;
/* check for overflow - ARG!!! How to detect overflow correctly!?!?!? */
return VERR_PARSE_NUMBER_TOO_BIG;
/* next */
pszExpr++;
}
/*
* Initialize the argument.
*/
return 0;
}
/**
* Match variable and variable descriptor, promoting the variable if necessary.
*
* @returns VBox status code.
* @param pDbgc Debug console instanace.
* @param pVar Variable.
* @param pVarDesc Variable descriptor.
*/
{
/*
* (If match or promoted to match, return, else break.)
*/
switch (pVarDesc->enmCategory)
{
/*
* Anything goes
*/
case DBGCVAR_CAT_ANY:
return VINF_SUCCESS;
/*
* Pointer with and without range.
* We can try resolve strings and symbols as symbols and
* promote numbers to flat GC pointers.
*/
return VERR_PARSE_NO_RANGE_ALLOWED;
/* fallthru */
case DBGCVAR_CAT_POINTER:
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_STRING:
{
if (VBOX_SUCCESS(rc))
{
/* deal with range */
{
}
return rc;
}
break;
}
case DBGCVAR_TYPE_NUMBER:
{
return VINF_SUCCESS;
}
default:
break;
}
break;
/*
* GC pointer with and without range.
* We can try resolve strings and symbols as symbols and
* promote numbers to flat GC pointers.
*/
return VERR_PARSE_NO_RANGE_ALLOWED;
/* fallthru */
case DBGCVAR_CAT_GC_POINTER:
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_FAR:
case DBGCVAR_TYPE_HC_PHYS:
return VERR_PARSE_CONVERSION_FAILED;
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_STRING:
{
if (VBOX_SUCCESS(rc))
{
/* deal with range */
{
}
return rc;
}
break;
}
case DBGCVAR_TYPE_NUMBER:
{
return VINF_SUCCESS;
}
default:
break;
}
break;
/*
* Number with or without a range.
* Numbers can be resolved from symbols, but we cannot demote a pointer
* to a number.
*/
return VERR_PARSE_NO_RANGE_ALLOWED;
/* fallthru */
case DBGCVAR_CAT_NUMBER:
{
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_STRING:
{
if (VBOX_SUCCESS(rc))
{
return rc;
}
break;
}
default:
break;
}
break;
/*
* Strings can easily be made from symbols (and of course strings).
* We could consider reformatting the addresses and numbers into strings later...
*/
case DBGCVAR_CAT_STRING:
{
case DBGCVAR_TYPE_SYMBOL:
/* fallthru */
case DBGCVAR_TYPE_STRING:
return VINF_SUCCESS;
default:
break;
}
break;
/*
* Symol is pretty much the same thing as a string (at least until we actually implement it).
*/
case DBGCVAR_CAT_SYMBOL:
{
case DBGCVAR_TYPE_STRING:
/* fallthru */
case DBGCVAR_TYPE_SYMBOL:
return VINF_SUCCESS;
default:
break;
}
break;
/*
* Anything else is illegal.
*/
default:
break;
}
return VERR_PARSE_NO_ARGUMENT_MATCH;
}
/**
* Matches a set of variables with a description set.
*
* This is typically used for routine arguments before a call. The effects in
* addition to the validation, is that some variables might be propagated to
* other types in order to match the description. The following transformations
* are supported:
* - String reinterpreted as a symbol and resolved to a number or pointer.
* - Number to a pointer.
* - Pointer to a number.
* @returns 0 on success with paVars.
* @returns VBox error code for match errors.
*/
{
/*
* Just do basic min / max checks first.
*/
return VERR_PARSE_TOO_FEW_ARGUMENTS;
return VERR_PARSE_TOO_MANY_ARGUMENTS;
/*
* Match the descriptors and actual variables.
*/
unsigned cCurDesc = 0;
unsigned iVar = 0;
unsigned iVarDesc = 0;
{
/* walk the descriptors */
return VERR_PARSE_TOO_MANY_ARGUMENTS;
{
iVarDesc++;
return VERR_PARSE_TOO_MANY_ARGUMENTS;
cCurDesc = 0;
}
/*
* Skip thru optional arguments until we find something which matches
* or can easily be promoted to what the descriptor want.
*/
for (;;)
{
if (VBOX_SUCCESS(rc))
{
cCurDesc++;
break;
}
/* can we advance? */
cCurDesc = 0;
}
/* next var */
iVar++;
}
/*
* Check that the rest of the descriptors are optional.
*/
{
return VERR_PARSE_TOO_FEW_ARGUMENTS;
cCurDesc = 0;
/* next */
iVarDesc++;
}
return 0;
}
/**
* Evaluates one argument with though of unary operators.
*
* @returns 0 on success. pResult contains the result.
* @returns VBox error code on parse or other evaluation error.
*
* @param pDbgc Debugger console instance data.
* @param pszExpr The expression string.
* @param pResult Where to store the result of the expression evaluation.
*/
{
/*
* The state of the expression is now such that it will start by zero or more
* unary operators and being followed by an expression of some kind.
* The expression is either plain or in parenthesis.
*
* Being in a lazy, recursive mode today, the parsing is done as simple as possible. :-)
* ASSUME: unary operators are all of equal precedence.
*/
int rc = 0;
if (pOp)
{
/* binary operators means syntax error. */
return VERR_PARSE_UNEXPECTED_OPERATOR;
/*
* If the next expression (the one following the unary operator) is in a
* parenthesis a full eval is needed. If not the unary eval will suffice.
*/
/* calc and strip next expr. */
pszExpr2++;
if (!*pszExpr2)
else
{
if (*pszExpr2 == '(')
else
if (VBOX_SUCCESS(rc))
}
}
else
{
/*
* Didn't find any operators, so it we have to check if this can be an
* function call before assuming numeric or string expression.
*
* (ASSUMPTIONS:)
* A function name only contains alphanumerical chars and it can not start
* with a numerical character.
* Immediately following the name is a parenthesis which must over
* the remaining part of the expression.
*/
{
pszFunEnd++;
if (*pszFunEnd != '(')
}
if (pszFunEnd)
{
/*
* Ok, it's a function call.
*/
if (fExternal)
if (!pFun)
return VERR_PARSE_FUNCTION_NOT_FOUND;
if (!pFun->pResultDesc)
return VERR_PARSE_NOT_A_FUNCTION;
/*
* Parse the expression in parenthesis.
*/
/** @todo implement multiple arguments. */
if (!rc)
{
rc = dbgcEvalSubMatchVars(pDbgc, pFun->cArgsMin, pFun->cArgsMax, pFun->paArgDescs, pFun->cArgDescs, &Arg, 1);
if (!rc)
}
}
else
{
/*
* Didn't find any operators, so it must be a plain expression.
* This might be numeric or a string expression.
*/
else
{
/*
* Hexadecimal number or a string?
*/
psz++;
if (!*psz)
{
*psz = '\0';
}
else
}
}
}
return rc;
}
/**
* Evaluates one argument.
*
* @returns 0 on success. pResult contains the result.
* @returns VBox error code on parse or other evaluation error.
*
* @param pDbgc Debugger console instance data.
* @param pszExpr The expression string.
* @param pResult Where to store the result of the expression evaluation.
*/
{
/*
* First we need to remove blanks in both ends.
* ASSUMES: There is no quoting unless the entire expression is a string.
*/
/* stripping. */
if (!*pszExpr)
return VERR_PARSE_EMPTY_ARGUMENT;
/* it there is any kind of quoting in the expression, it's string meat. */
/*
* Check if there are any parenthesis which needs removing.
*/
{
do
{
unsigned cPar = 1;
char ch;
{
if (ch == '(')
cPar++;
else if (ch == ')')
{
if (cPar <= 0)
cPar--;
break;
}
/* next */
psz++;
}
if (ch)
break;
/* remove the parenthesis. */
pszExpr++;
cchExpr -= 2;
/* strip blanks. */
if (!*pszExpr)
return VERR_PARSE_EMPTY_ARGUMENT;
}
/* tabs to spaces. */
*psz = ' ';
/*
* Now, we need to look for the binary operator with the lowest precedence.
*
* If there are no operators we're left with a simple expression which we
* evaluate with respect to unary operators
*/
char *pszOpSplit = NULL;
unsigned iOpSplit = 0;
unsigned cBinaryOps = 0;
unsigned cPar = 0;
char ch;
char chPrev = ' ';
bool fBinary = false;
{
//Log2(("ch=%c cPar=%d fBinary=%d\n", ch, cPar, fBinary));
/*
* Parenthesis.
*/
if (ch == '(')
{
cPar++;
fBinary = false;
}
else if (ch == ')')
{
if (cPar <= 0)
cPar++;
fBinary = true;
}
/*
* Potential operator.
*/
{
if (pOp)
{
/* If not the right kind of operator we've got a syntax error. */
return VERR_PARSE_UNEXPECTED_OPERATOR;
/*
* Update the parse state and skip the operator.
*/
if (fBinary)
{
cBinaryOps++;
{
pszOpSplit = psz;
}
}
fBinary = false;
}
else
fBinary = true;
}
/* next */
psz++;
} /* parse loop. */
/*
* Either we found an operator to divide the expression by
* or we didn't find any. In the first case it's divide and
* conquer. In the latter it's a single expression which
* needs dealing with its unary operators if any.
*/
int rc;
if (cBinaryOps)
{
/* process 1st sub expression. */
*pszOpSplit = '\0';
if (VBOX_SUCCESS(rc))
{
/* process 2nd sub expression. */
if (VBOX_SUCCESS(rc))
/* apply the operator. */
}
}
else
/* plain expression or using unary operators perhaps with paratheses. */
return rc;
}
/**
* Parses the arguments of one command.
*
* @returns 0 on success.
* @returns VBox error code on parse error with *pcArg containing the argument causing trouble.
* @param pDbgc Debugger console instance data.
* @param pCmd Pointer to the command descriptor.
* @param pszArg Pointer to the arguments to parse.
* @param paArgs Where to store the parsed arguments.
* @param cArgs Size of the paArgs array.
* @param pcArgs Where to store the number of arguments.
* In the event of an error this is used to store the index of the offending argument.
*/
static int dbgcProcessArguments(PDBGC pDbgc, PCDBGCCMD pCmd, char *pszArgs, PDBGCVAR paArgs, unsigned cArgs, unsigned *pcArgs)
{
/*
* Check if we have any argument and if the command takes any.
*/
*pcArgs = 0;
/* strip leading blanks. */
pszArgs++;
if (!*pszArgs)
{
return 0;
return VERR_PARSE_TOO_FEW_ARGUMENTS;
}
/** @todo fixme - foo() doesn't work. */
return VERR_PARSE_TOO_MANY_ARGUMENTS;
/*
* This is a hack, it's "temporary" and should go away "when" the parser is
* modified to match arguments while parsing.
*/
&& cArgs >= 1)
{
*pcArgs = 1;
}
/*
* The parse loop.
*/
*pcArgs = 0;
do
{
/*
* Can we have another argument?
*/
return VERR_PARSE_TOO_MANY_ARGUMENTS;
return VERR_PARSE_ARGUMENT_OVERFLOW;
/*
* Find the end of the argument.
*/
int cPar = 0;
char chQuote = '\0';
char ch;
for (;;)
{
/*
* Check for the end.
*/
{
if (chQuote)
return VERR_PARSE_UNBALANCED_QUOTE;
if (cPar)
break;
}
/*
* When quoted we ignore everything but the quotation char.
* We use the REXX way of escaping the quotation char, i.e. double occurence.
*/
{
if (chQuote)
{
/* end quote? */
{
psz++; /* skip the escaped quote char */
else
}
}
else
}
/*
* Parenthesis can of course be nested.
*/
else if (ch == '(')
cPar++;
else if (ch == ')')
{
if (!cPar)
cPar--;
}
/*
* Encountering blanks may mean the end of it all. But of course not
* while inside a quotation or paranthesis. A binary operator will
* also force continued parsing.
*/
{
psz++;
break; /* the end. */
if (pOp)
psz++;
continue;
}
/* next char */
psz++;
}
*pszEnd = '\0';
/* (psz = next char to process) */
/*
* Parse and evaluate the argument.
*/
if (VBOX_FAILURE(rc))
return rc;
/*
* Next.
*/
pArg++;
(*pcArgs)++;
pszArgs++;
} while (*pszArgs);
/*
* Match the arguments.
*/
return dbgcEvalSubMatchVars(pDbgc, pCmd->cArgsMin, pCmd->cArgsMax, pCmd->paArgDescs, pCmd->cArgDescs, pArg0, pArg - pArg0);
}
/**
* Process one command.
*
* @returns VBox status code. Any error indicates the termination of the console session.
* @param pDbgc Debugger console instance data.
* @param pszCmd Pointer to the command.
* @param cchCmd Length of the command.
*/
{
char *pszCmdInput = pszCmd;
/*
* Skip blanks.
*/
/* external command? */
if (fExternal)
/*
* Find arguments.
*/
pszArgs++;
{
return 0;
}
/*
* Find the command.
*/
/*
* Parse arguments (if any).
*/
unsigned cArgs;
int rc = dbgcProcessArguments(pDbgc, pCmd, pszArgs, &pDbgc->aArgs[pDbgc->iArg], ELEMENTS(pDbgc->aArgs) - pDbgc->iArg, &cArgs);
/*
* Execute the command.
*/
if (!rc)
{
}
else
{
/* report parse / eval error. */
switch (rc)
{
"Syntax error: Too few arguments. Minimum is %d for command '%s'.\n", pCmd->cArgsMin, pCmd->pszCmd);
break;
"Syntax error: Too many arguments. Maximum is %d for command '%s'.\n", pCmd->cArgsMax, pCmd->pszCmd);
break;
"Syntax error: Too many arguments.\n");
break;
"Syntax error: Unbalanced quote (argument %d).\n", cArgs);
break;
"Syntax error: Unbalanced parenthesis (argument %d).\n", cArgs);
break;
"Syntax error: An argument or subargument contains nothing useful (argument %d).\n", cArgs);
break;
"Syntax error: Invalid operator usage (argument %d).\n", cArgs);
break;
"Syntax error: Ivalid numeric value (argument %d). If a string was the intention, then quote it.\n", cArgs);
break;
"Error: Numeric overflow (argument %d).\n", cArgs);
break;
"Error: Invalid operation attempted (argument %d).\n", cArgs);
break;
"Error: Function not found (argument %d).\n", cArgs);
break;
"Error: The function specified is not a function (argument %d).\n", cArgs);
break;
case VERR_PARSE_NO_MEMORY:
"Error: Out memory in the regular heap! Expect odd stuff to happen...\n", cArgs);
break;
"Error: Incorrect argument type (argument %d?).\n", cArgs);
break;
"Error: An undefined variable was referenced (argument %d).\n", cArgs);
break;
"Error: A conversion between two types failed (argument %d).\n", cArgs);
break;
"Error: You hit a debugger feature which isn't implemented yet (argument %d).\n", cArgs);
break;
"Error: Couldn't satisfy a request for a specific result type (argument %d). (Usually applies to symbols)\n", cArgs);
break;
"Error: Cannot get symbol, it's set only (argument %d).\n", cArgs);
break;
default:
"Error: Unknown error %d!\n", rc);
return rc;
}
/*
* Parse errors are non fatal.
*/
rc = 0;
}
return rc;
}
/**
* Process all commands current in the buffer.
*
* @returns VBox status code. Any error indicates the termination of the console session.
* @param pDbgc Debugger console instance data.
*/
{
int rc = 0;
while (pDbgc->cInputLines)
{
/*
* Empty the log buffer if we're hooking the log.
*/
{
if (VBOX_FAILURE(rc))
break;
}
{
pDbgc->cInputLines = 0;
return 0;
}
/*
* Copy the command to the parse buffer.
*/
char ch;
{
{
pDbgc->cInputLines = 0;
return 0;
}
pszTrg++;
}
*pszTrg = '\0';
/*
* Advance the buffer.
*/
if (ch == '\n')
pDbgc->cInputLines--;
/*
* Parse and execute this command.
*/
if (rc)
break;
}
return rc;
}
/**
* Reads input, parses it and executes commands on '\n'.
*
* @returns VBox status.
* @param pDbgc Debugger console instance data.
*/
{
/*
* We know there's input ready, so let's read it first.
*/
if (VBOX_FAILURE(rc))
return rc;
/*
* Now execute any ready commands.
*/
if (pDbgc->cInputLines)
{
/** @todo this fReady stuff is broken. */
if ( VBOX_SUCCESS(rc)
}
return rc;
}
/**
* Gets the event context identifier string.
* @returns Read only string.
* @param enmCtx The context.
*/
{
switch (enmCtx)
{
case DBGFEVENTCTX_RAW: return "raw";
case DBGFEVENTCTX_REM: return "rem";
case DBGFEVENTCTX_HWACCL: return "hwaccl";
case DBGFEVENTCTX_HYPER: return "hyper";
case DBGFEVENTCTX_OTHER: return "other";
case DBGFEVENTCTX_INVALID: return "!Invalid Event Ctx!";
default:
return "!Unknown Event Ctx!";
}
}
/**
* Processes debugger events.
*
* @returns VBox status.
* @param pDbgc DBGC Instance data.
* @param pEvent Pointer to event data.
*/
{
/*
* Flush log first.
*/
{
if (VBOX_FAILURE(rc))
return rc;
}
/*
* Process the event.
*/
bool fPrintPrompt = true;
int rc = VINF_SUCCESS;
{
/*
* The first part is events we have initiated with commands.
*/
case DBGFEVENT_HALT_DONE:
{
if (VBOX_SUCCESS(rc))
break;
}
/*
* The second part is events which can occur at any time.
*/
case DBGFEVENT_FATAL_ERROR:
{
if (VBOX_SUCCESS(rc))
break;
}
case DBGFEVENT_BREAKPOINT:
{
switch (rc)
{
case VERR_DBGC_BP_NOT_FOUND:
break;
case VINF_DBGC_BP_NO_COMMAND:
break;
case VINF_BUFFER_OVERFLOW:
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Breakpoint %u! Command too long to execute! (%s)\n",
break;
default:
break;
}
else
break;
}
case DBGFEVENT_STEPPED:
case DBGFEVENT_STEPPED_HYPER:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf event: Single step! (%s)\n", dbgcGetEventCtx(pEvent->enmCtx));
if (VBOX_SUCCESS(rc))
break;
}
{
pDbgc->fRegCtxGuest = false;
"\ndbgf event: Hypervisor Assertion! (%s)\n"
"%s"
"%s"
"\n",
if (VBOX_SUCCESS(rc))
break;
}
case DBGFEVENT_DEV_STOP:
{
"\n"
"dbgf event: DBGFSTOP (%s)\n"
"File: %s\n"
"Line: %d\n"
"Function: %s\n",
"Message: %s\n",
if (VBOX_SUCCESS(rc))
break;
}
{
break;
}
case DBGFEVENT_TERMINATING:
{
break;
}
default:
{
rc = pDbgc->CmdHlp.pfnPrintf(&pDbgc->CmdHlp, NULL, "\ndbgf/dbgc error: Unknown event %d!\n", pEvent->enmType);
break;
}
}
/*
* Prompt, anyone?
*/
{
}
return rc;
}
/**
* Make a console instance.
*
* This will not return until either an 'exit' command is issued or a error code
* indicating connection loss is encountered.
*
* @returns VINF_SUCCESS if console termination caused by the 'exit' command.
* @returns The VBox status code causing the console termination.
*
* @param pVM VM Handle.
* @param pBack Pointer to the backend structure. This must contain
* a full set of function pointers to service the console.
* @param fFlags Reserved, must be zero.
* @remark A forced termination of the console is easiest done by forcing the
* callbacks to return fatal failures.
*/
{
/*
* Validate input.
*/
/*
* Allocate and initialize instance data
*/
if (!pDbgc)
return VERR_NO_MEMORY;
pDbgc->fRegCtxGuest = true;
pDbgc->fInputOverflow = false;
pDbgc->cInputLines = 0;
/*
* Print welcome message.
*/
"Welcome to the VirtualBox Debugger!\n");
if (VBOX_FAILURE(rc))
goto l_failure;
/*
* Attach to the VM.
*/
if (VBOX_FAILURE(rc))
{
rc = pDbgc->CmdHlp.pfnVBoxError(&pDbgc->CmdHlp, rc, "When trying to attach to VM %p\n", pDbgc->pVM);
goto l_failure;
}
/*
* Print commandline and auto select result.
*/
"Current VM is %08x\n" /** @todo get and print the VM name! */
"VBoxDbg> ",
if (VBOX_FAILURE(rc))
goto l_failure;
/*
* Main Debugger Loop.
*
* This loop will either block on waiting for input or on waiting on
* debug events. If we're forwarding the log we cannot wait for long
* before we must flush the log.
*/
for (rc = 0;;)
{
{
/*
* Wait for a debug event.
*/
if (VBOX_SUCCESS(rc))
{
if (VBOX_FAILURE(rc))
break;
}
else if (rc != VERR_TIMEOUT)
break;
/*
* Check for input.
*/
{
if (VBOX_FAILURE(rc))
break;
}
}
else
{
/*
* Wait for input. If Logging is enabled we'll only wait very briefly.
*/
{
if (VBOX_FAILURE(rc))
break;
}
}
/*
* Forward log output.
*/
{
if (VBOX_FAILURE(rc))
break;
}
}
/*
* Cleanup console debugger session.
*/
/* Disable log hook. */
{
}
/* Detach from the VM. */
/* finally, free the instance memory. */
return rc;
}
/**
* Register one or more external commands.
*
* @returns VBox status.
* @param paCommands Pointer to an array of command descriptors.
* The commands must be unique. It's not possible
* to register the same commands more than once.
* @param cCommands Number of commands.
*/
{
/*
* Lock the list.
*/
while (pCur)
{
{
return VWRN_DBGC_ALREADY_REGISTERED;
}
}
/*
* Allocate new chunk.
*/
int rc = 0;
if (pCur)
{
}
else
rc = VERR_NO_MEMORY;
return rc;
}
/**
* Deregister one or more external commands previously registered by
* DBGCRegisterCommands().
*
* @returns VBox status.
* @param paCommands Pointer to an array of command descriptors
* as given to DBGCRegisterCommands().
* @param cCommands Number of commands.
*/
{
/*
* Lock the list.
*/
while (pCur)
{
{
if (pPrev)
else
return VINF_SUCCESS;
}
}
}