SUPDrv-dtrace.cpp revision 6998b7cea7c904f33047cd17b05bea760a5839a9
/* $Id$ */
/** @file
* VBoxDrv - The VirtualBox Support Driver - DTrace Provider.
*/
/*
* Copyright (C) 2012 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* General Public License (GPL) as published by the Free Software
* Foundation, in version 2 as it comes in the "COPYING" file of the
* VirtualBox OSE distribution. VirtualBox OSE is distributed in the
* hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
*
* The contents of this file may alternatively be used under the terms
* of the Common Development and Distribution License Version 1.0
* (CDDL) only, as it comes in the "COPYING.CDDL" file of the
* VirtualBox OSE distribution, in which case the provisions of the
* CDDL are applicable instead of those of the GPL.
*
* You may elect to license modified versions of this file under the
* terms and conditions of either the GPL or the CDDL or both.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_SUP_DRV
#include "SUPDrvInternal.h"
#include <iprt/semaphore.h>
#ifdef RT_OS_DARWIN /** @todo figure this! */
#else
#endif
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
* Data for a provider.
*/
typedef struct SUPDRVDTPROVIDER
{
/** The entry in the provider list for this image. */
/** The provider descriptor. */
/** The VTG header. */
/** Pointer to the image this provider resides in. NULL if it's a
* driver. */
/** The session this provider is associated with if registered via
* SUPR0VtgRegisterDrv. NULL if pImage is set. */
/** The module name. */
const char *pszModName;
/** Dtrace provider attributes. */
/** The ID of this provider. */
/** Pointer to the data for a provider. */
typedef SUPDRVDTPROVIDER *PSUPDRVDTPROVIDER;
/* Seems there is some return code difference here. Keep the return code and
case it to whatever the host desires. */
#ifdef RT_OS_DARWIN
typedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
#else
typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
#endif
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
/*static uint64_t supdrvDTracePOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
int iArg, int cFrames);*/
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** The default provider attributes. */
static dtrace_pattr_t g_DefProvAttrs =
{ /* .dtat_name, .dtat_data, .dtat_class */
};
/**
* DTrace provider method table.
*/
static const dtrace_pops_t g_SupDrvDTraceProvOps =
{
/* .dtps_provide = */ supdrvDTracePOps_Provide,
/* .dtps_provide_module = */ NULL,
/* .dtps_disable = */ supdrvDTracePOps_Disable,
/* .dtps_suspend = */ NULL,
/* .dtps_resume = */ NULL,
/* .dtps_getargdesc = */ supdrvDTracePOps_GetArgDesc,
/* .dtps_usermode = */ NULL,
/* .dtps_destroy = */ supdrvDTracePOps_Destroy
};
#define VERR_SUPDRV_VTG_MAGIC (-3704)
#define VERR_SUPDRV_VTG_BITS (-3705)
//#define VERR_SUPDRV_VTG_RESERVED (-3705)
#define VERR_SUPDRV_VTG_BAD_HDR (-3706)
#define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3706)
#define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3707)
#define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3708)
#define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3709)
#define VERR_SUPDRV_VTG_STRTAB_OFF (-3709)
#define VERR_SUPDRV_VTG_BAD_STRING (-1111)
#define VERR_SUPDRV_VTG_STRING_TOO_LONG (-1111)
#define VERR_SUPDRV_VTG_BAD_ATTR (-1111)
#define VERR_SUPDRV_VTG_BAD_PROVIDER (-1111)
#define VERR_SUPDRV_VTG_BAD_PROBE (-1111)
#define VERR_SUPDRV_VTG_BAD_ARGLIST (-3709)
#define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-1111)
#define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3709)
#define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-1111)
#define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-1111)
static int supdrvVtgValidateString(const char *psz)
{
{
if (!ch)
return VINF_SUCCESS;
if ( !RTLocCIsAlNum(ch)
&& ch != ' '
&& ch != '('
&& ch != ')'
&& ch != ','
&& ch != '*'
&& ch != '&'
)
return VERR_SUPDRV_VTG_BAD_STRING;
}
return VERR_SUPDRV_VTG_STRING_TOO_LONG;
}
/**
* Validates the VTG data.
*
* @returns VBox status code.
* @param pVtgHdr The VTG object header of the data to validate.
* @param cbVtgObj The size of the VTG object.
* @param pbImage The image base. For validating the probe
* locations.
* @param cbImage The image size to go with @a pbImage.
*/
static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
{
uintptr_t i;
int rc;
{
cbImage = 0;
}
do { \
return rcBase ## _NOT_MULTIPLE; \
} while (0)
#define MY_WITHIN_IMAGE(p, rc) \
do { \
if (pbImage) \
{ \
return (rc); \
} \
else if (!RT_VALID_PTR(p)) \
return (rc); \
} while (0)
#define MY_VALIDATE_STR(offStrTab) \
do { \
return VERR_SUPDRV_VTG_STRTAB_OFF; \
if (rc != VINF_SUCCESS) \
return rc; \
} while (0)
#define MY_VALIDATE_ATTR(Attr) \
do { \
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; \
} while (0)
/*
* The header.
*/
return VERR_SUPDRV_VTG_MAGIC;
return VERR_SUPDRV_VTG_BITS;
if (pVtgHdr->u32Reserved0)
return VERR_SUPDRV_VTG_BAD_HDR;
MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
return VERR_SUPDRV_VTG_BAD_HDR_PTR;
MY_VALIDATE_PTR(pVtgHdr->paProbLocs, cbTmp, 1, _128K, sizeof(VTGPROBELOC), VERR_SUPDRV_VTG_BAD_HDR);
if (cbTmp < sizeof(VTGPROBELOC))
return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
return VERR_SUPDRV_VTG_BAD_HDR;
/*
* Validate the providers.
*/
while (i-- > 0)
{
return VERR_SUPDRV_VTG_BAD_PROVIDER;
if (pVtgHdr->paProviders[i].iFirstProbe + pVtgHdr->paProviders[i].cProbes > pVtgHdr->cbProbeEnabled)
return VERR_SUPDRV_VTG_BAD_PROVIDER;
return VERR_SUPDRV_VTG_BAD_PROVIDER;
}
/*
* Validate probes.
*/
while (i-- > 0)
{
unsigned iArg;
return VERR_SUPDRV_VTG_BAD_PROBE;
return VERR_SUPDRV_VTG_BAD_PROBE;
return VERR_SUPDRV_VTG_BAD_PROBE;
return VERR_SUPDRV_VTG_BAD_PROBE;
return VERR_SUPDRV_VTG_BAD_PROBE;
return VERR_SUPDRV_VTG_BAD_PROBE;
/* The referenced argument list. */
return VERR_SUPDRV_VTG_BAD_ARGLIST;
if ( pArgList->abReserved[0]
return VERR_SUPDRV_VTG_BAD_ARGLIST;
while (iArg-- > 0)
{
}
}
/*
* Check that pafProbeEnabled is all zero.
*/
i = pVtgHdr->cbProbeEnabled;
while (i-- > 0)
if (pVtgHdr->pafProbeEnabled[0])
/*
* Probe locations.
*/
while (i-- > 0)
{
return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
}
return VINF_SUCCESS;
}
/**
* Converts an attribute from VTG description speak to DTrace.
*
* @param pDtAttr The DTrace attribute (dst).
* @param pVtgAttr The VTG attribute descriptor (src).
*/
{
}
/**
* Gets a string from the string table.
*
* @returns Pointer to the string.
* @param pVtgHdr The VTG object header.
* @param offStrTab The string table offset.
*/
{
}
/**
* Registers the VTG tracepoint providers of a driver.
*
* @returns VBox status code.
* @param pszName The driver name.
* @param pVtgHdr The VTG object header.
* @param pVtgObj The size of the VTG object.
* @param pImage The image if applicable.
* @param pSession The session if applicable.
* @param pszModName The module name.
*/
static int supdrvVtgRegister(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage, PSUPDRVSESSION pSession,
const char *pszModName)
{
int rc;
unsigned i;
/*
* Validate input.
*/
if (pImage)
else
if (RT_FAILURE(rc))
return rc;
if (RT_SUCCESS(rc))
{
{
{
}
{
}
}
}
/*
* Register the providers.
*/
while (i-- > 0)
{
if (pProv)
{
NULL /* cred */,
if (!rc)
{
if (RT_SUCCESS(rc))
{
}
else
}
else
}
else
rc = VERR_NO_MEMORY;
if (RT_FAILURE(rc))
{
{
{
}
}
return rc;
}
}
return VINF_SUCCESS;
}
/**
* Registers the VTG tracepoint providers of a driver.
*
* @returns VBox status code.
* @param pSession The support driver session handle.
* @param pVtgHdr The VTG header.
* @param pszName The driver name.
*/
SUPR0DECL(int) SUPR0VtgRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
{
}
/**
* Deregister the VTG tracepoint providers of a driver.
*
* @param pSession The support driver session handle.
* @param pVtgHdr The VTG header.
*/
{
{
{
}
}
}
/**
* Early module initialization hook.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
{
/*
* Register a provider for this module.
*/
if (RT_SUCCESS(rc))
{
rc = supdrvVtgRegister(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
if (RT_SUCCESS(rc))
return rc;
}
return rc;
}
/**
* Late module termination hook.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
{
/*
* Unregister all probes (there should only be one).
*/
{
}
return VINF_SUCCESS;
}
/**
* Module loading hook, called before calling into the module.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
{
/*
* Check for DTrace probes in the module, register a new provider for them
* if found.
*/
return VINF_SUCCESS;
}
/**
* Module unloading hook, called after execution in the module
* have ceased.
*
* @returns VBox status code.
* @param pDevExt The device extension structure.
*/
{
/*
* Undo what we did in supdrvDTraceModuleLoading.
*/
return VINF_SUCCESS;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_provide}
*/
{
char *pszFnNmBuf;
if (pDtProbeDesc)
return; /* We don't generate probes, so never mind these requests. */
/* Need a buffer for extracting the function names and mangling them in
case of collision. */
if (!pszFnNmBuf)
return;
/*
* Itereate the probe location list and register all probes related to
* this provider.
*/
{
{
/* The function name normally needs to be stripped since we're
using C++ compilers for most of the code. ASSUMES nobody are
typedef'ing properly them. */
if (psz)
{
/* skip blanks preceeding the parameter parenthesis. */
psz--;
/* Find the start of the function name. */
{
break;
pszFunc--;
}
}
else
/* Look up the probe, if we have one in the same function, mangle
the function name a little to avoid having to deal with having
multiple location entries with the same probe ID. (lazy bird) */
if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
{
if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
{
unsigned iOrd = 2;
while (iOrd < 128)
{
if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
break;
iOrd++;
}
if (iOrd >= 128)
{
LogRel(("VBoxDrv: More than 128 duplicate probe location instances in file %s at line %u, function %s [%s], probe %s\n",
continue;
}
}
}
/* Create the probe. */
pProbeLoc->idProbe = dtrace_probe_create(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName,
0 /*aframes*/, pProbeLoc);
}
pProbeLoc++;
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_enable}
*/
{
{
}
return 0;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_disable}
*/
{
{
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
*/
{
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
{
const char *pszType = supdrvVtgGetString(pProv->pHdr, pArgList->aArgs[pArgDesc->dtargd_ndx].offType);
else
}
else
}
#if 0
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargval}
*/
{
return 0xbeef;
}
#endif
/**
* @callback_method_impl{dtrace_pops_t,dtps_destroy}
*/
{
}