DBGFReg.cpp revision 456eb07edf7d6d1f5a203f4cb35e6de4a5e25cb4
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/* $Id$ */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** @file
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGF - Debugger Facility, Register Methods.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Copyright (C) 2010-2013 Oracle Corporation
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * available from http://www.virtualbox.org. This file is free software;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * you can redistribute it and/or modify it under the terms of the GNU
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * General Public License (GPL) as published by the Free Software
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*******************************************************************************
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync* Header Files *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define LOG_GROUP LOG_GROUP_DBGF
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/vmm/dbgf.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include "DBGFInternal.h"
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/vmm/mm.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/vmm/vm.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/vmm/uvm.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/param.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/err.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <VBox/log.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <iprt/ctype.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <iprt/string.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#include <iprt/uint128.h>
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*******************************************************************************
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync* Defined Constants And Macros *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Locks the register database for writing. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define DBGF_REG_DB_LOCK_WRITE(pUVM) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rcSem = RTSemRWRequestWrite((pUVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertRC(rcSem); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync } while (0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Unlocks the register database after writing. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define DBGF_REG_DB_UNLOCK_WRITE(pUVM) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rcSem = RTSemRWReleaseWrite((pUVM)->dbgf.s.hRegDbLock); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertRC(rcSem); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync } while (0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Locks the register database for reading. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define DBGF_REG_DB_LOCK_READ(pUVM) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rcSem = RTSemRWRequestRead((pUVM)->dbgf.s.hRegDbLock, RT_INDEFINITE_WAIT); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertRC(rcSem); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync } while (0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Unlocks the register database after reading. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define DBGF_REG_DB_UNLOCK_READ(pUVM) \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync do { \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rcSem = RTSemRWReleaseRead((pUVM)->dbgf.s.hRegDbLock); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertRC(rcSem); \
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync } while (0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** The max length of a set, register or sub-field name. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#define DBGF_REG_MAX_NAME 40
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/*******************************************************************************
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync* Structures and Typedefs *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync*******************************************************************************/
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Register set registration record type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef enum DBGFREGSETTYPE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Invalid zero value. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGSETTYPE_INVALID = 0,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** CPU record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGSETTYPE_CPU,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Device record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGSETTYPE_DEVICE,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** End of valid record types. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGSETTYPE_END
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DBGFREGSETTYPE;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Register set registration record.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct DBGFREGSET
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** String space core. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTSTRSPACECORE Core;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The registration record type. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGSETTYPE enmType;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The user argument for the callbacks. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync union
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The CPU view. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PVMCPU pVCpu;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The device view. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PPDMDEVINS pDevIns;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The general view. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync void *pv;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync } uUserArg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The register descriptors. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGDESC paDescs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The number of register descriptors. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t cDescs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Array of lookup records.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * The first part of the array runs parallel to paDescs, the rest are
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * covering for aliases and bitfield variations. It's done this way to
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * simplify the query all operations. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync struct DBGFREGLOOKUP *paLookupRecs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The number of lookup records. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t cLookupRecs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The register name prefix. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szPrefix[1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DBGFREGSET;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a register registration record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFREGSET *PDBGFREGSET;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a const register registration record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFREGSET const *PCDBGFREGSET;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Register lookup record.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct DBGFREGLOOKUP
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The string space core. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTSTRSPACECORE Core;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the set. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGSET pSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Pointer to the register descriptor. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGDESC pDesc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** If an alias this points to the alias descriptor, NULL if not. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGALIAS pAlias;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** If a sub-field this points to the sub-field descriptor, NULL if not. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGSUBFIELD pSubField;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DBGFREGLOOKUP;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a register lookup record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFREGLOOKUP *PDBGFREGLOOKUP;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a const register lookup record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFREGLOOKUP const *PCDBGFREGLOOKUP;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Argument packet from DBGFR3RegNmQueryAll to dbgfR3RegNmQueryAllWorker.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef struct DBGFR3REGNMQUERYALLARGS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The output register array. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGENTRYNM paRegs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The number of entries in the output array. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t cRegs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The current register number when enumerating the string space.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @remarks Only used by EMT(0). */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t iReg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DBGFR3REGNMQUERYALLARGS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a dbgfR3RegNmQueryAllWorker argument packet. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFR3REGNMQUERYALLARGS *PDBGFR3REGNMQUERYALLARGS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Argument packet passed by DBGFR3RegPrintfV to dbgfR3RegPrintfCbOutput and
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * dbgfR3RegPrintfCbFormat.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsynctypedef struct DBGFR3REGPRINTFARGS
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync{
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync /** The user mode VM handle. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PUVM pUVM;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The target CPU. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VMCPUID idCpu;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** Set if we're looking at guest registers. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool fGuestRegs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The output buffer. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char *pszBuf;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The format string. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync const char *pszFormat;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The va list with format arguments. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync va_list va;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The current buffer offset. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t offBuf;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The amount of buffer space left, not counting the terminator char. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t cchLeftBuf;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** The status code of the whole operation. First error is return,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * subsequent ones are suppressed. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync} DBGFR3REGPRINTFARGS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/** Pointer to a DBGFR3RegPrintfV argument packet. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsynctypedef DBGFR3REGPRINTFARGS *PDBGFR3REGPRINTFARGS;
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Initializes the register database.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncint dbgfR3RegInit(PUVM pUVM)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pUVM->dbgf.s.fRegDbInitialized)
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = RTSemRWCreate(&pUVM->dbgf.s.hRegDbLock);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->dbgf.s.fRegDbInitialized = RT_SUCCESS(rc);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Terminates the register database.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncvoid dbgfR3RegTerm(PUVM pUVM)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTSemRWDestroy(pUVM->dbgf.s.hRegDbLock);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->dbgf.s.hRegDbLock = NIL_RTSEMRW;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->dbgf.s.fRegDbInitialized = false;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Validates a register name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * This is used for prefixes, aliases and field names.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns true if valid, false if not.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pszName The register name to validate.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param chDot Set to '.' if accepted, otherwise 0.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic bool dbgfR3RegIsNameValid(const char *pszName, char chDot)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync const char *psz = pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!RT_C_IS_ALPHA(*psz))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return false;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char ch;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while ((ch = *++psz))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ( !RT_C_IS_LOWER(ch)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && !RT_C_IS_DIGIT(ch)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && ch != '_'
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && ch != chDot)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return false;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (psz - pszName > DBGF_REG_MAX_NAME)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return false;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return true;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Common worker for registering a register set.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param paRegisters The register descriptors.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmType The set type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pvUserArg The user argument for the callbacks.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pszPrefix The name prefix.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param iInstance The instance number to be appended to @a
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * pszPrefix when creating the set name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int dbgfR3RegRegisterCommon(PUVM pUVM, PCDBGFREGDESC paRegisters, DBGFREGSETTYPE enmType, void *pvUserArg,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync const char *pszPrefix, uint32_t iInstance)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Validate input.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* The name components. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(dbgfR3RegIsNameValid(pszPrefix, 0), ("%s\n", pszPrefix), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync const char *psz = RTStrEnd(pszPrefix, RTSTR_MAX);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool const fNeedUnderscore = RT_C_IS_DIGIT(psz[-1]);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t const cchPrefix = psz - pszPrefix + fNeedUnderscore;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(cchPrefix < RT_SIZEOFMEMB(DBGFREGSET, szPrefix) - 4 - 1, ("%s\n", pszPrefix), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(iInstance <= 9999, ("%d\n", iInstance), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* The descriptors. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t cLookupRecs = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t iDesc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (iDesc = 0; paRegisters[iDesc].pszName != NULL; iDesc++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(dbgfR3RegIsNameValid(paRegisters[iDesc].pszName, 0), ("%s (#%u)\n", paRegisters[iDesc].pszName, iDesc), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (enmType == DBGFREGSETTYPE_CPU)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn((unsigned)paRegisters[iDesc].enmReg == iDesc && iDesc < (unsigned)DBGFREG_END,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ("%d iDesc=%d\n", paRegisters[iDesc].enmReg, iDesc),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(paRegisters[iDesc].enmReg == DBGFREG_END, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn( paRegisters[iDesc].enmType > DBGFREGVALTYPE_INVALID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && paRegisters[iDesc].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(!(paRegisters[iDesc].fFlags & ~DBGFREG_FLAGS_READ_ONLY),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ("%#x (#%u)\n", paRegisters[iDesc].fFlags, iDesc),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(paRegisters[iDesc].pfnGet, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(RT_VALID_PTR(paRegisters[iDesc].pfnSet) || (paRegisters[iDesc].fFlags & DBGFREG_FLAGS_READ_ONLY),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t iAlias = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGALIAS paAliases = paRegisters[iDesc].paAliases;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (paAliases)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(paAliases, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (; paAliases[iAlias].pszName; iAlias++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(dbgfR3RegIsNameValid(paAliases[iAlias].pszName, 0), ("%s (%s)\n", paAliases[iAlias].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn( paAliases[iAlias].enmType > DBGFREGVALTYPE_INVALID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && paAliases[iAlias].enmType < DBGFREGVALTYPE_END, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t iSubField = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGSUBFIELD paSubFields = paRegisters[iDesc].paSubFields;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (paSubFields)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(paSubFields, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (; paSubFields[iSubField].pszName; iSubField++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(dbgfR3RegIsNameValid(paSubFields[iSubField].pszName, '.'), ("%s (%s)\n", paSubFields[iSubField].pszName, paRegisters[iDesc].pszName), VERR_INVALID_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(paSubFields[iSubField].iFirstBit + paSubFields[iSubField].cBits <= 128, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(paSubFields[iSubField].cBits + paSubFields[iSubField].cShift <= 128, VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrNullReturn(paSubFields[iSubField].pfnGet, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrNullReturn(paSubFields[iSubField].pfnSet, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync cLookupRecs += (1 + iAlias) * (1 + iSubField);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Check the instance number of the CPUs. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(enmType != DBGFREGSETTYPE_CPU || iInstance < pUVM->cCpus, VERR_INVALID_CPU_ID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Allocate a new record and all associated lookup records.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t cbRegSet = RT_OFFSETOF(DBGFREGSET, szPrefix[cchPrefix + 4 + 1]);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync cbRegSet = RT_ALIGN_Z(cbRegSet, 32);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t const offLookupRecArray = cbRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync cbRegSet += cLookupRecs * sizeof(DBGFREGLOOKUP);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGSET pRegSet = (PDBGFREGSET)MMR3HeapAllocZU(pUVM, MM_TAG_DBGF_REG, cbRegSet);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pRegSet)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_NO_MEMORY;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Initialize the new record.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->Core.pszString = pRegSet->szPrefix;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->enmType = enmType;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->uUserArg.pv = pvUserArg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->paDescs = paRegisters;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->cDescs = iDesc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->cLookupRecs = cLookupRecs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pRegSet->paLookupRecs = (PDBGFREGLOOKUP)((uintptr_t)pRegSet + offLookupRecArray);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync if (fNeedUnderscore)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTStrPrintf(pRegSet->szPrefix, cchPrefix + 4 + 1, "%s_%u", pszPrefix, iInstance);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTStrPrintf(pRegSet->szPrefix, cchPrefix + 4 + 1, "%s%u", pszPrefix, iInstance);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Initialize the lookup records. See DBGFREGSET::paLookupRecs.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szName[DBGF_REG_MAX_NAME * 3 + 16];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync strcpy(szName, pRegSet->szPrefix);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char *pszReg = strchr(szName, '\0');
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pszReg++ = '.';
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Array parallel to the descriptors. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGLOOKUP pLookupRec = &pRegSet->paLookupRecs[0];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (iDesc = 0; paRegisters[iDesc].pszName != NULL && RT_SUCCESS(rc); iDesc++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync strcpy(pszReg, paRegisters[iDesc].pszName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->Core.pszString = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_REG, szName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pLookupRec->Core.pszString)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = VERR_NO_STR_MEMORY;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync pLookupRec->pSet = pRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pDesc = &paRegisters[iDesc];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pAlias = NULL;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pSubField = NULL;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync pLookupRec++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Aliases and sub-fields. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync for (iDesc = 0; paRegisters[iDesc].pszName != NULL && RT_SUCCESS(rc); iDesc++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGALIAS pCurAlias = NULL; /* first time we add sub-fields for the real name. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGALIAS pNextAlias = paRegisters[iDesc].paAliases;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync const char *pszRegName = paRegisters[iDesc].pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Add sub-field records. */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync PCDBGFREGSUBFIELD paSubFields = paRegisters[iDesc].paSubFields;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (paSubFields)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t cchReg = strlen(pszRegName);
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync memcpy(pszReg, pszRegName, cchReg);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char *pszSub = &pszReg[cchReg];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pszSub++ = '.';
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (uint32_t iSubField = 0; paSubFields[iSubField].pszName && RT_SUCCESS(rc); iSubField++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync strcpy(pszSub, paSubFields[iSubField].pszName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->Core.pszString = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_REG, szName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pLookupRec->Core.pszString)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = VERR_NO_STR_MEMORY;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pSet = pRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pDesc = &paRegisters[iDesc];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pAlias = pCurAlias;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pSubField = &paSubFields[iSubField];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Advance to the next alias. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pCurAlias = pNextAlias++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pCurAlias)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pszRegName = pCurAlias->pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pszRegName)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* The alias record. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync strcpy(pszReg, pszRegName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->Core.pszString = MMR3HeapStrDupU(pUVM, MM_TAG_DBGF_REG, szName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pLookupRec->Core.pszString)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = VERR_NO_STR_MEMORY;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pSet = pRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pDesc = &paRegisters[iDesc];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pAlias = pCurAlias;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec->pSubField = NULL;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync Assert(pLookupRec == &pRegSet->paLookupRecs[pRegSet->cLookupRecs]);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync if (RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Insert the record into the register set string space and optionally into
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * the CPU register set cache.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGF_REG_DB_LOCK_WRITE(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool fInserted = RTStrSpaceInsert(&pUVM->dbgf.s.RegSetSpace, &pRegSet->Core);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (fInserted)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->dbgf.s.cRegs += pRegSet->cDescs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (enmType == DBGFREGSETTYPE_CPU)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (pRegSet->cDescs > DBGFREG_ALL_COUNT)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->dbgf.s.cRegs -= pRegSet->cDescs - DBGFREG_ALL_COUNT;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!strcmp(pszPrefix, "cpu"))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->aCpus[iInstance].dbgf.s.pGuestRegSet = pRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM->aCpus[iInstance].dbgf.s.pHyperRegSet = pRegSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGLOOKUP paLookupRecs = pRegSet->paLookupRecs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uint32_t iLookupRec = pRegSet->cLookupRecs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (iLookupRec-- > 0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool fInserted2 = RTStrSpaceInsert(&pUVM->dbgf.s.RegSpace, &paLookupRecs[iLookupRec].Core);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsg(fInserted2, ("'%s'", paLookupRecs[iLookupRec].Core.pszString)); NOREF(fInserted2);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGF_REG_DB_UNLOCK_WRITE(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGF_REG_DB_UNLOCK_WRITE(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = VERR_DUPLICATE;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Bail out.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync for (uint32_t i = 0; i < pRegSet->cLookupRecs; i++)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync MMR3HeapFree((char *)pRegSet->paLookupRecs[i].Core.pszString);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync MMR3HeapFree(pRegSet);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Registers a set of registers for a CPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pVM Pointer to the VM.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pVCpu Pointer to the VMCPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param paRegisters The register descriptors.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param fGuestRegs Set if it's the guest registers, clear if
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * hypervisor registers.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters, bool fGuestRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PUVM pUVM = pVM->pUVM;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pUVM->dbgf.s.fRegDbInitialized)
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = dbgfR3RegInit(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_FAILURE(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync return dbgfR3RegRegisterCommon(pUVM, paRegisters, DBGFREGSETTYPE_CPU, pVCpu,
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync fGuestRegs ? "cpu" : "hypercpu", pVCpu->idCpu);
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync}
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Registers a set of registers for a device.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * @param pVM Pointer to the VM.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * @param paRegisters The register descriptors.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * @param pDevIns The device instance. This will be the callback user
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * argument.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * @param pszPrefix The device name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param iInstance The device instance.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3_INT_DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync const char *pszPrefix, uint32_t iInstance)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync AssertPtrReturn(paRegisters, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(pDevIns, VERR_INVALID_POINTER);
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync AssertPtrReturn(pszPrefix, VERR_INVALID_POINTER);
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync return dbgfR3RegRegisterCommon(pVM->pUVM, paRegisters, DBGFREGSETTYPE_DEVICE, pDevIns, pszPrefix, iInstance);
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync}
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync/**
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * Clears the register value variable.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue The variable to clear.
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync */
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsyncDECLINLINE(void) dbgfR3RegValClear(PDBGFREGVAL pValue)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->au64[0] = 0;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync pValue->au64[1] = 0;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync}
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue The value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param u64 The integer value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncDECLINLINE(void) dbgfR3RegValR80SetU64(PDBGFREGVAL pValue, uint64_t u64)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo fixme */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.fSign = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.uExponent = 16383;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.u64Mantissa = u64;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Sets a 80-bit floating point variable to a 64-bit unsigned interger value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue The value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param u128 The integer value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncDECLINLINE(void) dbgfR3RegValR80SetU128(PDBGFREGVAL pValue, RTUINT128U u128)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo fixme */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.fSign = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.uExponent = 16383;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pValue->r80.s.u64Mantissa = u128.s.Lo;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Get a 80-bit floating point variable as a 64-bit unsigned integer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns 64-bit unsigned integer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue The value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncDECLINLINE(uint64_t) dbgfR3RegValR80GetU64(PCDBGFREGVAL pValue)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo stupid, stupid MSC. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return pValue->r80.s.u64Mantissa;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Get a 80-bit floating point variable as a 128-bit unsigned integer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns 128-bit unsigned integer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue The value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncDECLINLINE(RTUINT128U) dbgfR3RegValR80GetU128(PCDBGFREGVAL pValue)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /** @todo stupid, stupid MSC. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync RTUINT128U uRet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#if 0
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uRet.s.Lo = (uint64_t)InVal.lrd;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uRet.s.Hi = (uint64_t)InVal.lrd / _4G / _4G;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uRet.s.Lo = pValue->r80.s.u64Mantissa;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync uRet.s.Hi = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
3614117c1132a61599e6190939e775cafe549411vboxsync return uRet;
034f0367d3b0431c6346b1a3af3abb435ee50d4evboxsync}
3614117c1132a61599e6190939e775cafe549411vboxsync
3614117c1132a61599e6190939e775cafe549411vboxsync
3614117c1132a61599e6190939e775cafe549411vboxsync/**
3614117c1132a61599e6190939e775cafe549411vboxsync * Performs a cast between register value types.
3614117c1132a61599e6190939e775cafe549411vboxsync *
3614117c1132a61599e6190939e775cafe549411vboxsync * @retval VINF_SUCCESS
3614117c1132a61599e6190939e775cafe549411vboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
3614117c1132a61599e6190939e775cafe549411vboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
3614117c1132a61599e6190939e775cafe549411vboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
3614117c1132a61599e6190939e775cafe549411vboxsync *
3614117c1132a61599e6190939e775cafe549411vboxsync * @param pValue The value to cast (input + output).
3614117c1132a61599e6190939e775cafe549411vboxsync * @param enmFromType The input value.
3614117c1132a61599e6190939e775cafe549411vboxsync * @param enmToType The desired output value.
3614117c1132a61599e6190939e775cafe549411vboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int dbgfR3RegValCast(PDBGFREGVAL pValue, DBGFREGVALTYPE enmFromType, DBGFREGVALTYPE enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGVAL const InVal = *pValue;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync dbgfR3RegValClear(pValue);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Note! No default cases here as gcc warnings about missing enum values
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync are desired. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmFromType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u8; return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u8; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u8); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_INVALID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U16:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u16; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u16; return VINF_SUCCESS;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u16; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u16); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_INVALID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u32; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u32; return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u32; return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u32); return VINF_DBGF_ZERO_EXTENDED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_INVALID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u64; return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.u64; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.u64); return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync case DBGFREGVALTYPE_INVALID:
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync break;
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (enmToType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.u128.s.Lo; return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128: pValue->u128 = InVal.u128; return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU128(pValue, InVal.u128); return VINF_DBGF_TRUNCATED_REGISTER;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_INVALID:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_R80:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync switch (enmToType)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U8: pValue->u8 = (uint8_t )dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U16: pValue->u16 = (uint16_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U32: pValue->u32 = (uint32_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U64: pValue->u64 = (uint64_t)dbgfR3RegValR80GetU64(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U128: pValue->u128 = dbgfR3RegValR80GetU128(&InVal); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_R80: pValue->r80 = InVal.r80; return VINF_SUCCESS;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_DTR: return VERR_DBGF_UNSUPPORTED_CAST;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_32BIT_HACK:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_END:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_INVALID:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync break;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_DTR:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync switch (enmToType)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U8: pValue->u8 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U16: pValue->u16 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U32: pValue->u32 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U64: pValue->u64 = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_U128: pValue->u128.s.Lo = InVal.dtr.u64Base; return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_R80: dbgfR3RegValR80SetU64(pValue, InVal.dtr.u64Base); return VINF_DBGF_TRUNCATED_REGISTER;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_DTR: pValue->dtr = InVal.dtr; return VINF_SUCCESS;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_32BIT_HACK:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_END:
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync case DBGFREGVALTYPE_INVALID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_INVALID:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_END:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_32BIT_HACK:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgFailed(("%d / %d\n", enmFromType, enmToType));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_DBGF_UNSUPPORTED_CAST;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Worker for the CPU register queries.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The virtual CPU ID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmReg The register to query.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmType The desired return type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param fGuestRegs Query guest CPU registers if set (true),
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * hypervisor CPU registers if clear (false).
36fbf6dcd3e6b2e5891456b730577ff0eb355c9fvboxsync * @param pValue Where to return the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) dbgfR3RegCpuQueryWorkerOnCpu(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool fGuestRegs, PDBGFREGVAL pValue)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGF_REG_DB_LOCK_READ(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Look up the register set of the specified CPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGSET pSet = fGuestRegs
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ? pUVM->aCpus[idCpu].dbgf.s.pGuestRegSet
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync : pUVM->aCpus[idCpu].dbgf.s.pHyperRegSet;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync if (RT_LIKELY(pSet))
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /*
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Look up the register and get the register value.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync if (RT_LIKELY(pSet->cDescs > (size_t)enmReg))
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync pValue->au64[0] = pValue->au64[1] = 0;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync if (RT_SUCCESS(rc))
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync {
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync /*
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * Do the cast if the desired return type doesn't match what
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync * the getter returned.
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync */
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync if (pDesc->enmType == enmType)
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync rc = VINF_SUCCESS;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync else
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync rc = dbgfR3RegValCast(pValue, pDesc->enmType, enmType);
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync else
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync rc = VERR_DBGF_REGISTER_NOT_FOUND;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync }
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync else
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync rc = VERR_INVALID_CPU_ID;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync DBGF_REG_DB_UNLOCK_READ(pUVM);
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync return rc;
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync}
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
ac6445a70a26cb69d08734f1d9dbc171cec86cd8vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Internal worker for the CPU register query functions.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The virtual CPU ID. Can be OR'ed with
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_HYPER_VMCPUID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmReg The register to query.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmType The desired return type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue Where to return the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic int dbgfR3RegCpuQueryWorker(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, DBGFREGVALTYPE enmType, PDBGFREGVAL pValue)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(enmReg >= DBGFREG_AL && enmReg <= DBGFREG_END, ("%d\n", enmReg), VERR_INVALID_PARAMETER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool const fGuestRegs = !(idCpu & DBGFREG_HYPER_VMCPUID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync idCpu &= ~DBGFREG_HYPER_VMCPUID;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VMR3ReqPriorityCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryWorkerOnCpu, 6,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pUVM, idCpu, enmReg, enmType, fGuestRegs, pValue);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Queries a 8-bit CPU register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The target CPU ID. Can be OR'ed with
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_HYPER_VMCPUID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmReg The register that's being queried.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pu8 Where to store the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryU8(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGVAL Value;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U8, &Value);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu8 = Value.u8;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu8 = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Queries a 16-bit CPU register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The target CPU ID. Can be OR'ed with
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_HYPER_VMCPUID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmReg The register that's being queried.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pu16 Where to store the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryU16(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGVAL Value;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U16, &Value);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu16 = Value.u16;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu16 = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Queries a 32-bit CPU register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The target CPU ID. Can be OR'ed with
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_HYPER_VMCPUID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmReg The register that's being queried.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pu32 Where to store the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryU32(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGVAL Value;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U32, &Value);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = Value.u32;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pu32 = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Queries a 64-bit CPU register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_UNSUPPORTED_CAST
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_TRUNCATED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param pUVM The user mode VM handle.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param idCpu The target CPU ID. Can be OR'ed with
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * DBGFREG_HYPER_VMCPUID.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param enmReg The register that's being queried.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param pu64 Where to store the register value.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync */
23603ed361f22874964e3a841add2c58ec2bb1eavboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryU64(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64)
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync{
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync DBGFREGVAL Value;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync int rc = dbgfR3RegCpuQueryWorker(pUVM, idCpu, enmReg, DBGFREGVALTYPE_U64, &Value);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync if (RT_SUCCESS(rc))
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync *pu64 = Value.u64;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync else
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync *pu64 = 0;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync return rc;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync}
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync#if 0 /* rewrite / remove */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Wrapper around CPUMQueryGuestMsr for dbgfR3RegCpuQueryBatchWorker.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pVCpu The current CPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pReg The where to store the register value and
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * size.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idMsr The MSR to get.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic void dbgfR3RegGetMsrBatch(PVMCPU pVCpu, PDBGFREGENTRY pReg, uint32_t idMsr)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->enmType = DBGFREGVALTYPE_U64;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = CPUMQueryGuestMsr(pVCpu, idMsr, &pReg->Val.u64);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_FAILURE(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsg(rc == VERR_CPUM_RAISE_GP_0, ("%Rrc\n", rc));
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.u64 = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync}
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync
5045ab9ca39fa0b301f4020b7a072406eb0ecea2vboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) dbgfR3RegCpuQueryBatchWorker(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#if 0
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PVMCPU pVCpu = &pUVM->pVM->aCpus[idCpu];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCCPUMCTX pCtx = CPUMQueryGuestCtxPtr(pVCpu);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGENTRY pReg = paRegs - 1;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (cRegs-- > 0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au64[0] = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au64[1] = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREG const enmReg = pReg->enmReg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(enmReg >= 0 && enmReg <= DBGFREG_END, ("%d (%#x)\n", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (enmReg != DBGFREG_END)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGDESC pDesc = &g_aDbgfRegDescs[enmReg];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pDesc->pfnGet)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCRTUINT128U pu = (PCRTUINT128U)((uintptr_t)pCtx + pDesc->offCtx);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->enmType = pDesc->enmType;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync switch (pDesc->enmType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U8: pReg->Val.u8 = pu->au8[0]; break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U16: pReg->Val.u16 = pu->au16[0]; break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U32: pReg->Val.u32 = pu->au32[0]; break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U64: pReg->Val.u64 = pu->au64[0]; break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_U128:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au64[0] = pu->au64[0];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au64[1] = pu->au64[1];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync case DBGFREGVALTYPE_R80:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au64[0] = pu->au64[0];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pReg->Val.au16[5] = pu->au16[5];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync break;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync default:
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgFailedReturn(("%s %d\n", pDesc->pszName, pDesc->enmType), VERR_IPE_NOT_REACHED_DEFAULT_CASE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc = pDesc->pfnGet(pVCpu, pDesc, pCtx, &pReg->Val.u);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_FAILURE(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_NOT_IMPLEMENTED;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Query a batch of registers.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The target CPU ID. Can be OR'ed with
3614117c1132a61599e6190939e775cafe549411vboxsync * DBGFREG_HYPER_VMCPUID.
3614117c1132a61599e6190939e775cafe549411vboxsync * @param paRegs Pointer to an array of @a cRegs elements. On
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * input the enmReg members indicates which
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * registers to query. On successful return the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * other members are set. DBGFREG_END can be used
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * as a filler.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cRegs The number of entries in @a paRegs.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryBatch(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t iReg = cRegs;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (iReg-- > 0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREG enmReg = paRegs[iReg].enmReg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertMsgReturn(enmReg < DBGFREG_END && enmReg >= DBGFREG_AL, ("%d (%#x)", enmReg, enmReg), VERR_DBGF_REGISTER_NOT_FOUND);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VMR3ReqCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pUVM, idCpu, paRegs, cRegs);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Query all registers for a Virtual CPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_VM_HANDLE
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_INVALID_CPU_ID
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idCpu The target CPU ID. Can be OR'ed with
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_HYPER_VMCPUID.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param paRegs Pointer to an array of @a cRegs elements.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * These will be filled with the CPU register
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * values. Overflowing entries will be set to
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * DBGFREG_END. The returned registers can be
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * accessed by using the DBGFREG values as index.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cRegs The number of entries in @a paRegs. The
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * recommended value is DBGFREG_ALL_COUNT.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegCpuQueryAll(PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Validate input.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(idCpu < pUVM->cCpus, VERR_INVALID_CPU_ID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn(cRegs < _1M, VERR_OUT_OF_RANGE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Convert it into a batch query (lazy bird).
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync unsigned iReg = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (iReg < cRegs && iReg < DBGFREG_ALL_COUNT)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync paRegs[iReg].enmReg = (DBGFREG)iReg;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync iReg++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (iReg < cRegs)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync paRegs[iReg++].enmReg = DBGFREG_END;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VMR3ReqCallWaitU(pUVM, idCpu, (PFNRT)dbgfR3RegCpuQueryBatchWorker, 4, pUVM, idCpu, paRegs, cRegs);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync#endif /* rewrite or remove? */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Gets the name of a register.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns Pointer to read-only register name (lower case). NULL if the
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * parameters are invalid.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync *
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param pUVM The user mode VM handle.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param enmReg The register identifier.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * @param enmType The register type. This is for sort out
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * aliases. Pass DBGFREGVALTYPE_INVALID to get
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync * the standard name.
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync */
23603ed361f22874964e3a841add2c58ec2bb1eavboxsyncVMMR3DECL(const char *) DBGFR3RegCpuName(PUVM pUVM, DBGFREG enmReg, DBGFREGVALTYPE enmType)
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync{
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync AssertReturn(enmReg >= DBGFREG_AL && enmReg < DBGFREG_END, NULL);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync AssertReturn(enmType >= DBGFREGVALTYPE_INVALID && enmType < DBGFREGVALTYPE_END, NULL);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, NULL);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, NULL);
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync PCDBGFREGSET pSet = pUVM->aCpus[0].dbgf.s.pGuestRegSet;
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync if (RT_UNLIKELY(!pSet))
23603ed361f22874964e3a841add2c58ec2bb1eavboxsync return NULL;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGDESC pDesc = &pSet->paDescs[enmReg];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGALIAS pAlias = pDesc->paAliases;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ( pAlias
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && pDesc->enmType != enmType
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && enmType != DBGFREGVALTYPE_INVALID)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (pAlias->pszName)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (pAlias->enmType == enmType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return pAlias->pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pAlias++;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return pDesc->pszName;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Fold the string to lower case and copy it into the destination buffer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns Number of folder characters, -1 on overflow.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pszSrc The source string.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cchSrc How much to fold and copy.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pszDst The output buffer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param cbDst The size of the output buffer.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic ssize_t dbgfR3RegCopyToLower(const char *pszSrc, size_t cchSrc, char *pszDst, size_t cbDst)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ssize_t cchFolded = 0;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char ch;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync while (cchSrc-- > 0 && (ch = *pszSrc++))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_UNLIKELY(cbDst <= 1))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return -1;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync cbDst--;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char chLower = RT_C_TO_LOWER(ch);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync cchFolded += chLower != ch;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pszDst++ = chLower;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (RT_UNLIKELY(!cbDst))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return -1;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *pszDst = '\0';
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return cchFolded;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Resolves the register name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns Lookup record.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * @param idDefCpu The default CPU ID set.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * @param pszReg The register name.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * @param fGuestRegs Default to guest CPU registers if set, the
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync * hypervisor CPU registers if clear.
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync */
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsyncstatic PCDBGFREGLOOKUP dbgfR3RegResolve(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, bool fGuestRegs)
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync{
9540eeb13face31ddc1c5f15338556fe46f18a77vboxsync DBGF_REG_DB_LOCK_READ(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Try looking up the name without any case folding or cpu prefixing. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PRTSTRSPACE pRegSpace = &pUVM->dbgf.s.RegSpace;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, pszReg);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pLookupRec)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync char szName[DBGF_REG_MAX_NAME * 4 + 16];
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Lower case it and try again. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync ssize_t cchFolded = dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (cchFolded > 0)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ( !pLookupRec
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && cchFolded >= 0
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && idDefCpu != VMCPUID_ANY)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /* Prefix it with the specified CPU set. */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), fGuestRegs ? "cpu%u." : "hypercpu%u.", idDefCpu);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync dbgfR3RegCopyToLower(pszReg, RTSTR_MAX, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGF_REG_DB_UNLOCK_READ(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return pLookupRec;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Validates the register name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VINF_SUCCESS if the register was found.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @retval VERR_DBGF_REGISTER_NOT_FOUND if not found.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param idDefCpu The default CPU.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pszReg The registe name.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncVMMR3DECL(int) DBGFR3RegNmValidate(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Validate input.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Resolve the register.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync bool fGuestRegs = true;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ((idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync fGuestRegs = false;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pUVM, idDefCpu, pszReg, fGuestRegs);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pLookupRec)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VERR_DBGF_REGISTER_NOT_FOUND;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync return VINF_SUCCESS;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync}
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync/**
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * On CPU worker for the register queries, used by dbgfR3RegNmQueryWorker and
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * dbgfR3RegPrintfCbFormatNormal.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @returns VBox status code.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync *
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pUVM The user mode VM handle.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pLookupRec The register lookup record.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param enmType The desired return type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param pValue Where to return the register value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * @param penmType Where to store the register value type.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Optional.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsyncstatic DECLCALLBACK(int) dbgfR3RegNmQueryWorkerOnCpu(PUVM pUVM, PCDBGFREGLOOKUP pLookupRec, DBGFREGVALTYPE enmType,
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync{
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGDESC pDesc = pLookupRec->pDesc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGSET pSet = pLookupRec->pSet;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync PCDBGFREGSUBFIELD pSubField = pLookupRec->pSubField;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync DBGFREGVALTYPE enmValueType = pDesc->enmType;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync int rc;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync NOREF(pUVM);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync /*
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync * Get the register or sub-field value.
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync */
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync dbgfR3RegValClear(pValue);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (!pSubField)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if ( pLookupRec->pAlias
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && pLookupRec->pAlias->enmType != enmValueType
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync && RT_SUCCESS(rc))
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync enmValueType = pLookupRec->pAlias->enmType;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync if (pSubField->pfnGet)
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync {
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync rc = pSubField->pfnGet(pSet->uUserArg.pv, pSubField, &pValue->u128);
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync enmValueType = DBGFREGVALTYPE_U128;
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync }
016096e367cd20c3d3c3fd9a6650b55935c2e31dvboxsync else
{
rc = pDesc->pfnGet(pSet->uUserArg.pv, pDesc, pValue);
if ( pLookupRec->pAlias
&& pLookupRec->pAlias->enmType != enmValueType
&& RT_SUCCESS(rc))
{
rc = dbgfR3RegValCast(pValue, enmValueType, pLookupRec->pAlias->enmType);
enmValueType = pLookupRec->pAlias->enmType;
}
if (RT_SUCCESS(rc))
{
rc = dbgfR3RegValCast(pValue, enmValueType, DBGFREGVALTYPE_U128);
if (RT_SUCCESS(rc))
{
RTUInt128AssignShiftLeft(&pValue->u128, -pSubField->iFirstBit);
RTUInt128AssignAndNFirstBits(&pValue->u128, pSubField->cBits);
if (pSubField->cShift)
RTUInt128AssignShiftLeft(&pValue->u128, pSubField->cShift);
}
}
}
if (RT_SUCCESS(rc))
{
unsigned const cBits = pSubField->cBits + pSubField->cShift;
if (cBits <= 8)
enmValueType = DBGFREGVALTYPE_U8;
else if (cBits <= 16)
enmValueType = DBGFREGVALTYPE_U16;
else if (cBits <= 32)
enmValueType = DBGFREGVALTYPE_U32;
else if (cBits <= 64)
enmValueType = DBGFREGVALTYPE_U64;
else
enmValueType = DBGFREGVALTYPE_U128;
rc = dbgfR3RegValCast(pValue, DBGFREGVALTYPE_U128, enmValueType);
}
}
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
{
rc = dbgfR3RegValCast(pValue, enmValueType, enmType);
if (penmType)
*penmType = RT_SUCCESS(rc) ? enmType : enmValueType;
}
}
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 pUVM The user mode VM handle.
* @param idDefCpu The virtual CPU ID for the default CPU register
* set. Can be OR'ed with DBGFREG_HYPER_VMCPUID.
* @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(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, DBGFREGVALTYPE enmType,
PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
{
/*
* Validate input.
*/
UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
VM_ASSERT_VALID_EXT_RETURN(pUVM->pVM, VERR_INVALID_VM_HANDLE);
AssertReturn((idDefCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idDefCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
AssertPtrReturn(pszReg, VERR_INVALID_POINTER);
Assert(enmType > DBGFREGVALTYPE_INVALID && enmType <= DBGFREGVALTYPE_END);
AssertPtr(pValue);
/*
* Resolve the register and call the getter on the relevant CPU.
*/
bool fGuestRegs = true;
if ((idDefCpu & DBGFREG_HYPER_VMCPUID) && idDefCpu != VMCPUID_ANY)
{
fGuestRegs = false;
idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
}
PCDBGFREGLOOKUP pLookupRec = dbgfR3RegResolve(pUVM, idDefCpu, pszReg, fGuestRegs);
if (pLookupRec)
{
if (pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU)
idDefCpu = pLookupRec->pSet->uUserArg.pVCpu->idCpu;
else if (idDefCpu != VMCPUID_ANY)
idDefCpu &= ~DBGFREG_HYPER_VMCPUID;
return VMR3ReqPriorityCallWaitU(pUVM, idDefCpu, (PFNRT)dbgfR3RegNmQueryWorkerOnCpu, 5,
pUVM, 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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType)
{
return dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_END, pValue, 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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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.
*/
VMMR3DECL(int) DBGFR3RegNmQueryU8(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U8, &Value, NULL);
if (RT_SUCCESS(rc))
*pu8 = Value.u8;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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.
*/
VMMR3DECL(int) DBGFR3RegNmQueryU16(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U16, &Value, NULL);
if (RT_SUCCESS(rc))
*pu16 = Value.u16;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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.
*/
VMMR3DECL(int) DBGFR3RegNmQueryU32(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U32, &Value, NULL);
if (RT_SUCCESS(rc))
*pu32 = Value.u32;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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.
*/
VMMR3DECL(int) DBGFR3RegNmQueryU64(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U64, &Value, NULL);
if (RT_SUCCESS(rc))
*pu64 = Value.u64;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_U128, &Value, NULL);
if (RT_SUCCESS(rc))
*pu128 = Value.u128;
else
pu128->s.Hi = pu128->s.Lo = 0;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_R80, &Value, NULL);
if (RT_SUCCESS(rc))
*plrd = Value.lrd;
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 pUVM The user mode VM handle.
* @param idDefCpu The default target CPU ID, VMCPUID_ANY if not
* applicable. Can be OR'ed with
* DBGFREG_HYPER_VMCPUID.
* @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(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint32_t *pu32Limit)
{
DBGFREGVAL Value;
int rc = dbgfR3RegNmQueryWorker(pUVM, idDefCpu, pszReg, DBGFREGVALTYPE_DTR, &Value, NULL);
if (RT_SUCCESS(rc))
{
*pu64Base = Value.dtr.u64Base;
*pu32Limit = Value.dtr.u32Limit;
}
else
{
*pu64Base = 0;
*pu32Limit = 0;
}
return rc;
}
/// @todo VMMR3DECL(int) DBGFR3RegNmQueryBatch(PUVM pUVM,VMCPUID idDefCpu, DBGFREGENTRYNM paRegs, size_t cRegs);
/**
* Gets the number of registers returned by DBGFR3RegNmQueryAll.
*
* @returns VBox status code.
* @param pUVM The user mode VM handle.
* @param pcRegs Where to return the register count.
*/
VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PUVM pUVM, size_t *pcRegs)
{
UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
*pcRegs = pUVM->dbgf.s.cRegs;
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)
{
if (iReg < cRegs)
{
size_t iEndReg = iReg + cRegsToPad;
if (iEndReg > cRegs)
iEndReg = cRegs;
while (iReg < iEndReg)
{
paRegs[iReg].pszName = NULL;
paRegs[iReg].enmType = DBGFREGVALTYPE_END;
dbgfR3RegValClear(&paRegs[iReg].Val);
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)
{
if (cRegsToQuery > pSet->cDescs)
cRegsToQuery = pSet->cDescs;
if (cRegsToQuery > cRegs)
cRegsToQuery = cRegs;
for (size_t iReg = 0; iReg < cRegsToQuery; iReg++)
{
paRegs[iReg].enmType = pSet->paDescs[iReg].enmType;
paRegs[iReg].pszName = pSet->paLookupRecs[iReg].Core.pszString;
dbgfR3RegValClear(&paRegs[iReg].Val);
int rc2 = pSet->paDescs[iReg].pfnGet(pSet->uUserArg.pv, &pSet->paDescs[iReg], &paRegs[iReg].Val);
AssertRCSuccess(rc2);
if (RT_FAILURE(rc2))
dbgfR3RegValClear(&paRegs[iReg].Val);
}
}
/**
* @callback_method_impl{FNRTSTRSPACECALLBACK, Worker used by
* dbgfR3RegNmQueryAllWorker}
*/
static DECLCALLBACK(int) dbgfR3RegNmQueryAllEnum(PRTSTRSPACECORE pStr, void *pvUser)
{
PCDBGFREGSET pSet = (PCDBGFREGSET)pStr;
if (pSet->enmType != DBGFREGSETTYPE_CPU)
{
PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
if (pArgs->iReg < pArgs->cRegs)
dbgfR3RegNmQueryAllInSet(pSet, pSet->cDescs, &pArgs->paRegs[pArgs->iReg], pArgs->cRegs - pArgs->iReg);
pArgs->iReg += pSet->cDescs;
}
return 0;
}
/**
* @callback_method_impl{FNVMMEMTRENDEZVOUS, Worker used by DBGFR3RegNmQueryAll}
*/
static DECLCALLBACK(VBOXSTRICTRC) dbgfR3RegNmQueryAllWorker(PVM pVM, PVMCPU pVCpu, void *pvUser)
{
PDBGFR3REGNMQUERYALLARGS pArgs = (PDBGFR3REGNMQUERYALLARGS)pvUser;
PDBGFREGENTRYNM paRegs = pArgs->paRegs;
size_t const cRegs = pArgs->cRegs;
PUVM pUVM = pVM->pUVM;
PUVMCPU pUVCpu = pVCpu->pUVCpu;
DBGF_REG_DB_LOCK_READ(pUVM);
/*
* My guest CPU registers.
*/
size_t iCpuReg = pVCpu->idCpu * DBGFREG_ALL_COUNT;
if (pUVCpu->dbgf.s.pGuestRegSet)
{
if (iCpuReg < cRegs)
dbgfR3RegNmQueryAllInSet(pUVCpu->dbgf.s.pGuestRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
}
else
dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
/*
* My hypervisor CPU registers.
*/
iCpuReg = pUVM->cCpus * DBGFREG_ALL_COUNT + pUVCpu->idCpu * DBGFREG_ALL_COUNT;
if (pUVCpu->dbgf.s.pHyperRegSet)
{
if (iCpuReg < cRegs)
dbgfR3RegNmQueryAllInSet(pUVCpu->dbgf.s.pHyperRegSet, DBGFREG_ALL_COUNT, &paRegs[iCpuReg], cRegs - iCpuReg);
}
else
dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, iCpuReg, DBGFREG_ALL_COUNT);
/*
* The primary CPU does all the other registers.
*/
if (pUVCpu->idCpu == 0)
{
pArgs->iReg = pUVM->cCpus * DBGFREG_ALL_COUNT * 2;
RTStrSpaceEnumerate(&pUVM->dbgf.s.RegSetSpace, dbgfR3RegNmQueryAllEnum, pArgs);
dbgfR3RegNmQueryAllPadEntries(paRegs, cRegs, pArgs->iReg, cRegs);
}
DBGF_REG_DB_UNLOCK_READ(pUVM);
return VINF_SUCCESS; /* Ignore errors. */
}
/**
* Queries all register.
*
* @returns VBox status code.
* @param pUVM The user mode 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.
*/
VMMR3DECL(int) DBGFR3RegNmQueryAll(PUVM pUVM, PDBGFREGENTRYNM paRegs, size_t cRegs)
{
UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
PVM pVM = pUVM->pVM;
VM_ASSERT_VALID_EXT_RETURN(pVM, VERR_INVALID_VM_HANDLE);
AssertPtrReturn(paRegs, VERR_INVALID_POINTER);
AssertReturn(cRegs > 0, VERR_OUT_OF_RANGE);
DBGFR3REGNMQUERYALLARGS Args;
Args.paRegs = paRegs;
Args.cRegs = cRegs;
return VMMR3EmtRendezvous(pVM, VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE, dbgfR3RegNmQueryAllWorker, &Args);
}
VMMR3DECL(int) DBGFR3RegNmSet(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType)
{
NOREF(pUVM); NOREF(idDefCpu); NOREF(pszReg); NOREF(pValue); NOREF(enmType);
return VERR_NOT_IMPLEMENTED;
}
/**
* Internal worker for DBGFR3RegFormatValue, cbTmp is sufficent.
*
* @copydoc DBGFR3RegFormatValue
*/
DECLINLINE(ssize_t) dbgfR3RegFormatValueInt(char *pszTmp, size_t cbTmp, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
{
switch (enmType)
{
case DBGFREGVALTYPE_U8:
return RTStrFormatU8(pszTmp, cbTmp, pValue->u8, uBase, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_U16:
return RTStrFormatU16(pszTmp, cbTmp, pValue->u16, uBase, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_U32:
return RTStrFormatU32(pszTmp, cbTmp, pValue->u32, uBase, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_U64:
return RTStrFormatU64(pszTmp, cbTmp, pValue->u64, uBase, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_U128:
return RTStrFormatU128(pszTmp, cbTmp, &pValue->u128, uBase, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_R80:
return RTStrFormatR80u2(pszTmp, cbTmp, &pValue->r80Ex, cchWidth, cchPrecision, fFlags);
case DBGFREGVALTYPE_DTR:
{
ssize_t cch = RTStrFormatU64(pszTmp, cbTmp, pValue->dtr.u64Base,
16, 2+16, 0, RTSTR_F_SPECIAL | RTSTR_F_ZEROPAD);
AssertReturn(cch > 0, VERR_DBGF_REG_IPE_1);
pszTmp[cch++] = ':';
cch += RTStrFormatU64(&pszTmp[cch], cbTmp - cch, pValue->dtr.u32Limit,
16, 4, 0, RTSTR_F_ZEROPAD | RTSTR_F_32BIT);
return cch;
}
case DBGFREGVALTYPE_32BIT_HACK:
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
/* no default, want gcc warnings */
}
RTStrPrintf(pszTmp, cbTmp, "!enmType=%d!", enmType);
return VERR_DBGF_REG_IPE_2;
}
/**
* 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.
*/
VMMR3DECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType,
unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags)
{
/*
* Format to temporary buffer using worker shared with dbgfR3RegPrintfCbFormatNormal.
*/
char szTmp[160];
ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), pValue, enmType, uBase, cchWidth, cchPrecision, fFlags);
if (cchOutput > 0)
{
if ((size_t)cchOutput < cbBuf)
memcpy(pszBuf, szTmp, cchOutput + 1);
else
{
if (cbBuf)
{
memcpy(pszBuf, szTmp, cbBuf - 1);
pszBuf[cbBuf - 1] = '\0';
}
cchOutput = VERR_BUFFER_OVERFLOW;
}
}
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.
*/
VMMR3DECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial)
{
int cchWidth = 0;
switch (enmType)
{
case DBGFREGVALTYPE_U8: cchWidth = 2 + fSpecial*2; break;
case DBGFREGVALTYPE_U16: cchWidth = 4 + fSpecial*2; break;
case DBGFREGVALTYPE_U32: cchWidth = 8 + fSpecial*2; break;
case DBGFREGVALTYPE_U64: cchWidth = 16 + fSpecial*2; break;
case DBGFREGVALTYPE_U128: cchWidth = 32 + fSpecial*2; break;
case DBGFREGVALTYPE_R80: cchWidth = 0; break;
case DBGFREGVALTYPE_DTR: cchWidth = 16+1+4 + fSpecial*2; break;
case DBGFREGVALTYPE_32BIT_HACK:
case DBGFREGVALTYPE_END:
case DBGFREGVALTYPE_INVALID:
break;
/* no default, want gcc warnings */
}
uint32_t fFlags = RTSTR_F_ZEROPAD;
if (fSpecial)
fFlags |= RTSTR_F_SPECIAL;
if (cchWidth != 0)
fFlags |= RTSTR_F_WIDTH;
return DBGFR3RegFormatValueEx(pszBuf, cbBuf, pValue, enmType, 16, cchWidth, 0, fFlags);
}
/**
* Format a register using special hacks as well as sub-field specifications
* (the latter isn't implemented yet).
*/
static size_t
dbgfR3RegPrintfCbFormatField(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
PCDBGFREGLOOKUP pLookupRec, int cchWidth, int cchPrecision, unsigned fFlags)
{
char szTmp[160];
NOREF(cchWidth); NOREF(cchPrecision); NOREF(fFlags);
/*
* Retrieve the register value.
*/
DBGFREGVAL Value;
DBGFREGVALTYPE enmType;
int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pUVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
if (RT_FAILURE(rc))
{
PCRTSTATUSMSG pErr = RTErrGet(rc);
if (pErr)
return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
}
char *psz = szTmp;
/*
* Special case: Format eflags.
*/
if ( pLookupRec->pSet->enmType == DBGFREGSETTYPE_CPU
&& pLookupRec->pDesc->enmReg == DBGFREG_RFLAGS
&& pLookupRec->pSubField == NULL)
{
rc = dbgfR3RegValCast(&Value, enmType, DBGFREGVALTYPE_U32);
AssertRC(rc);
uint32_t const efl = Value.u32;
/* the iopl */
psz += RTStrPrintf(psz, sizeof(szTmp) / 2, "iopl=%u ", X86_EFL_GET_IOPL(efl));
/* add flags */
static const struct
{
const char *pszSet;
const char *pszClear;
uint32_t fFlag;
} aFlags[] =
{
{ "vip",NULL, X86_EFL_VIP },
{ "vif",NULL, X86_EFL_VIF },
{ "ac", NULL, X86_EFL_AC },
{ "vm", NULL, X86_EFL_VM },
{ "rf", NULL, X86_EFL_RF },
{ "nt", NULL, X86_EFL_NT },
{ "ov", "nv", X86_EFL_OF },
{ "dn", "up", X86_EFL_DF },
{ "ei", "di", X86_EFL_IF },
{ "tf", NULL, X86_EFL_TF },
{ "ng", "pl", X86_EFL_SF },
{ "zr", "nz", X86_EFL_ZF },
{ "ac", "na", X86_EFL_AF },
{ "po", "pe", X86_EFL_PF },
{ "cy", "nc", X86_EFL_CF },
};
for (unsigned i = 0; i < RT_ELEMENTS(aFlags); i++)
{
const char *pszAdd = aFlags[i].fFlag & efl ? aFlags[i].pszSet : aFlags[i].pszClear;
if (pszAdd)
{
*psz++ = *pszAdd++;
*psz++ = *pszAdd++;
if (*pszAdd)
*psz++ = *pszAdd++;
*psz++ = ' ';
}
}
/* drop trailing space */
psz--;
}
else
{
/*
* General case.
*/
AssertMsgFailed(("Not implemented: %s\n", pLookupRec->Core.pszString));
return pfnOutput(pvArgOutput, pLookupRec->Core.pszString, pLookupRec->Core.cchString);
}
/* Output the string. */
return pfnOutput(pvArgOutput, szTmp, psz - &szTmp[0]);
}
/**
* Formats a register having parsed up to the register name.
*/
static size_t
dbgfR3RegPrintfCbFormatNormal(PDBGFR3REGPRINTFARGS pThis, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
PCDBGFREGLOOKUP pLookupRec, unsigned uBase, int cchWidth, int cchPrecision, unsigned fFlags)
{
char szTmp[160];
/*
* Get the register value.
*/
DBGFREGVAL Value;
DBGFREGVALTYPE enmType;
int rc = dbgfR3RegNmQueryWorkerOnCpu(pThis->pUVM, pLookupRec, DBGFREGVALTYPE_END, &Value, &enmType);
if (RT_FAILURE(rc))
{
PCRTSTATUSMSG pErr = RTErrGet(rc);
if (pErr)
return pfnOutput(pvArgOutput, pErr->pszDefine, strlen(pErr->pszDefine));
return pfnOutput(pvArgOutput, szTmp, RTStrPrintf(szTmp, sizeof(szTmp), "rc=%d", rc));
}
/*
* Format the value.
*/
ssize_t cchOutput = dbgfR3RegFormatValueInt(szTmp, sizeof(szTmp), &Value, enmType, uBase, cchWidth, cchPrecision, fFlags);
if (RT_UNLIKELY(cchOutput <= 0))
{
AssertFailed();
return pfnOutput(pvArgOutput, "internal-error", sizeof("internal-error") - 1);
}
return pfnOutput(pvArgOutput, szTmp, cchOutput);
}
/**
* @callback_method_impl{FNSTRFORMAT}
*/
static DECLCALLBACK(size_t)
dbgfR3RegPrintfCbFormat(void *pvArg, PFNRTSTROUTPUT pfnOutput, void *pvArgOutput,
const char **ppszFormat, va_list *pArgs, int cchWidth,
int cchPrecision, unsigned fFlags, char chArgSize)
{
NOREF(pArgs); NOREF(chArgSize);
/*
* Parse the format type and hand the job to the appropriate worker.
*/
PDBGFR3REGPRINTFARGS pThis = (PDBGFR3REGPRINTFARGS)pvArg;
const char *pszFormat = *ppszFormat;
if ( pszFormat[0] != 'V'
|| pszFormat[1] != 'R')
{
AssertMsgFailed(("'%s'\n", pszFormat));
return 0;
}
unsigned offCurly = 2;
if (pszFormat[offCurly] != '{')
{
AssertMsgReturn(pszFormat[offCurly], ("'%s'\n", pszFormat), 0);
offCurly++;
AssertMsgReturn(pszFormat[offCurly] == '{', ("'%s'\n", pszFormat), 0);
}
const char *pachReg = &pszFormat[offCurly + 1];
/*
* The end and length of the register.
*/
const char *pszEnd = strchr(pachReg, '}');
AssertMsgReturn(pszEnd, ("Missing closing curly bracket: '%s'\n", pszFormat), 0);
size_t const cchReg = pszEnd - pachReg;
/*
* Look up the register - same as dbgfR3RegResolve, except for locking and
* input string termination.
*/
PRTSTRSPACE pRegSpace = &pThis->pUVM->dbgf.s.RegSpace;
/* Try looking up the name without any case folding or cpu prefixing. */
PCDBGFREGLOOKUP pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGetN(pRegSpace, pachReg, cchReg);
if (!pLookupRec)
{
/* Lower case it and try again. */
char szName[DBGF_REG_MAX_NAME * 4 + 16];
ssize_t cchFolded = dbgfR3RegCopyToLower(pachReg, cchReg, szName, sizeof(szName) - DBGF_REG_MAX_NAME);
if (cchFolded > 0)
pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
if ( !pLookupRec
&& cchFolded >= 0
&& pThis->idCpu != VMCPUID_ANY)
{
/* Prefix it with the specified CPU set. */
size_t cchCpuSet = RTStrPrintf(szName, sizeof(szName), pThis->fGuestRegs ? "cpu%u." : "hypercpu%u.", pThis->idCpu);
dbgfR3RegCopyToLower(pachReg, cchReg, &szName[cchCpuSet], sizeof(szName) - cchCpuSet);
pLookupRec = (PCDBGFREGLOOKUP)RTStrSpaceGet(pRegSpace, szName);
}
}
AssertMsgReturn(pLookupRec, ("'%s'\n", pszFormat), 0);
AssertMsgReturn( pLookupRec->pSet->enmType != DBGFREGSETTYPE_CPU
|| pLookupRec->pSet->uUserArg.pVCpu->idCpu == pThis->idCpu,
("'%s' idCpu=%u, pSet/cpu=%u\n", pszFormat, pThis->idCpu, pLookupRec->pSet->uUserArg.pVCpu->idCpu),
0);
/*
* Commit the parsed format string. Up to this point it is nice to know
* what register lookup failed and such, so we've delayed comitting.
*/
*ppszFormat = pszEnd + 1;
/*
* Call the responsible worker.
*/
switch (pszFormat[offCurly - 1])
{
case 'R': /* %VR{} */
case 'X': /* %VRX{} */
return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
16, cchWidth, cchPrecision, fFlags);
case 'U':
return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
10, cchWidth, cchPrecision, fFlags);
case 'O':
return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
8, cchWidth, cchPrecision, fFlags);
case 'B':
return dbgfR3RegPrintfCbFormatNormal(pThis, pfnOutput, pvArgOutput, pLookupRec,
2, cchWidth, cchPrecision, fFlags);
case 'F':
return dbgfR3RegPrintfCbFormatField(pThis, pfnOutput, pvArgOutput, pLookupRec, cchWidth, cchPrecision, fFlags);
default:
AssertFailed();
return 0;
}
}
/**
* @callback_method_impl{FNRTSTROUTPUT}
*/
static DECLCALLBACK(size_t)
dbgfR3RegPrintfCbOutput(void *pvArg, const char *pachChars, size_t cbChars)
{
PDBGFR3REGPRINTFARGS pArgs = (PDBGFR3REGPRINTFARGS)pvArg;
size_t cbToCopy = cbChars;
if (cbToCopy >= pArgs->cchLeftBuf)
{
if (RT_SUCCESS(pArgs->rc))
pArgs->rc = VERR_BUFFER_OVERFLOW;
cbToCopy = pArgs->cchLeftBuf;
}
if (cbToCopy > 0)
{
memcpy(&pArgs->pszBuf[pArgs->offBuf], pachChars, cbToCopy);
pArgs->offBuf += cbToCopy;
pArgs->cchLeftBuf -= cbToCopy;
pArgs->pszBuf[pArgs->offBuf] = '\0';
}
return cbToCopy;
}
/**
* On CPU worker for the register formatting, used by DBGFR3RegPrintfV.
*
* @returns VBox status code.
*
* @param pArgs The argument package and state.
*/
static DECLCALLBACK(int) dbgfR3RegPrintfWorkerOnCpu(PDBGFR3REGPRINTFARGS pArgs)
{
DBGF_REG_DB_LOCK_READ(pArgs->pUVM);
RTStrFormatV(dbgfR3RegPrintfCbOutput, pArgs, dbgfR3RegPrintfCbFormat, pArgs, pArgs->pszFormat, pArgs->va);
DBGF_REG_DB_UNLOCK_READ(pArgs->pUVM);
return pArgs->rc;
}
/**
* Format a registers.
*
* This is restricted to registers from one CPU, that specified by @a idCpu.
*
* @returns VBox status code.
* @param pUVM The user mode 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) DBGFR3RegPrintfV(PUVM pUVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va)
{
AssertPtrReturn(pszBuf, VERR_INVALID_POINTER);
AssertReturn(cbBuf > 0, VERR_BUFFER_OVERFLOW);
*pszBuf = '\0';
UVM_ASSERT_VALID_EXT_RETURN(pUVM, VERR_INVALID_VM_HANDLE);
AssertReturn((idCpu & ~DBGFREG_HYPER_VMCPUID) < pUVM->cCpus || idCpu == VMCPUID_ANY, VERR_INVALID_CPU_ID);
AssertPtrReturn(pszFormat, VERR_INVALID_POINTER);
/*
* Set up an argument package and execute the formatting on the
* specified CPU.
*/
DBGFR3REGPRINTFARGS Args;
Args.pUVM = pUVM;
Args.idCpu = idCpu != VMCPUID_ANY ? idCpu & ~DBGFREG_HYPER_VMCPUID : idCpu;
Args.fGuestRegs = idCpu != VMCPUID_ANY && !(idCpu & DBGFREG_HYPER_VMCPUID);
Args.pszBuf = pszBuf;
Args.pszFormat = pszFormat;
va_copy(Args.va, va);
Args.offBuf = 0;
Args.cchLeftBuf = cbBuf - 1;
Args.rc = VINF_SUCCESS;
int rc = VMR3ReqPriorityCallWaitU(pUVM, Args.idCpu, (PFNRT)dbgfR3RegPrintfWorkerOnCpu, 1, &Args);
va_end(Args.va);
return rc;
}
/**
* Format a registers.
*
* This is restricted to registers from one CPU, that specified by @a idCpu.
*
* @returns VBox status code.
* @param pUVM The user mode 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) DBGFR3RegPrintf(PUVM pUVM, VMCPUID idCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...)
{
va_list va;
va_start(va, pszFormat);
int rc = DBGFR3RegPrintfV(pUVM, idCpu, pszBuf, cbBuf, pszFormat, va);
va_end(va);
return rc;
}