DBGCCmdHlp.cpp revision 5dd0f48aea5b772d5b217101f71606345feb8d3b
/* $Id$ */
/** @file
* DBGC - Debugger Console, Command Helpers.
*/
/*
* Copyright (C) 2006-2011 Oracle Corporation
*
* 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 (GPL) 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.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_DBGC
#include "DBGCInternal.h"
/**
* @interface_method_impl{DBGCCMDHLP,pfnPrintf}
*/
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, employed by dbgcPrintfV
* and others.
*
* @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(size_t) dbgcStringFormatter(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
{
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_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, "%%#%RHv%s", (uintptr_t)pVar->u.pvHCFlat, szRange);
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_NUMBER:
case DBGCVAR_TYPE_UNKNOWN:
default:
}
}
default:
return 0;
}
}
/**
* Output callback employed by dbgcHlpPrintfV.
*
* @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 (RT_SUCCESS(rc))
else
{
cbChars = 0;
}
}
return cbChars;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnPrintfV}
*/
static DECLCALLBACK(int) dbgcHlpPrintfV(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, const char *pszFormat, va_list args)
{
/*
* Do the formatting and output.
*/
if (pcbWritten)
*pcbWritten = cb;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVBoxErrorV}
*/
static DECLCALLBACK(int) dbgcHlpVBoxErrorV(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, va_list args)
{
switch (rc)
{
case VINF_SUCCESS:
break;
default:
if (RT_SUCCESS(rc))
break;
}
return rc;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVBoxError}
*/
{
return rcRet;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnMemRead}
*/
static DECLCALLBACK(int) dbgcHlpMemRead(PDBGCCMDHLP pCmdHlp, PVM pVM, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)
{
int rc;
/*
* Dummy check.
*/
if (cbRead == 0)
{
if (*pcbRead)
*pcbRead = 0;
return VINF_SUCCESS;
}
/*
* Convert Far addresses getting size and the correct base address.
* Getting and checking the size is what makes this messy and slow.
*/
switch (pVarPointer->enmType)
{
case DBGCVAR_TYPE_GC_FAR:
/* Use DBGFR3AddrFromSelOff for the conversion. */
if (RT_FAILURE(rc))
return rc;
/* don't bother with flat selectors (for now). */
if (!DBGFADDRESS_IS_FLAT(&Address))
{
if (RT_SUCCESS(rc))
{
if (DBGFSelInfoIsExpandDown(&SelInfo))
{
return VERR_OUT_OF_SELECTOR_BOUNDS;
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
else
{
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
{
if (!pcbRead)
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
}
}
break;
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.
*/
{
case DBGCVAR_TYPE_GC_FLAT:
break;
case DBGCVAR_TYPE_GC_PHYS:
break;
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
{
if (RT_SUCCESS(rc))
{
/** @todo protect this!!! */
rc = 0;
}
else
break;
}
default:
}
/*
* Check for failure.
*/
if (RT_FAILURE(rc))
{
return VINF_SUCCESS;
return rc;
}
/*
* Next.
*/
if (!cbLeft)
break;
if (RT_FAILURE(rc))
{
return VINF_SUCCESS;
return rc;
}
}
/*
* Done
*/
if (pcbRead)
return 0;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnMemWrite}
*/
static DECLCALLBACK(int) dbgcHlpMemWrite(PDBGCCMDHLP pCmdHlp, PVM pVM, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)
{
int rc;
/*
* Dummy check.
*/
if (cbWrite == 0)
{
if (*pcbWritten)
*pcbWritten = 0;
return VINF_SUCCESS;
}
/*
* Convert Far addresses getting size and the correct base address.
* Getting and checking the size is what makes this messy and slow.
*/
switch (pVarPointer->enmType)
{
case DBGCVAR_TYPE_GC_FAR:
{
/* Use DBGFR3AddrFromSelOff for the conversion. */
if (RT_FAILURE(rc))
return rc;
/* don't bother with flat selectors (for now). */
if (!DBGFADDRESS_IS_FLAT(&Address))
{
if (RT_SUCCESS(rc))
{
if (DBGFSelInfoIsExpandDown(&SelInfo))
{
return VERR_OUT_OF_SELECTOR_BOUNDS;
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
else
{
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
{
if (!pcbWritten)
return VERR_OUT_OF_SELECTOR_BOUNDS;
}
}
}
}
/* fall thru */
case DBGCVAR_TYPE_GC_FLAT:
*pcbWritten = cbWrite;
return rc;
case DBGCVAR_TYPE_GC_PHYS:
*pcbWritten = cbWrite;
return rc;
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
{
/*
* Copy HC memory page by page.
*/
if (pcbWritten)
*pcbWritten = 0;
while (cbWrite > 0)
{
/* convert to flat address */
if (RT_FAILURE(rc))
{
if (pcbWritten && *pcbWritten)
return -VERR_INVALID_POINTER;
return VERR_INVALID_POINTER;
}
/* calc size. */
/** @todo protect this!!! */
/* advance */
else
if (pcbWritten)
*pcbWritten += cbChunk;
}
return VINF_SUCCESS;
}
default:
return VERR_NOT_IMPLEMENTED;
}
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnHlpExec}
*/
{
/* 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;
}
/**
* @copydoc DBGCCMDHLP::pfnEvalV
*/
static DECLCALLBACK(int) dbgcHlpEvalV(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, va_list va)
{
/*
* Format the expression.
*/
char szExprFormatted[2048];
size_t cb = RTStrPrintfExV(dbgcStringFormatter, pDbgc, szExprFormatted, sizeof(szExprFormatted), pszExpr, va);
/* ignore overflows. */
}
/**
* @copydoc DBGCCMDHLP::pfnFailV
*/
static DECLCALLBACK(int) dbgcHlpFailV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, va_list va)
{
/*
* Do the formatting and output.
*/
return VERR_DBGC_COMMAND_FAILED;
}
/**
* @copydoc DBGCCMDHLP::pfnFailV
*/
static DECLCALLBACK(int) dbgcHlpFailRcV(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, const char *pszFormat, va_list va)
{
/*
* Do the formatting and output.
*/
return VERR_DBGC_COMMAND_FAILED;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarToDbgfAddr}
*/
static DECLCALLBACK(int) dbgcHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)
{
{
case DBGCVAR_TYPE_GC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_GC_FAR:
return DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, pAddress, pVar->u.GCFar.sel, pVar->u.GCFar.off);
case DBGCVAR_TYPE_GC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
{
if (RT_FAILURE(rc))
return rc;
}
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
default:
}
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarFromDbgfAddr}
*/
static DECLCALLBACK(int) dbgcHlpVarFromDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult)
{
{
case DBGFADDRESS_FLAGS_FAR16:
case DBGFADDRESS_FLAGS_FAR32:
case DBGFADDRESS_FLAGS_FAR64:
break;
case DBGFADDRESS_FLAGS_FLAT:
break;
case DBGFADDRESS_FLAGS_PHYS:
break;
default:
break;
}
return VINF_SUCCESS;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarToNumber}
*/
static DECLCALLBACK(int) dbgcHlpVarToNumber(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number)
{
{
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:
break;
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_STRING:
return VERR_DBGC_PARSE_INCORRECT_ARG_TYPE; /** @todo better error code! */
default:
}
*pu64Number = u64Number;
return VINF_SUCCESS;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarToBool}
*/
{
{
case DBGCVAR_TYPE_STRING:
{
*pf = true;
return VINF_SUCCESS;
}
{
*pf = false;
return VINF_SUCCESS;
}
return VERR_DBGC_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_GC_FAR:
case DBGCVAR_TYPE_SYMBOL:
default:
}
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarGetRange}
*/
static DECLCALLBACK(int) dbgcHlpVarGetRange(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault,
{
switch (pVar->enmRangeType)
{
default:
case DBGCVAR_RANGE_NONE:
break;
case DBGCVAR_RANGE_BYTES:
break;
case DBGCVAR_RANGE_ELEMENTS:
break;
}
return VINF_SUCCESS;
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnVarConvert}
*/
static DECLCALLBACK(int) dbgcHlpVarConvert(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pInVar, DBGCVARTYPE enmToType, bool fConvSyms,
{
int rc;
{
case DBGCVAR_TYPE_GC_FLAT:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FLAT:
false /*fReadOnly */,
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_GC_FAR:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
if (RT_SUCCESS(rc))
{
return VINF_SUCCESS;
}
case DBGCVAR_TYPE_GC_FAR:
return VINF_SUCCESS;
case DBGCVAR_TYPE_GC_PHYS:
rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
}
case DBGCVAR_TYPE_HC_FLAT:
rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
}
case DBGCVAR_TYPE_HC_PHYS:
rc = DBGFR3AddrFromSelOff(pDbgc->pVM, pDbgc->idCpu, &Address, pArg->u.GCFar.sel, pArg->u.GCFar.off);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
}
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_GC_PHYS:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
//rc = MMR3PhysGCPhys2GCVirtEx(pDbgc->pVM, pResult->u.GCPhys, ..., &pResult->u.GCFlat); - yea, sure.
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FLAT:
false /*fReadOnly */,
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_HC_FLAT:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
/** @todo more memory types! */
case DBGCVAR_TYPE_HC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
/** @todo more memory types! */
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_HC_PHYS:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_NUMBER:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_FLAT:
return VINF_SUCCESS;
case DBGCVAR_TYPE_HC_PHYS:
return VINF_SUCCESS;
case DBGCVAR_TYPE_NUMBER:
return VINF_SUCCESS;
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_SYMBOL:
case DBGCVAR_TYPE_STRING:
switch (enmToType)
{
case DBGCVAR_TYPE_GC_FLAT:
case DBGCVAR_TYPE_GC_FAR:
case DBGCVAR_TYPE_GC_PHYS:
case DBGCVAR_TYPE_HC_FLAT:
case DBGCVAR_TYPE_HC_PHYS:
case DBGCVAR_TYPE_NUMBER:
if (fConvSyms)
{
if (RT_SUCCESS(rc))
{
{
}
return VINF_SUCCESS;
}
}
case DBGCVAR_TYPE_STRING:
case DBGCVAR_TYPE_SYMBOL:
return VINF_SUCCESS;
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
break;
case DBGCVAR_TYPE_UNKNOWN:
case DBGCVAR_TYPE_ANY:
break;
}
return VERR_INVALID_PARAMETER;
}
/**
* @interface_method_impl{DBGFINFOHLP,pfnPrintf}
*/
static DECLCALLBACK(void) dbgcHlpGetDbgfOutputHlp_Printf(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)
{
}
/**
* @interface_method_impl{DBGFINFOHLP,pfnPrintfV}
*/
static DECLCALLBACK(void) dbgcHlpGetDbgfOutputHlp_PrintfV(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)
{
}
/**
* @interface_method_impl{DBGCCMDHLP,pfnGetDbgfOutputHlp}
*/
{
/* Lazy init */
{
}
return &pDbgc->DbgfOutputHlp;
}
/**
* Initializes the Command Helpers for a DBGC instance.
*
* @param pDbgc Pointer to the DBGC instance.
*/
{
}