SUPDrvTracer.cpp revision a167f8813b459e30d4c34e76f4305bcc2f24adde
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * VBoxDrv - The VirtualBox Support Driver - Tracer Interface.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * Copyright (C) 2012 Oracle Corporation
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * available from http://www.virtualbox.org. This file is free software;
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * you can redistribute it and/or modify it under the terms of the GNU
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * General Public License (GPL) as published by the Free Software
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
a16eb14ad7a4b5ef91ddc22d3e8e92d930f736fcvboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * The contents of this file may alternatively be used under the terms
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * of the Common Development and Distribution License Version 1.0
1c94c0a63ba68be1a7b2c640e70d7a06464e4fcavboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * VirtualBox OSE distribution, in which case the provisions of the
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * CDDL are applicable instead of those of the GPL.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * You may elect to license modified versions of this file under the
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * terms and conditions of either the GPL or the CDDL or both.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/*******************************************************************************
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync* Header Files *
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync*******************************************************************************/
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/*******************************************************************************
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync* Structures and Typedefs *
6420f75ffc86ab6494eb5e95418f0c95e71e8068vboxsync*******************************************************************************/
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync/** Pointer to a user tracer module registration record. */
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync * Data for a tracepoint provider.
3609dfc9f2733f4dc836c6a6bb3745398f280fcevboxsync /** The entry in the provider list for this image. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The entry in the per session provider list for this image. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The core structure. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Pointer to the image this provider resides in. NULL if it's a
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * driver. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The session this provider is associated with if registered via
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * SUPR0VtgRegisterDrv. NULL if pImage is set. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The user tracepoint module associated with this provider. NULL if
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * pImage is set. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Used to indicate that we've called pfnProviderDeregistered already and it
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * failed because the provider was busy. Next time we must try
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * pfnProviderDeregisterZombie.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * @remarks This does not necessiarly mean the provider is in the zombie
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * list. See supdrvTracerCommonDeregisterImpl. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Set if the provider has been successfully registered with the
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * tracer. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The provider name (for logging purposes). */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync/** Pointer to the data for a tracepoint provider. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * User tracer module VTG data copy.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Magic (SUDPRVVTGCOPY_MAGIC). */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Refernece counter (we expect to share a lot of these). */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The size of the */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Image type flags. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Hash list entry (SUPDRVDEVEXT::aTrackerUmodHash). */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The VTG object header.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * The rest of the data follows immediately afterwards. First the object,
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * then the probe locations and finally the probe location string table. All
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * pointers are fixed up to point within this data. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync/** Pointer to a VTG object copy. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync/** Magic value for SUPDRVVTGCOPY. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync * User tracer module registration record.
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Magic (SUPDRVTRACERUMOD_MAGIC). */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** List entry. This is anchored in SUPDRVSESSION::UmodList. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The address of the ring-3 VTG header. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Pointer to the ring-0 copy of the VTG data. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The memory object that locks down the user memory. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The memory object that maps the locked memory into kernel space. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Pointer to the probe enabled-count array within the mapping. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** Pointer to the probe location array within the mapping. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The address of the ring-3 probe locations. */
611910c4ba57eb6db5c0d508ca7b923efd654aecvboxsync /** The lookup table index. */
#ifdef DEBUG_bird
if (!ch)
return VINF_SUCCESS;
return VERR_SUPDRV_VTG_BAD_STRING;
return VERR_SUPDRV_VTG_STRING_TOO_LONG;
MY_CHECK_MSG_RET(a_Expr, ("%s: Validation failed on line " RT_XSTR(__LINE__) ": " #a_Expr "\n", __FUNCTION__), a_rc)
if (pbImage) \
return (rc); \
else if (!RT_VALID_PTR(p)) \
return (rc); \
static int supdrvVtgValidateHdr(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
struct VTGAREAS
} const *paAreas;
unsigned cAreas;
SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_FEW - cb=%#zx cMin=%#zx cbUnit=%#zx line=%u %s\n", \
SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_TOO_MUCH - cb=%#zx cMax=%#zx cbUnit=%#zx line=%u %s\n", \
SUPR0Printf("supdrvVtgValidateHdr: " #rcBase "_OFF - off=%#x cb=%#x pVtgHdr=%p cbVtgHdr=%#zx line=%u %s\n", \
cbImage = 0;
return VERR_SUPDRV_TRACER_TOO_LARGE;
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH - u64Tmp=%#llx ProbeLocs=%#llx ProbeLocsEnd=%#llx\n",
return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
#ifdef RT_OS_DARWIN
&& !fUmod)
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_PTR - u64Tmp=%#llx uProbeLocs=%#llx uVtgHdrAddr=%RTptr\n",
return VERR_SUPDRV_VTG_BAD_HDR_PTR;
return VERR_SUPDRV_VTG_MAGIC;
&& ( !fUmod
return VERR_SUPDRV_VTG_BITS;
MY_VALIDATE_OFF(pVtgHdr->offStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), sizeof(uint8_t), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_OFF(pVtgHdr->offArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_OFF(pVtgHdr->offProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_OFF(pVtgHdr->offProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_OFF(pVtgHdr->offProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(uint32_t), sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
if (!fUmod)
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - uProbeLocs=%#llx uProbeLocsEnd=%#llx offProbeLocs=%#llx cbProbeLocs=%#x uVtgHdrAddr=%RTptr\n",
pVtgHdr->uProbeLocs.u64, pVtgHdr->uProbeLocsEnd.u64, pVtgHdr->offProbeLocs, pVtgHdr->cbProbeLocs, uVtgHdrAddr);
return VERR_SUPDRV_VTG_BAD_HDR_MISC;
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - cbProbeEnabled=%#zx cbProbes=%#zx\n",
return VERR_SUPDRV_VTG_BAD_HDR_MISC;
for (i = 0; i < cAreas; i++)
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - overlapping areas %d and %d\n", i, i-1);
return VERR_SUPDRV_VTG_BAD_HDR_MISC;
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - probe locations overlaps the header\n");
return VERR_SUPDRV_VTG_BAD_HDR_MISC;
SUPR0Printf("supdrvVtgValidateHdr: VERR_SUPDRV_VTG_BAD_HDR_MISC - bad header size %#x, expected %#x\n",
return VERR_SUPDRV_VTG_BAD_HDR_MISC;
return VINF_SUCCESS;
static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, RTUINTPTR uVtgHdrAddr, const uint8_t *pbImage, size_t cbImage, bool fUmod)
uintptr_t i;
int rc;
cbImage = 0;
return VERR_SUPDRV_VTG_STRTAB_OFF; \
return rc; \
if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
return VERR_SUPDRV_VTG_BAD_ATTR; \
if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
return VERR_SUPDRV_VTG_BAD_ATTR; \
return VERR_SUPDRV_VTG_BAD_ATTR; \
return rc;
MY_CHECK_RET(pProvider->iFirstProbe < pVtgHdr->cbProbeEnabled / sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_PROVIDER);
MY_CHECK_RET((uint32_t)pProvider->iFirstProbe + pProvider->cProbes <= pVtgHdr->cbProbeEnabled / sizeof(uint32_t),
PCVTGDESCPROVIDER pProvider = (PCVTGDESCPROVIDER)((uintptr_t)pVtgHdr + pVtgHdr->offProviders) + pProbe->idxProvider;
PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList );
unsigned iArg;
bool fHaveLargeArgs;
return VERR_SUPDRV_VTG_BAD_PROBE;
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_ARGLIST - iProbe=%u cArgs=%u\n", i, pArgList->cArgs);
return VERR_SUPDRV_VTG_BAD_ARGLIST;
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_ARGLIST - iProbe=%u fHaveLargeArgs=%d\n", i, pArgList->fHaveLargeArgs);
return VERR_SUPDRV_VTG_BAD_ARGLIST;
return VERR_SUPDRV_VTG_BAD_ARGLIST;
fHaveLargeArgs = false;
while (iArg-- > 0)
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#0)\n", fType, iArg, i);
return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#1)\n", fType, iArg, i);
return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u (#2)\n", fType, iArg, i);
return VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
fHaveLargeArgs = true;
SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - iProbe=%u fHaveLargeArgs=%d expected %d\n",
return VERR_SUPDRV_VTG_BAD_PROBE;
&& !fUmod )
MY_CHECK_RET(offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) == offTmp, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
return VINF_SUCCESS;
LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
int rc;
RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
uint32_t i;
bool fEmpty;
RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
int rc;
if (!rc)
fEmpty = false;
if (fEmpty)
static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, PSUPDRVLDRIMAGE pImage,
int rc;
uintptr_t i;
if (pImage)
return rc;
return rc;
return rc;
pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1 + cchModName + 1]));
if (pProv)
if (!pUmod)
if (!pUmod)
if (pSession)
if (pProv)
if (pImage)
RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
return rc;
return VINF_SUCCESS;
SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
int rc;
LOG_TRACER(("SUPR0TracerRegisterDrv: pSession=%p pVtgHdr=%p pszName=%s\n", pSession, pVtgHdr, pszName));
rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, NULL /*pImage*/, pSession, NULL /*pUmod*/, pszName);
return rc;
int rc;
AssertReturn((uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage < pImage->cbImageBits, VERR_INVALID_PARAMETER);
rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, pImage, NULL /*pSession*/, NULL /*pUmod*/, pImage->szName);
return rc;
SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
int rc;
int rc2;
if (pImage)
return rc;
uint32_t i;
int rc;
cZombies++;
RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
int rc;
cZombies++;
cZombies++;
cZombies++;
if (cZombies == 0)
int rc;
if (pImage)
if ( pImage
return rc;
# if defined(RT_ARCH_AMD64)
if (!cRefs)
static PSUPDRVVTGCOPY supdrvVtgFindObjectCopyLocked(PRTLISTANCHOR pHashList, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
return pCur;
return NULL;
static PSUPDRVVTGCOPY supdrvVtgFindObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pHdr, uint32_t cbStrTab, uint32_t fFlags)
PRTLISTANCHOR pHashList = &pDevExt->aTrackerUmodHash[pHdr->Uuid.au8[3] % RT_ELEMENTS(pDevExt->aTrackerUmodHash)];
return pRet;
static int supdrvVtgCreateObjectCopy(PSUPDRVDEVEXT pDevExt, PCVTGOBJHDR pVtgHdr, RTR3PTR R3PtrVtgHdr, RTUINTPTR uVtgHdrAddr,
int rc;
size_t const cProbeLocs = pVtgHdr->cbProbeLocs / (pVtgHdr->cBits == 32 ? sizeof(VTGPROBELOC32) : sizeof(VTGPROBELOC64));
if (!pThis)
return VERR_NO_MEMORY;
uint32_t i;
for (i = 0; i < cProbeLocs; i++)
for (i = 0; i < cProbeLocs; i++)
rc = supdrvVtgValidate(&pThis->Hdr, (uintptr_t)&pThis->Hdr, (uint8_t *)&pThis->Hdr, cb, false /*fUmod*/);
return rc;
return rc;
static void supdrvTracerUmodClearProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
uint32_t i;
static int supdrvTracerUmodSetProbeIds(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUMOD pUmod)
uint32_t i;
return VINF_SUCCESS;
int rc;
return VERR_INVALID_CONTEXT;
return VERR_INVALID_PARAMETER;
return rc;
return rc;
if (!pUmod)
return VERR_NO_MEMORY;
rc = RTR0MemObjLockUser(&pUmod->hMemObjLock, R3PtrLock, cbLock, RTMEM_PROT_READ | RTMEM_PROT_WRITE, NIL_RTR0PROCESS);
rc = RTR0MemObjMapKernel(&pUmod->hMemObjMap, pUmod->hMemObjLock, (void *)-1, 0, RTMEM_PROT_READ | RTMEM_PROT_WRITE);
rc = supdrvVtgCreateObjectCopy(pDevExt, &Hdr, R3PtrVtgHdr, uVtgHdrAddr, R3PtrStrTab, cbStrTab, fFlags, pUmod);
return VINF_SUCCESS;
return rc;
int VBOXCALL supdrvIOCtl_TracerUmodDeregister(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, RTR3PTR R3PtrVtgHdr)
uint32_t i;
int rc;
if ( pUmod
if (pUmod)
return rc;
static void supdrvTracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
== R3PtrProbeLoc))
&& pVtgCopy))
pDevExt->pTracerOps->pfnProbeFireUser(pDevExt->pTracerOps, pSession, pCtx, &pVtgCopy->Hdr, pProbeLocRO);
void VBOXCALL supdrvIOCtl_TracerUmodProbeFire(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx)
int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
int rc;
rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
return rc;
int rc;
return rc;
int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
int rc;
*piRetVal = 0;
rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
return rc;
uint32_t i;
#ifdef VBOX_WITH_NATIVE_DTRACE
#ifdef VBOX_WITH_DTRACE_R0DRV
rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, NULL /*pImage*/, NULL /*pSession*/, NULL /*pUmod*/, "vboxdrv");
return rc;
return VINF_SUCCESS;
return rc;