VBoxDTraceR0.cpp revision 57a7aeb014cdd1900c8bfecb0f9dcc7b96a61cc9
/* $Id$ */
/** @file
* VBoxDTraceR0.
*
* Contributed by: bird
*/
/*
* Copyright (C) 2012-2015 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* Development and Distribution License Version 1.0 (CDDL) only, as it
* comes in the "COPYING.CDDL" file of the VirtualBox OSE distribution.
* VirtualBox OSE is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY of any kind.
*
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#include <iprt/asm-amd64-x86.h>
#include <iprt/semaphore.h>
#include <iprt/spinlock.h>
#include <sys/dtrace_impl.h>
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
//#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2)
//# define HAVE_RTMEMALLOCEX_FEATURES
//#endif
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/** Caller indicator. */
typedef enum VBOXDTCALLER
{
} VBOXDTCALLER;
/**
* Stack data used for thread structure and such.
*
* This is planted in every external entry point and used to emulate solaris
* curthread, CRED, curproc and similar. It is also used to get at the
* uncached probe arguments.
*/
typedef struct VBoxDtStackData
{
/** Eyecatcher no. 1 (VBDT_STACK_DATA_MAGIC2). */
/** Eyecatcher no. 2 (VBDT_STACK_DATA_MAGIC2). */
/** The format of the caller specific data. */
/** Caller specific data. */
union
{
/** kVBoxDtCaller_ProbeFireKernel. */
struct
{
/** The caller. */
/** Pointer to the stack arguments of a probe function call. */
/** kVBoxDtCaller_ProbeFireUser. */
struct
{
/** The user context. */
/** The argument displacement caused by 64-bit arguments passed directly to
* dtrace_probe. */
int offArg;
} u;
/** Credentials allocated by VBoxDtGetCurrentCreds. */
struct VBoxDtCred *pCred;
/** Thread structure currently being held by this thread. */
struct VBoxDtThread *pThread;
/** Pointer to this structure.
* This is the final bit of integrity checking. */
struct VBoxDtStackData *pSelf;
/** Pointer to the on-stack thread specific data. */
typedef VBDTSTACKDATA *PVBDTSTACKDATA;
/** The first magic value. */
/** The second magic value. */
/** The alignment of the stack data.
* The data doesn't require more than sizeof(uintptr_t) alignment, but the
* greater alignment the quicker lookup. */
#define VBDT_STACK_DATA_ALIGN 32
/** Plants the stack data. */
#define VBDT_SETUP_STACK_DATA(a_enmCaller) \
/** Passifies the stack data and frees up resource held within it. */
#define VBDT_CLEAR_STACK_DATA() \
do \
{ \
pStackData->u32Magic1 = 0; \
pStackData->u32Magic2 = 0; \
if (pStackData->pCred) \
if (pStackData->pThread) \
} while (0)
/** Simple SUPR0Printf-style logging. */
#if 0 /*def DEBUG_bird*/
# define LOG_DTRACE(a) SUPR0Printf a
#else
# define LOG_DTRACE(a) do { } while (0)
#endif
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Per CPU information */
/** Dummy mutex. */
struct VBoxDtMutex g_DummyMtx;
/** Pointer to the tracer helpers provided by VBoxDrv. */
static PCSUPDRVTRACERHLP g_pVBoxDTraceHlp;
#if 0
void (*dtrace_cpu_init)(processorid_t);
void (*dtrace_modload)(struct modctl *);
void (*dtrace_modunload)(struct modctl *);
void (*dtrace_helpers_cleanup)(void);
void (*dtrace_cpustart_init)(void);
void (*dtrace_cpustart_fini)(void);
void (*dtrace_cpc_fire)(uint64_t);
void (*dtrace_debugger_init)(void);
void (*dtrace_debugger_fini)(void);
#endif
/**
* Gets the stack data.
*
* @returns Pointer to the stack data. Never NULL.
*/
static PVBDTSTACKDATA vboxDtGetStackData(void)
{
for (;;)
{
return pData;
}
}
{
/** @todo ? */
}
/**
* Dummy callback used by dtrace_sync.
*/
{
}
/**
* Synchronzie across all CPUs (expensive).
*/
void dtrace_sync(void)
{
}
/**
* Fetch a 8-bit "word" from userland.
*
* @return The byte value.
* @param pvUserAddr The userland address.
*/
{
if (RT_FAILURE(rc))
{
u8 = 0;
}
return u8;
}
/**
* Fetch a 16-bit word from userland.
*
* @return The word value.
* @param pvUserAddr The userland address.
*/
{
if (RT_FAILURE(rc))
{
u16 = 0;
}
return u16;
}
/**
* Fetch a 32-bit word from userland.
*
* @return The dword value.
* @param pvUserAddr The userland address.
*/
{
if (RT_FAILURE(rc))
{
u32 = 0;
}
return u32;
}
/**
* Fetch a 64-bit word from userland.
*
* @return The qword value.
* @param pvUserAddr The userland address.
*/
{
if (RT_FAILURE(rc))
{
u64 = 0;
}
return u64;
}
/** copyin implementation */
{
}
/** copyout implementation */
{
}
/**
* Copy data from userland into the kernel.
*
* @param uUserAddr The userland address.
* @param uKrnlAddr The kernel buffer address.
* @param cb The number of bytes to copy.
* @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
*/
void dtrace_copyin( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cb, volatile uint16_t *pfFlags)
{
if (RT_FAILURE(rc))
{
}
}
/**
* Copy data from the kernel into userland.
*
* @param uKrnlAddr The kernel buffer address.
* @param uUserAddr The userland address.
* @param cb The number of bytes to copy.
* @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
*/
void dtrace_copyout( uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cb, volatile uint16_t *pfFlags)
{
if (RT_FAILURE(rc))
{
}
}
/**
* Copy a string from userland into the kernel.
*
* @param uUserAddr The userland address.
* @param uKrnlAddr The kernel buffer address.
* @param cbMax The maximum number of bytes to copy. May stop
* earlier if zero byte is encountered.
* @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
*/
void dtrace_copyinstr( uintptr_t uUserAddr, uintptr_t uKrnlAddr, size_t cbMax, volatile uint16_t *pfFlags)
{
if (!cbMax)
return;
if (RT_FAILURE(rc))
{
/* Byte by byte - lazy bird! */
{
if (RT_FAILURE(rc))
{
return;
}
return;
off++;
}
}
}
/**
* Copy a string from the kernel and into user land.
*
* @param uKrnlAddr The kernel string address.
* @param uUserAddr The userland address.
* @param cbMax The maximum number of bytes to copy. Will stop
* earlier if zero byte is encountered.
* @param pfFlags Pointer to the relevant cpuc_dtrace_flags.
*/
void dtrace_copyoutstr(uintptr_t uKrnlAddr, uintptr_t uUserAddr, size_t cbMax, volatile uint16_t *pfFlags)
{
}
/**
* Get the caller @a cCallFrames call frames up the stack.
*
* @returns The caller's return address or ~(uintptr_t)0.
* @param cCallFrames The number of frames.
*/
{
return ~(uintptr_t)0;
}
/**
* Get argument number @a iArg @a cCallFrames call frames up the stack.
*
* @returns The caller's return address or ~(uintptr_t)0.
* @param iArg The argument to get.
* @param cCallFrames The number of frames.
*/
{
return UINT64_MAX;
}
/**
* Produce a traceback of the kernel stack.
*
* @param paPcStack Where to return the program counters.
* @param cMaxFrames The maximum number of PCs to return.
* @param cSkipFrames The number of artificial callstack frames to
* skip at the top.
* @param pIntr Not sure what this is...
*/
{
int iFrame = 0;
while (iFrame < cMaxFrames)
{
iFrame++;
}
}
/**
* Get the number of call frames on the stack.
*
* @returns The stack depth.
* @param cSkipFrames The number of artificial callstack frames to
* skip at the top.
*/
int dtrace_getstackdepth(int cSkipFrames)
{
return 1;
}
/**
* Produce a traceback of the userland stack.
*
* @param paPcStack Where to return the program counters.
* @param paFpStack Where to return the frame pointers.
* @param cMaxFrames The maximum number of frames to return.
*/
{
int iFrame = 0;
while (iFrame < cMaxFrames)
{
iFrame++;
}
}
/**
* Produce a traceback of the userland stack.
*
* @param paPcStack Where to return the program counters.
* @param cMaxFrames The maximum number of frames to return.
*/
{
int iFrame = 0;
while (iFrame < cMaxFrames)
{
iFrame++;
}
}
/**
* Computes the depth of the userland stack.
*/
int dtrace_getustackdepth(void)
{
return 0;
}
/**
*
* @returns Current level.
*/
int dtrace_getipl(void)
{
#ifdef RT_ARCH_AMD64
/* CR8 is normally the same as IRQL / IPL on AMD64. */
return ASMGetCR8();
#else
/* Just fake it on x86. */
return !ASMIntAreEnabled();
#endif
}
/**
* Get current monotonic timestamp.
*
* @returns Timestamp, nano seconds.
*/
hrtime_t dtrace_gethrtime(void)
{
return RTTimeNanoTS();
}
/**
* Get current walltime.
*
* @returns Timestamp, nano seconds.
*/
hrtime_t dtrace_gethrestime(void)
{
/** @todo try get better resolution here somehow ... */
}
/**
* DTrace panic routine.
*
* @param pszFormat Panic message.
* @param va Arguments to the panic message.
*/
{
for (;;)
{
*pchCrash = '\0';
}
}
/**
* DTrace panic routine.
*
* @param pszFormat Panic message.
* @param ... Arguments to the panic message.
*/
void VBoxDtPanic(const char *pszFormat, ...)
{
}
/**
* DTrace kernel message routine.
*
* @param pszFormat Kernel message.
* @param ... Arguments to the panic message.
*/
{
}
/** uprintf implementation */
void VBoxDtUPrintf(const char *pszFormat, ...)
{
}
/** vuprintf implementation */
{
}
/* CRED implementation. */
cred_t *VBoxDtGetCurrentCreds(void)
{
{
struct VBoxDtCred *pCred;
#ifdef HAVE_RTMEMALLOCEX_FEATURES
#else
#endif
/** @todo get the right creds on unix systems. */
}
}
/* crhold implementation */
{
}
/* crfree implementation */
{
if (!cRefs)
}
/** Spinlock protecting the thread structures. */
/** List of threads by usage age. */
static RTLISTANCHOR g_ThreadAgeList;
/** Hash table for looking up thread structures. */
/** Fake kthread_t structures.
* The size of this array is making horrible ASSUMPTIONS about the number of
* thread in the system that will be subjected to DTracing. */
static int vboxDtInitThreadDb(void)
{
if (RT_FAILURE(rc))
return rc;
{
}
return VINF_SUCCESS;
}
static void vboxDtTermThreadDb(void)
{
}
/* curthread implementation, providing a fake kthread_t. */
struct VBoxDtThread *VBoxDtGetCurrentThread(void)
{
/*
* Once we've retrieved a thread, we hold on to it until the thread exits
* the VBoxDTrace module.
*/
{
}
/*
* Lookup the thread in the hash table.
*/
while (pThread)
{
{
{
/* Re-initialize the reused thread. */
pThread->t_dtrace_vtime = 0;
pThread->t_dtrace_start = 0;
pThread->t_dtrace_stop = 0;
pThread->t_dtrace_scrpc = 0;
pThread->t_dtrace_astpc = 0;
pThread->t_predcache = 0;
}
/* Hold the thread in the on-stack data, making sure it does not
get reused till the thread leaves VBoxDTrace. */
return pThread;
}
}
/*
* Unknown thread. Allocate a new entry, recycling unused or old ones.
*/
{
else
{
{
{
break;
}
}
}
}
/*
* Initialize the data.
*/
pThread->t_dtrace_vtime = 0;
pThread->t_dtrace_start = 0;
pThread->t_dtrace_stop = 0;
pThread->t_dtrace_scrpc = 0;
pThread->t_dtrace_astpc = 0;
pThread->t_predcache = 0;
/*
* Add it to the hash as well as the on-stack data.
*/
return pThread;
}
/**
* Called by the stack data destructor.
*
* @param pThread The thread to release.
*
*/
{
}
/*
*
* Virtual Memory / Resource Allocator.
* Virtual Memory / Resource Allocator.
* Virtual Memory / Resource Allocator.
*
*/
/** The number of bits per chunk.
* @remarks The 32 bytes are for heap headers and such like. */
/**
* Resource allocator chunk.
*/
typedef struct VBoxDtVMemChunk
{
/** The ordinal (unbased) of the first item. */
/** The current number of free items in this chunk. */
/** The allocation bitmap. */
/** Pointer to a resource allocator chunk. */
typedef VBOXDTVMEMCHUNK *PVBOXDTVMEMCHUNK;
/**
* Resource allocator instance.
*/
typedef struct VBoxDtVMem
{
/** Spinlock protecting the data (interrupt safe). */
/** Magic value. */
/** The current number of free items in the chunks. */
/** The current number of chunks that we have allocated. */
/** The configured resource base. */
/** The configured max number of items. */
/** The size of the apChunks array. */
/** Array of chunk pointers.
* (The size is determined at creation.) */
} VBOXDTVMEM;
/** Pointer to a resource allocator instance. */
typedef VBOXDTVMEM *PVBOXDTVMEM;
/** Magic value for the VBOXDTVMEM structure. */
/* vmem_create implementation */
{
/*
* Assert preconditions of this implementation.
*/
/*
* Allocate the instance.
*/
if (cb % VBOXDTVMEMCHUNK_BITS)
cChunks++;
if (!pThis)
return NULL;
if (RT_FAILURE(rc))
{
return NULL;
}
pThis->cCurChunks = 0;
return pThis;
}
/* vmem_destroy implementation */
{
if (!pThis)
return;
/*
* Invalidate the instance.
*/
/*
* Free the chunks, then the instance.
*/
while (iChunk-- > 0)
{
}
}
/* vmem_alloc implementation */
{
/*
* Validate input.
*/
/*
* Allocation loop.
*/
for (;;)
{
{
{
{
NULL);
}
}
}
/* Out of resources? */
break;
/*
* Allocate another chunk.
*/
uint32_t const iFirstBit = cChunks > 0 ? pThis->apChunks[cChunks - 1]->iFirst + VBOXDTVMEMCHUNK_BITS : 0;
if (!pChunk)
return NULL;
if (cFreeBits != VBOXDTVMEMCHUNK_BITS)
{
/* lazy bird. */
while (iBit < VBOXDTVMEMCHUNK_BITS)
{
iBit++;
}
}
/*
* Insert the new chunk. If someone raced us here, we'll drop it to
* avoid wasting resources.
*/
{
}
else
{
}
}
return NULL;
}
/* vmem_free implementation */
{
/*
* Validate input.
*/
/*
* Free it.
*/
{
}
}
/*
*
* Memory Allocators.
* Memory Allocators.
* Memory Allocators.
*
*/
/* kmem_alloc implementation */
{
void *pvMem;
#ifdef HAVE_RTMEMALLOCEX_FEATURES
#else
uint32_t fMemAllocFlags = 0;
#endif
return pvMem;
}
/* kmem_zalloc implementation */
{
void *pvMem;
#ifdef HAVE_RTMEMALLOCEX_FEATURES
uint32_t fMemAllocFlags = (fFlags & KM_NOSLEEP ? RTMEMALLOCEX_FLAGS_ANY_CTX : 0) | RTMEMALLOCEX_FLAGS_ZEROED;
#else
#endif
return pvMem;
}
/* kmem_free implementation */
{
}
/**
* Memory cache mockup structure.
* No slab allocator here!
*/
struct VBoxDtMemCache
{
};
/* Limited kmem_cache_create implementation. */
{
/*
* Check the input.
*/
/*
* Create a parameter container. Don't bother with anything fancy here yet,
* just get something working.
*/
if (!pThis)
return NULL;
return pThis;
}
/* Limited kmem_cache_destroy implementation. */
{
}
/* kmem_cache_alloc implementation. */
{
void *pvMem;
#ifdef HAVE_RTMEMALLOCEX_FEATURES
uint32_t fMemAllocFlags = (fFlags & KM_NOSLEEP ? RTMEMALLOCEX_FLAGS_ANY_CTX : 0) | RTMEMALLOCEX_FLAGS_ZEROED;
#else
#endif
return pvMem;
}
/* kmem_cache_free implementation. */
{
}
/*
*
* Mutex Semaphore Wrappers.
*
*/
/** Initializes a mutex. */
{
if (RT_SUCCESS(rc))
return 0;
return -1;
}
/** Deletes a mutex. */
{
return;
}
/* mutex_enter implementation */
{
if (pMtx == &g_DummyMtx)
return;
}
/* mutex_exit implementation */
{
if (pMtx == &g_DummyMtx)
return;
}
/* MUTEX_HELD implementation */
{
AssertPtrReturn(pMtx, false);
if (pMtx == &g_DummyMtx)
return true;
}
/*
*
* Helpers for handling VTG structures.
* Helpers for handling VTG structures.
* Helpers for handling VTG structures.
*
*/
/**
* 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.
*/
{
}
/*
*
* DTrace Provider Interface.
* DTrace Provider Interface.
* DTrace Provider Interface.
*
*/
/**
* @callback_method_impl{dtrace_pops_t,dtps_provide}
*/
{
LOG_DTRACE(("%s: %p / %p pDtProbeDesc=%p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc));
if (pDtProbeDesc)
return; /* We don't generate probes, so never mind these requests. */
return;
/* 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.
*/
uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc);
{
/* Skip probe location belonging to other providers or once that
we've already reported. */
continue;
else
if (*pidProbe != 0)
continue;
/* The function name may need to be stripped since we're using C++
enough to use function pointer returns without typedef'ing
properly them (e.g. signal). */
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) */
{
{
unsigned iOrd = 2;
while (iOrd < 128)
{
break;
iOrd++;
}
if (iOrd >= 128)
{
LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
continue;
}
}
}
/* Create the probe. */
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_enable}
*/
{
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);
{
if (!pProbeLocEn->fEnabled)
{
}
}
else
{
/* Update kernel mode structure */
{
}
/* Update user mode structure. */
}
}
return 0;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_disable}
*/
{
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);
{
if (pProbeLocEn->fEnabled)
{
pProbeLocEn->fEnabled = 0;
}
}
else
{
/* Update kernel mode structure */
{
}
/* Update user mode structure. */
pProbeLocEn->fEnabled = 0;
}
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
*/
{
LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
{
+ pProbeDesc->offArgList);
{
{
/** @todo mapping? */
return;
}
}
}
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_getargval}
*/
{
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;
+ pProbeDesc->offArgList);
/*
* Get the stack data. This is a wee bit complicated on 32-bit systems
* since we want to support 64-bit integer arguments.
*/
if (iArg >= 20)
u64Ret = UINT64_MAX;
{
#if ARCH_BITS == 64
#else
if ( !pArgList->fHaveLargeArgs
else
{
/* Similar to what we did for mac in when calling dtrace_probe(). */
for (int i = 5; i < iArg; i++)
offArg++;
}
#endif
}
{
{
if ( !pArgList->fHaveLargeArgs
{
else
u64Ret = UINT64_MAX;
}
else
{
for (int i = 5; i < iArg; i++)
offArg++;
{
}
else
u64Ret = UINT64_MAX;
}
}
else
{
else
u64Ret = UINT64_MAX;
}
}
else
return u64Ret;
}
/**
* @callback_method_impl{dtrace_pops_t,dtps_destroy}
*/
{
LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
{
{
}
else
{
}
*pidProbe = 0;
}
}
/**
* DTrace provider method table.
*/
static const dtrace_pops_t g_vboxDtVtgProvOps =
{
/* .dtps_provide = */ vboxDtPOps_Provide,
/* .dtps_provide_module = */ NULL,
/* .dtps_enable = */ vboxDtPOps_Enable,
/* .dtps_disable = */ vboxDtPOps_Disable,
/* .dtps_suspend = */ NULL,
/* .dtps_resume = */ NULL,
/* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
/* .dtps_getargval = */ vboxDtPOps_GetArgVal,
/* .dtps_usermode = */ NULL,
/* .dtps_destroy = */ vboxDtPOps_Destroy
};
/*
*
* Support Driver Tracer Interface.
* Support Driver Tracer Interface.
* Support Driver Tracer Interface.
*
*/
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
*/
static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
{
/*
* Convert arguments from uintptr_t to uint64_t.
*/
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
if (!pArgList->fHaveLargeArgs)
else
{
{
iSrcArg++;
iDstArg++;
}
dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
}
#else
#endif
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
*/
static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
{
{
/*
* Combine two 32-bit arguments into one 64-bit argument where needed.
*/
PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
if (!pArgList->fHaveLargeArgs)
else
{
{
iSrcArg++;
iDstArg++;
}
dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
}
#else
#endif
}
{
}
else
AssertFailed();
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
*/
static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
{
return VERR_INVALID_MAGIC;
if (uArg)
return VERR_INVALID_PARAMETER;
return RTErrConvertFromErrno(rc);
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
*/
static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
{
return RTErrConvertFromErrno(rc);
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
*/
static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
{
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
/* Note! DTrace may call us back before dtrace_register returns, so we
have to point it to pCore->TracerData.DTrace.idProvider. */
&DtAttrs,
NULL /* cred */,
if (!rc)
{
rc = VINF_SUCCESS;
}
else
{
}
return rc;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
if (!rc)
{
rc = VINF_SUCCESS;
}
else
{
rc = VERR_TRY_AGAIN;
}
return rc;
}
/**
* interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
*/
static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
{
if (!rc)
{
rc = VINF_SUCCESS;
}
else
{
rc = VERR_TRY_AGAIN;
}
return rc;
}
/**
* The tracer registration record of the VBox DTrace implementation
*/
static SUPDRVTRACERREG g_VBoxDTraceReg =
{
};
/**
* Module termination code.
*
* @param hMod Opque module handle.
*/
{
}
/**
* Module initialization code.
*
* @param hMod Opque module handle.
*/
{
int rc = dtrace_attach();
if (rc == DDI_SUCCESS)
{
if (RT_SUCCESS(rc))
return rc;
}
else
{
}
return rc;
}