DBGFReg.cpp revision 78767995a4d318c552cd8b1cdf57547964acf595
/* $Id$ */
/** @file
* DBGF - Debugger Facility, Register Methods.
*/
/*
* Copyright (C) 2010-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_DBGF
#include "DBGFInternal.h"
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
/** Locks the register database for writing. */
#define DBGF_REG_DB_LOCK_WRITE(pVM) \
do { \
} while (0)
/** Unlocks the register database after writing. */
#define DBGF_REG_DB_UNLOCK_WRITE(pVM) \
do { \
} while (0)
/** Locks the register database for reading. */
#define DBGF_REG_DB_LOCK_READ(pVM) \
do { \
} while (0)
/** Unlocks the register database after reading. */
#define DBGF_REG_DB_UNLOCK_READ(pVM) \
do { \
} while (0)
/** The max length of a set, register or sub-field name. */
#define DBGF_REG_MAX_NAME 40
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Register set registration record type.
*/
typedef enum DBGFREGSETTYPE
{
/** Invalid zero value. */
/** CPU record. */
/** Device record. */
/** End of valid record types. */
/**
* Register set registration record.
*/
typedef struct DBGFREGSET
{
/** String space core. */
/** The registration record type. */
/** The user argument for the callbacks. */
union
{
/** The CPU view. */
/** The device view. */
/** The general view. */
void *pv;
} uUserArg;
/** The register descriptors. */
/** The number of register descriptors. */
/** Array of lookup records.
* The first part of the array runs parallel to paDescs, the rest are
* covering for aliases and bitfield variations. It's done this way to
* simplify the query all operations. */
struct DBGFREGLOOKUP *paLookupRecs;
/** The number of lookup records. */
/** The register name prefix. */
char szPrefix[1];
} DBGFREGSET;
/** Pointer to a register registration record. */
typedef DBGFREGSET *PDBGFREGSET;
/** Pointer to a const register registration record. */
typedef DBGFREGSET const *PCDBGFREGSET;
/**
* Register lookup record.
*/
typedef struct DBGFREGLOOKUP
{
/** The string space core. */
/** Pointer to the set. */
/** Pointer to the register descriptor. */
/** If an alias this points to the alias descriptor, NULL if not. */
/** If a sub-field this points to the sub-field descriptor, NULL if not. */
/** Pointer to a register lookup record. */
typedef DBGFREGLOOKUP *PDBGFREGLOOKUP;
/** Pointer to a const register lookup record. */
typedef DBGFREGLOOKUP const *PCDBGFREGLOOKUP;
/**
* Argument packet from DBGFR3RegNmQueryAll to dbgfR3RegNmQueryAllWorker.
*/
typedef struct DBGFR3REGNMQUERYALLARGS
{
/** The output register array. */
/** The number of entries in the output array. */
/** The current register number when enumerating the string space. */
/** Pointer to a dbgfR3RegNmQueryAllWorker argument packet. */
/**
* Argument packet passed by DBGFR3RegNmPrintfV to dbgfR3RegNmPrintfCbOutput
* and dbgfR3RegNmPrintfCbFormat.
*/
typedef struct DBGFR3REGNMPRINTFARGS
{
/** The VM handle. */
/** The target CPU. */
/** The output buffer. */
char *pszBuf;
/** The format string. */
const char *pszFormat;
/** The va list with format arguments. */
/** The current buffer offset. */
/** The amount of buffer space left, not counting the terminator char. */
/** The status code of the whole operation. First error is return,
* subsequent ones are suppressed. */
int rc;
/** Pointer to a DBGFR3RegNmPrintfV argument packet. */
typedef DBGFR3REGNMPRINTFARGS *PDBGFR3REGNMPRINTFARGS;
/**
* Initializes the register database.
*
* @returns VBox status code.
* @param pVM The VM handle.
*/
{
int rc = VINF_SUCCESS;
{
}
return rc;
}
/**
* Terminates the register database.
*
* @param pVM The VM handle.
*/
{
}
/**
* Validates a register name.
*
* This is used for prefixes, aliases and field names.
*
* @returns true if valid, false if not.
* @param pszName The register name to validate.
* @param chDot Set to '.' if accepted, otherwise 0.
*/
{
if (!RT_C_IS_ALPHA(*psz))
return false;
char ch;
if ( !RT_C_IS_LOWER(ch)
&& !RT_C_IS_DIGIT(ch)
&& ch != '_'
return false;
return false;
return true;
}
/**
* Common worker for registering a register set.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param paRegisters The register descriptors.
* @param enmType The set type.
* @param pvUserArg The user argument for the callbacks.
* @param pszPrefix The name prefix.
* @param iInstance The instance number to be appended to @a
* pszPrefix when creating the set name.
*/
static int dbgfR3RegRegisterCommon(PVM pVM, PCDBGFREGDESC paRegisters, DBGFREGSETTYPE enmType, void *pvUserArg, const char *pszPrefix, uint32_t iInstance)
{
/*
* Validate input.
*/
/* The name components. */
AssertMsgReturn(cchPrefix < RT_SIZEOFMEMB(DBGFREGSET, szPrefix) - 4 - 1, ("%s\n", pszPrefix), VERR_INVALID_NAME);
/* The descriptors. */
uint32_t cLookupRecs = 0;
{
AssertMsgReturn(dbgfR3RegIsNameValid(paRegisters[iDesc].pszName, 0), ("%s (#%u)\n", paRegisters[iDesc].pszName, iDesc), VERR_INVALID_NAME);
if (enmType == DBGFREGSETTYPE_CPU)
else
if (paAliases)
{
{
AssertMsgReturn(dbgfR3RegIsNameValid(paAliases[iAlias].pszName, 0), ("%s (%s)\n", paAliases[iAlias].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
}
}
if (paSubFields)
{
{
AssertMsgReturn(dbgfR3RegIsNameValid(paSubFields[iSubField].pszName, '.'), ("%s (%s)\n", paSubFields[iSubField].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
AssertReturn(paSubFields[iSubField].iFirstBit + paSubFields[iSubField].cBits <= 128, VERR_INVALID_PARAMETER);
AssertReturn(paSubFields[iSubField].cBits + paSubFields[iSubField].cShift <= 128, VERR_INVALID_PARAMETER);
}
}
}
/* Check the instance number of the CPUs. */
/*
* Allocate a new record and all associated lookup records.
*/
if (!pRegSet)
return VERR_NO_MEMORY;
/*
* Initialize the new record.
*/
if (fNeedUnderscore)
else
/*
* Initialize the lookup records. See DBGFREGSET::paLookupRecs.
*/
*pszReg++ = '.';
/* Array parallel to the descriptors. */
int rc = VINF_SUCCESS;
{
pLookupRec++;
}
/* Aliases and sub-fields. */
{
while (RT_SUCCESS(rc))
{
/* Add sub-field records. */
if (paSubFields)
{
*pszSub++ = '.';
{
pLookupRec++;
}
}
/* Advance to the next alias. */
pCurAlias = pNextAlias++;
if (!pCurAlias)
break;
if (!pszRegName)
break;
/* The alias record. */
pLookupRec++;
}
}
if (RT_SUCCESS(rc))
{
/*
* Insert the record into the register set string space and optionally into
* the CPU register set cache.
*/
if (fInserted)
{
if (enmType == DBGFREGSETTYPE_CPU)
{
}
while (iLookupRec-- > 0)
{
}
return VINF_SUCCESS;
}
rc = VERR_DUPLICATE;
}
/*
* Bail out.
*/
return rc;
}
/**
* Registers a set of registers for a CPU.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pVCpu The virtual CPU handle.
* @param paRegisters The register descriptors.
*/
{
{
if (RT_FAILURE(rc))
return rc;
}
}
/**
* Registers a set of registers for a device.
*
* @returns VBox status code.
* @param enmReg The register identifier.
* @param enmType The register type. This is for sort out
* aliases. Pass DBGFREGVALTYPE_INVALID to get
* the standard name.
*/
VMMR3DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, const char *pszPrefix, uint32_t iInstance)
{
return dbgfR3RegRegisterCommon(pVM, paRegisters, DBGFREGSETTYPE_DEVICE, pDevIns, pszPrefix, iInstance);
}
/**
* Clears the register value variable.
*
* @param pValue The variable to clear.
*/
{
}
/**
* Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
*
* @param pValue The value.
* @param u64 The integer value.
*/
{
/** @todo fixme */
}
/**
* Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
*
* @param pValue The value.
* @param u128 The integer value.
*/
{
/** @todo fixme */
}
/**
* Get a 80-bit floating point variable as a 64-bit unsigned integer.
*
* @returns 64-bit unsigned integer.
* @param pValue The value.
*/
{
/** @todo stupid, stupid MSC. */
}
/**
* Get a 80-bit floating point variable as a 128-bit unsigned integer.
*
* @returns 128-bit unsigned integer.
* @param pValue The value.
*/
{
/** @todo stupid, stupid MSC. */
#if 0
#else
#endif
return uRet;
}
/**
* Performs a cast between register value types.
*
* @retval VINF_SUCCESS
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VERR_DBGF_UNSUPPORTED_CAST
*
* @param pValue The value to cast (input + output).
* @param enmFromType The input value.
* @param enmToType The desired output value.
*/
static int dbgfR3RegValCast(PDBGFREGVAL pValue, DBGFREGVALTYPE enmFromType, DBGFREGVALTYPE enmToType)
{
/* Note! No default cases here as gcc warnings about missing enum values
are desired. */
switch (enmFromType)
{
case DBGFREGVALTYPE_U8:
switch (enmToType)
{
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u8); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_U16:
switch (enmToType)
{
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u16); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_U32:
switch (enmToType)
{
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u32); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_U64:
switch (enmToType)
{
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u64); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_U128:
switch (enmToType)
{
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u128); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_R80:
switch (enmToType)
{
case DBGFREGVALTYPE_U8: pValue->u8 = (uint8_t )dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_U16: pValue->u16 = (uint16_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_U32: pValue->u32 = (uint32_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_U64: pValue->u64 = (uint64_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_U128: pValue->u128 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_DTR:
switch (enmToType)
{
case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.dtr.u64Base); return VINF_DBGF_TRUNCATED_REGISTER;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
}
break;
case DBGFREGVALTYPE_INVALID:
case DBGFREGVALTYPE_END:
break;
}
return VERR_DBGF_UNSUPPORTED_CAST;
}
/**
* Worker for the CPU register queries.
*
* @returns VBox status code.
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idCpu The virtual CPU ID.
* @param enmReg The register to query.
* @param enmType The desired return type.
* @param pValue Where to return the register value.
*/
static DECLCALLBACK(int) dbgfR3RegCpuQueryWorker(PVM pVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType, PDBGFREGVAL pValue)
{
int rc = VINF_SUCCESS;
/*
* Look up the register set of the specified CPU.
*/
{
/*
* Look up the register and get the register value.
*/
{
if (RT_SUCCESS(rc))
{
/*
* Do the cast if the desired return type doesn't match what
* the getter returned.
*/
rc = VINF_SUCCESS;
else
}
}
else
}
else
return rc;
}
/**
* Queries a 8-bit CPU register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param enmReg The register that's being queried.
* @param pu8 Where to store the register value.
*/
{
int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U8, &Value);
if (RT_SUCCESS(rc))
else
*pu8 = 0;
return rc;
}
/**
* Queries a 16-bit CPU register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param enmReg The register that's being queried.
* @param pu16 Where to store the register value.
*/
{
int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U16, &Value);
if (RT_SUCCESS(rc))
else
*pu16 = 0;
return rc;
}
/**
* Queries a 32-bit CPU register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param enmReg The register that's being queried.
* @param pu32 Where to store the register value.
*/
{
int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U32, &Value);
if (RT_SUCCESS(rc))
else
*pu32 = 0;
return rc;
}
/**
* Queries a 64-bit CPU register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param enmReg The register that's being queried.
* @param pu64 Where to store the register value.
*/
{
int rc = VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorker, 5, pVM, idCpu, enmReg, DBGFREGVALTYPE_U64, &Value);
if (RT_SUCCESS(rc))
else
*pu64 = 0;
return rc;
}
/**
* Wrapper around CPUMQueryGuestMsr for dbgfR3RegCpuQueryBatchWorker.
*
* @retval VINF_SUCCESS
* @retval VERR_DBGF_REGISTER_NOT_FOUND
*
* @param pVCpu The current CPU.
* @param pReg The where to store the register value and
* size.
* @param idMsr The MSR to get.
*/
{
if (RT_FAILURE(rc))
{
}
}
static DECLCALLBACK(int) dbgfR3RegCpuQueryBatchWorker(PVM pVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
{
#if 0
while (cRegs-- > 0)
{
pReg++;
AssertMsgReturn(enmReg >= 0 && enmReg <= DBGFREG_END, ("%d (%#x)\n", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
if (enmReg != DBGFREG_END)
{
{
{
case DBGFREGVALTYPE_U128:
break;
case DBGFREGVALTYPE_R80:
break;
default:
}
}
else
{
if (RT_FAILURE(rc))
return rc;
}
}
}
return VINF_SUCCESS;
#else
return VERR_NOT_IMPLEMENTED;
#endif
}
/**
* Query a batch of registers.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param paRegs Pointer to an array of @a cRegs elements. On
* input the enmReg members indicates which
* registers to query. On successful return the
* other members are set. DBGFREG_END can be used
* as a filler.
* @param cRegs The number of entries in @a paRegs.
*/
{
if (!cRegs)
return VINF_SUCCESS;
while (iReg-- > 0)
{
AssertMsgReturn(enmReg < DBGFREG_END && enmReg >= DBGFREG_AL, ("%d (%#x)", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
}
return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
}
/**
* Query a all registers for a Virtual CPU.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
*
* @param pVM The VM handle.
* @param idCpu The target CPU ID.
* @param paRegs Pointer to an array of @a cRegs elements.
* These will be filled with the CPU register
* values. Overflowing entries will be set to
* DBGFREG_END. The returned registers can be
* accessed by using the DBGFREG values as index.
* @param cRegs The number of entries in @a paRegs. The
* recommended value is DBGFREG_ALL_COUNT.
*/
{
/*
* Validate input.
*/
if (!cRegs)
return VINF_SUCCESS;
/*
* Convert it into a batch query (lazy bird).
*/
unsigned iReg = 0;
{
iReg++;
}
return VMR3ReqCallWait(pVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pVM, idCpu, paRegs, cRegs);
}
/**
* Gets the name of a register.
*
* @returns Pointer to read-only register name (lower case). NULL if the
* parameters are invalid.
*
* @param pVM The VM handle.
* @param enmReg The register identifier.
* @param enmType The register type. This is for sort out
* aliases. Pass DBGFREGVALTYPE_INVALID to get
* the standard name.
*/
{
if (RT_UNLIKELY(!pSet))
return NULL;
if ( pAlias
&& enmType != DBGFREGVALTYPE_INVALID)
{
{
pAlias++;
}
}
}
/**
* Fold the string to lower case and copy it into the destination buffer.
*
* @returns Number of folder characters, -1 on overflow.
* @param pszSrc The source string.
* @param cchSrc How much to fold and copy.
* @param pszDst The output buffer.
* @param cbDst The size of the output buffer.
*/
{
char ch;
{
return -1;
cbDst--;
}
if (RT_UNLIKELY(!cbDst))
return -1;
*pszDst = '\0';
return cchFolded;
}
/**
* Resolves the register name.
*
* @returns Lookup record.
* @param pVM The VM handle.
* @param idDefCpu The default CPU ID set.
* @param pszReg The register name.
*/
{
/* Try looking up the name without any case folding or cpu prefixing. */
if (!pLookupRec)
{
/* Lower case it and try again. */
ssize_t cchFolded = dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
if (cchFolded > 0)
if ( !pLookupRec
&& cchFolded >= 0
&& idDefCpu != VMCPUID_ANY)
{
/* Prefix it with the specified CPU set. */
}
}
return pLookupRec;
}
/**
* On CPU worker for the register queries, used by dbgfR3RegNmQueryWorker and
* dbgfR3RegNmPrintfCbFormat.
*
* @returns VBox status code.
*
* @param pVM The VM handle.
* @param pLookupRec The register lookup record.
* @param enmType The desired return type.
* @param pValue Where to return the register value.
* @param penmType Where to store the register value type.
* Optional.
*/
static DECLCALLBACK(int) dbgfR3RegNmQueryWorkerOnCpu(PVM pVM, PCDBGFREGLOOKUP pLookupRec, DBGFREGVALTYPE enmType,
{
int rc;
/*
* Get the register or sub-field value.
*/
if (!pSubField)
{
if ( pLookupRec->pAlias
&& RT_SUCCESS(rc))
{
}
}
else
{
{
}
else
{
if ( pLookupRec->pAlias
&& RT_SUCCESS(rc))
{
}
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
}
}
}
if (RT_SUCCESS(rc))
{
if (cBits <= 8)
else if (cBits <= 16)
else if (cBits <= 32)
else if (cBits <= 64)
else
}
}
if (RT_SUCCESS(rc))
{
/*
* Do the cast if the desired return type doesn't match what
* the getter returned.
*/
if ( enmValueType == enmType
|| enmType == DBGFREGVALTYPE_END)
{
rc = VINF_SUCCESS;
if (penmType)
*penmType = enmValueType;
}
else
{
if (penmType)
}
}
return rc;
}
/**
* Worker for the register queries.
*
* @returns VBox status code.
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The virtual CPU ID for the default CPU register
* set.
* @param pszReg The register to query.
* @param enmType The desired return type.
* @param pValue Where to return the register value.
* @param penmType Where to store the register value type.
* Optional.
*/
static int dbgfR3RegNmQueryWorker(PVM pVM, VMCPUID idDefCpu, const char *pszReg, DBGFREGVALTYPE enmType,
{
/*
* Validate input.
*/
/*
* Resolve the register and call the getter on the relevant CPU.
*/
if (pLookupRec)
{
return VMR3ReqCallWait(pVM, idDefCpu, (PFNRT)dbgfR3RegNmQueryWorkerOnCpu, 5, pVM, pLookupRec, enmType, pValue, penmType);
}
return VERR_DBGF_REGISTER_NOT_FOUND;
}
/**
* Queries a descriptor table register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pValue Where to store the register value.
* @param penmType Where to store the register value type.
*/
VMMR3DECL(int) DBGFR3RegNmQuery(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
{
}
/**
* Queries a 8-bit register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu8 Where to store the register value.
*/
{
if (RT_SUCCESS(rc))
else
*pu8 = 0;
return rc;
}
/**
* Queries a 16-bit register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu16 Where to store the register value.
*/
{
if (RT_SUCCESS(rc))
else
*pu16 = 0;
return rc;
}
/**
* Queries a 32-bit register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu32 Where to store the register value.
*/
{
if (RT_SUCCESS(rc))
else
*pu32 = 0;
return rc;
}
/**
* Queries a 64-bit register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu64 Where to store the register value.
*/
{
if (RT_SUCCESS(rc))
else
*pu64 = 0;
return rc;
}
/**
* Queries a 128-bit register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu128 Where to store the register value.
*/
VMMR3DECL(int) DBGFR3RegNmQueryU128(PVM pVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128)
{
if (RT_SUCCESS(rc))
else
return rc;
}
#if 0
/**
* Queries a long double register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param plrd Where to store the register value.
*/
VMMR3DECL(int) DBGFR3RegNmQueryLrd(PVM pVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd)
{
if (RT_SUCCESS(rc))
else
*plrd = 0;
return rc;
}
#endif
/**
* Queries a descriptor table register value.
*
* @retval VINF_SUCCESS
* @retval VERR_INVALID_VM_HANDLE
* @retval VERR_INVALID_CPU_ID
* @retval VERR_DBGF_REGISTER_NOT_FOUND
* @retval VERR_DBGF_UNSUPPORTED_CAST
* @retval VINF_DBGF_TRUNCATED_REGISTER
* @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
*
* @param pVM The VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable.
* @param pszReg The register that's being queried. Except for
* CPU registers, this must be on the form
* "set.reg[.sub]".
* @param pu64Base Where to store the register base value.
* @param pu32Limit Where to store the register limit value.
*/
VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PVM pVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint32_t *pu32Limit)
{
if (RT_SUCCESS(rc))
{
}
else
{
*pu64Base = 0;
*pu32Limit = 0;
}
return rc;
}
/// @todo VMMR3DECL(int) DBGFR3RegNmQueryBatch(PVM pVM,VMCPUID idDefCpu, DBGFREGENTRYNM paRegs, size_t cRegs);
/**
* Gets the number of registers returned by DBGFR3RegNmQueryAll.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param pcRegs Where to return the register count.
*/
{
return VINF_SUCCESS;
}
/**
* Pad register entries.
*
* @param paRegs The output array.
* @param cRegs The size of the output array.
* @param iReg The first register to pad.
* @param cRegsToPad The number of registers to pad.
*/
static void dbgfR3RegNmQueryAllPadEntries(PDBGFREGENTRYNM paRegs, size_t cRegs, size_t iReg, size_t cRegsToPad)
{
{
{
iReg++;
}
}
}
/**
* Query all registers in a set.
*
* @param pSet The set.
* @param cRegsToQuery The number of registers to query.
* @param paRegs The output array.
* @param cRegs The size of the output array.
*/
static void dbgfR3RegNmQueryAllInSet(PCDBGFREGSET pSet, size_t cRegsToQuery, PDBGFREGENTRYNM paRegs, size_t cRegs)
{
int rc = VINF_SUCCESS;
if (cRegsToQuery > cRegs)
{
if (RT_FAILURE(rc2))
}
}
/**
* @callback_method_impl{FNRTSTRSPACECALLBACK, Worker used by
* dbgfR3RegNmQueryAllWorker}
*/
{
{
dbgfR3RegNmQueryAllInSet(pSet, pSet->cDescs, &pArgs->paRegs[pArgs->iReg], pArgs->cRegs - pArgs->iReg);
}
return 0;
}
/**
* @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker used by DBGFR3RegNmQueryAll}
*/
{
/*
* My CPU registers.
*/
{
dbgfR3RegNmQueryAllInSet(pVCpu->dbgf.s.pRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
}
else
/*
* The primary CPU does all the other registers.
*/
{
}
return VINF_SUCCESS; /* Ignore errors. */
}
/**
* Queries all register.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param paRegs The output register value array. The register
* name string is read only and shall not be freed
* or modified.
* @param cRegs The number of entries in @a paRegs. The
* correct size can be obtained by calling
* DBGFR3RegNmQueryAllCount.
*/
{
return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3RegNmQueryAllWorker, &Args);
}
/**
* Internal worker for DBGFR3RegFormatValue, cbTmp is sufficent.
*
* @copydoc DBGFR3RegFormatValue
*/
DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszTmp, size_t cbTmp, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
{
switch (enmType)
{
case DBGFREGVALTYPE_U8:
case DBGFREGVALTYPE_U16:
case DBGFREGVALTYPE_U32:
case DBGFREGVALTYPE_U64:
case DBGFREGVALTYPE_U128:
case DBGFREGVALTYPE_R80:
case DBGFREGVALTYPE_DTR:
{
return cch;
}
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
/* no default, want gcc warnings */
}
return VERR_INTERNAL_ERROR_5;
}
/**
* Format a register value, extended version.
*
* @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
* @param pszBuf The output buffer.
* @param cbBuf The size of the output buffer.
* @param pValue The value to format.
* @param enmType The value type.
* @param uBase The base (ignored if not applicable).
* @param cchWidth The width if RTSTR_F_WIDTH is set, otherwise
* ignored.
* @param cchPrecision The width if RTSTR_F_PRECISION is set, otherwise
* ignored.
* @param fFlags String formatting flags, RTSTR_F_XXX.
*/
VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
{
/*
* Format to temporary buffer using worker shared with dbgfR3RegNmPrintfCbFormat.
*/
char szTmp[160];
ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
if (cchOutput > 0)
{
else
{
if (cbBuf)
{
}
}
}
return cchOutput;
}
/**
* Format a register value as hexadecimal and with default width according to
* the type.
*
* @returns The number of bytes returned, VERR_BUFFER_OVERFLOW on failure.
* @param pszBuf The output buffer.
* @param cbBuf The size of the output buffer.
* @param pValue The value to format.
* @param enmType The value type.
* @param fSpecial Same as RTSTR_F_SPECIAL.
*/
VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
{
int cchWidth = 0;
switch (enmType)
{
case DBGFREGVALTYPE_R80: cchWidth = 0; break;
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
/* no default, want gcc warnings */
}
if (fSpecial)
if (cchWidth != 0)
fFlags |= RTSTR_F_WIDTH;
}
/**
* @callback_method_impl{FNSTRFORMAT}
*/
static DECLCALLBACK(size_t)
{
/*
* Parse out the register bits of the register format type. Noisily reject
* unknown format types.
*/
const char *pszFormat = *ppszFormat;
if ( pszFormat[0] != 'V'
{
return 0;
}
unsigned uBase;
uBase = 16;
uBase = 10;
uBase = 8;
uBase = 2;
else
{
return 0;
}
/*
* Look up the register - same as dbgfR3RegResolve, except for locking and
* input string termination.
*/
/* Try looking up the name without any case folding or cpu prefixing. */
PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(&pThis->pVM->dbgf.s.RegSpace, pachReg, cchReg);
if (!pLookupRec)
{
/* Lower case it and try again. */
ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szTmp, sizeof(szTmp) - DBGF_REG_MAX_NAME);
if (cchFolded > 0)
if ( !pLookupRec
&& cchFolded >= 0
{
/* Prefix it with the specified CPU set. */
}
}
0);
/* Commit the format type parsing so we can return more freely below. */
*ppszFormat = pszFormat;
/*
* Get the register value.
*/
if (RT_FAILURE(rc))
{
if (pErr)
}
/*
* Format the value.
*/
ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
if (RT_UNLIKELY(cchOutput <= 0))
{
AssertFailed();
}
}
/**
* @callback_method_impl{FNRTSTROUTPUT}
*/
static DECLCALLBACK(size_t)
{
{
}
if (cbToCopy > 0)
{
}
return cbToCopy;
}
/**
* On CPU worker for the register formatting, used by DBGFR3RegNmPrintfV.
*
* @returns VBox status code.
*
* @param pArgs The argument package and state.
*/
{
RTStrFormatV(dbgfR3RegNmPrintfCbOutput, pArgs, dbgfR3RegNmPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
}
/**
* Format a registers.
*
* This is restricted to registers from one CPU, that specified by @a idCpu.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param idCpu The CPU ID of any CPU registers that may be
* printed, pass VMCPUID_ANY if not applicable.
* @param pszBuf The output buffer.
* @param cbBuf The size of the output buffer.
* @param pszFormat The format string. Register names are given by
* %VR{name}, they take no arguments.
* @param va Other format arguments.
*/
VMMR3DECL(int) DBGFR3RegNmPrintfV(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
{
*pszBuf = '\0';
/*
* Set up an argument package and execute the formatting on the
* specified CPU.
*/
return rc;
}
/**
* Format a registers.
*
* This is restricted to registers from one CPU, that specified by @a idCpu.
*
* @returns VBox status code.
* @param pVM The VM handle.
* @param idCpu The CPU ID of any CPU registers that may be
* printed, pass VMCPUID_ANY if not applicable.
* @param pszBuf The output buffer.
* @param cbBuf The size of the output buffer.
* @param pszFormat The format string. Register names are given by
* %VR{name}, %VRU{name}, %VRO{name} and
* %VRB{name}, which are hexadecimal, (unsigned)
* decimal, octal and binary representation. None
* of these types takes any arguments.
* @param ... Other format arguments.
*/
VMMR3DECL(int) DBGFR3RegNmPrintf(PVM pVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
{
return rc;
}