SUPDrv-dtrace.cpp revision f714516da18876b1836a804fc0cac5e8ff589e83
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VBoxDrv - The VirtualBox Support Driver - DTrace Provider.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Copyright (C) 2012 Oracle Corporation
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * available from http://www.virtualbox.org. This file is free software;
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * you can redistribute it and/or modify it under the terms of the GNU
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * General Public License (GPL) as published by the Free Software
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * The contents of this file may alternatively be used under the terms
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * of the Common Development and Distribution License Version 1.0
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * VirtualBox OSE distribution, in which case the provisions of the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * CDDL are applicable instead of those of the GPL.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * You may elect to license modified versions of this file under the
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * terms and conditions of either the GPL or the CDDL or both.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*******************************************************************************
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync* Header Files *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync*******************************************************************************/
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* Avoid type and define conflicts. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* DTrace experiments with the Unbreakable Enterprise Kernel (UEK2)
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync (Oracle Linux).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 1. The dtrace.h here is from the dtrace module source, not
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync /usr/include/sys/dtrace.h nor /usr/include/dtrace.h.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync 2. To generate the missing entries for the dtrace module in Module.symvers
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync | grep _crc_ \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync Update: Althernative workaround (active), resolve symbols dynamically.
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync 3. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync and VBoxTpG and build time. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/* DTrace experiments with the Unbreakable Enterprise Kernel (UEKR3)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync (Oracle Linux).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 1. To generate the missing entries for the dtrace module in Module.symvers
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync | grep _crc_ \
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync Update: Althernative workaround (active), resolve symbols dynamically.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync 2. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync and VBoxTpG and build time. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <dtrace/enabling.h> /* Missing from provider.h. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync# include <dtrace/arg.h> /* Missing from provider.h. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** Status code fixer (UEK uses linux convension unlike the others). */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * The UEK DTrace port is trying to be smart and seems to have turned all
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * errno return codes negative. While this conforms to the linux kernel way of
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * doing things, it breaks with the way the interfaces work on Solaris and
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * Mac OS X.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/*******************************************************************************
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync* Structures and Typedefs *
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync*******************************************************************************/
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/* Seems there is some return code difference here. Keep the return code and
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync case it to whatever the host desires. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsynctypedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync/** Caller indicator. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * Stack data planted before calling dtrace_probe so that we can easily find the
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * stack argument later.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Eyecatcher no. 1 (SUPDRVDT_STACK_DATA_MAGIC2). */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Eyecatcher no. 2 (SUPDRVDT_STACK_DATA_MAGIC2). */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** The format of the caller specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** Caller specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** kVBoxDtCaller_ProbeFireKernel. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** Pointer to the stack arguments of a probe function call. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** kVBoxDtCaller_ProbeFireUser. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** The user context. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync /** The argument displacement caused by 64-bit arguments passed directly to
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * dtrace_probe. */
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync /** Pointer to this structure.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync * This is the final bit of integrity checking. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** Pointer to the on-stack thread specific data. */
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/*******************************************************************************
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync* Defined Constants And Macros *
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync*******************************************************************************/
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** The first magic value. */
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#define SUPDRVDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('S', 'U', 'P', 'D')
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** The second magic value. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync#define SUPDRVDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** The alignment of the stack data.
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * The data doesn't require more than sizeof(uintptr_t) alignment, but the
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync * greater alignment the quicker lookup. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** Plants the stack data. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync uint8_t abBlob[sizeof(VBDTSTACKDATA) + SUPDRVDT_STACK_DATA_ALIGN - 1]; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync PVBDTSTACKDATA pStackData = (PVBDTSTACKDATA)( (uintptr_t)&abBlob[SUPDRVDT_STACK_DATA_ALIGN - 1] \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic1 = SUPDRVDT_STACK_DATA_MAGIC1; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync pStackData->u32Magic2 = SUPDRVDT_STACK_DATA_MAGIC2; \
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync/** Passifies the stack data and frees up resource held within it. */
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync } while (0)
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync/** Simple SUPR0Printf-style logging. */
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync#if 0 /*def DEBUG_bird*/
c10a6f0c7041e4d1ee50ad38425aab9d43c55522vboxsync# define LOG_DTRACE(a) do { } while (0)
510567648d46488f4166e5f69ffffe3eeeeec4d9vboxsync/*******************************************************************************
cd5df721f068659172f3bf95de8fedeb465f057dvboxsync* Global Variables *
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync*******************************************************************************/
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync/** @name DTrace kernel interface used on Darwin and Linux.
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic void (* g_pfnDTraceProbeFire)(dtrace_id_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic dtrace_id_t (* g_pfnDTraceProbeCreate)(dtrace_provider_id_t, const char *, const char *, const char *, int, void *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic dtrace_id_t (* g_pfnDTraceProbeLookup)(dtrace_provider_id_t, const char *, const char *, const char *);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic int (* g_pfnDTraceProviderRegister)(const char *, const dtrace_pattr_t *, uint32_t, /*cred_t*/ void *,
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync const dtrace_pops_t *, void *, dtrace_provider_id_t *);
8bc8d66f188d5357155b8340e2d489573be2b607vboxsyncstatic void (* g_pfnDTraceProviderInvalidate)(dtrace_provider_id_t);
2f3883b126a405f92b19e829472f614c7352b4f9vboxsyncstatic int (* g_pfnDTraceProviderUnregister)(dtrace_provider_id_t);
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_invalidate g_pfnDTraceProviderInvalidate
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync#define dtrace_unregister g_pfnDTraceProviderUnregister
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * Gets the stack data.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @returns Pointer to the stack data. Never NULL.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Locate the caller of probe_dtrace.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync int volatile iDummy = 1; /* use this to get the stack address. */
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync PVBDTSTACKDATA pData = (PVBDTSTACKDATA)( ((uintptr_t)&iDummy + SUPDRVDT_STACK_DATA_ALIGN - 1)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync if ( pData->u32Magic1 == SUPDRVDT_STACK_DATA_MAGIC1
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync pData = (PVBDTSTACKDATA)((uintptr_t)pData + SUPDRVDT_STACK_DATA_ALIGN);
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Helpers for handling VTG structures.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * Converts an attribute from VTG description speak to DTrace.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * @param pDtAttr The DTrace attribute (dst).
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * @param pVtgAttr The VTG attribute descriptor (src).
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsyncstatic void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * Gets a string from the string table.
b8bb9c9f6b8ebfd0a7d6df0c0289f9fe80241750vboxsync * @returns Pointer to the string.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param pVtgHdr The VTG object header.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * @param offStrTab The string table offset.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsyncstatic const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync return (const char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * DTrace Provider Interface.
5050fc8de0b121eab1b738d7c1007cde4903284dvboxsync * DTrace Provider Interface.
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync * DTrace Provider Interface.
88cc9bf61296bc5526344415167bb2625ae1dd99vboxsync * @callback_method_impl{dtrace_pops_t,dtps_provide}
8bc8d66f188d5357155b8340e2d489573be2b607vboxsyncstatic void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
8bc8d66f188d5357155b8340e2d489573be2b607vboxsync LOG_DTRACE(("%s: %p / %p pDtProbeDesc=%p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc));
2f3883b126a405f92b19e829472f614c7352b4f9vboxsync return; /* We don't generate probes, so never mind these requests. */
if (!pszFnNmBuf)
uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc);
if (*pidProbe != 0)
if (psz)
psz--;
pszFunc--;
iOrd++;
LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
LOG_DTRACE(("%s: %p / %p - %#x / %p iArg=%d cFrames=%u\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
return UINT64_MAX;
offArg++;
offArg++;
return u64Ret;
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
*pidProbe = 0;
static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
iSrcArg++;
iDstArg++;
dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
iSrcArg++;
iDstArg++;
dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
AssertFailed();
static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
*puSessionData = 0;
return VERR_NOT_SUPPORTED;
static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
return VERR_NOT_SUPPORTED;
static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
&DtAttrs,
if (!rc)
return rc;
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
if (!rc)
return rc;
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
if (!rc)
return rc;
# ifndef RT_OS_LINUX
return NULL;
const char *pszName;
} s_aDTraceFunctions[] =
# ifndef RT_OS_LINUX
SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (rc=%Rrc, i=%u).\n", s_aDTraceFunctions[i].pszName, rc, i);
if (!ulAddr)
SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (i=%u).\n", s_aDTraceFunctions[i].pszName, i);
# ifndef RT_OS_LINUX
return NULL;
return &g_VBoxDTraceReg;
#ifndef VBOX_WITH_NATIVE_DTRACE