VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv-dtrace.cpp@ 67954

Last change on this file since 67954 was 64584, checked in by vboxsync, 8 years ago

SUPDrv-dtrace.cpp: the dtrace_register/invalidate/unregister APIs could perhaps mess up the AC flag, so safe+restore flags.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 41.6 KB
RevLine 
[40518]1/* $Id: SUPDrv-dtrace.cpp 64584 2016-11-04 19:08:09Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - DTrace Provider.
4 */
5
6/*
[62490]7 * Copyright (C) 2012-2016 Oracle Corporation
[40518]8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
[57358]28/*********************************************************************************************************************************
29* Header Files *
30*********************************************************************************************************************************/
[40518]31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#include "SUPDrvInternal.h"
33
34#include <VBox/err.h>
[40605]35#include <VBox/log.h>
[40600]36#include <VBox/VBoxTpG.h>
[40602]37
[40518]38#include <iprt/assert.h>
[40602]39#include <iprt/ctype.h>
40#include <iprt/mem.h>
[40857]41#include <iprt/errno.h>
42#ifdef RT_OS_DARWIN
43# include <iprt/dbg.h>
44#endif
[40518]45
[40857]46#ifdef RT_OS_DARWIN
47# include VBOX_PATH_MACOSX_DTRACE_H
[41354]48#elif defined(RT_OS_LINUX)
[49395]49/* Avoid type and define conflicts. */
50# undef UINT8_MAX
51# undef UINT16_MAX
52# undef UINT32_MAX
53# undef UINT64_MAX
54# undef INT64_MAX
55# undef INT64_MIN
56# define intptr_t dtrace_intptr_t
57
58# if 0
59/* DTrace experiments with the Unbreakable Enterprise Kernel (UEK2)
[41354]60 (Oracle Linux).
[48952]61 1. The dtrace.h here is from the dtrace module source, not
[41354]62 /usr/include/sys/dtrace.h nor /usr/include/dtrace.h.
[48952]63 2. To generate the missing entries for the dtrace module in Module.symvers
[41354]64 of UEK:
65 nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
66 | grep _crc_ \
67 | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
68 -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
69 >> Module.symvers
[49395]70 Update: Althernative workaround (active), resolve symbols dynamically.
[48952]71 3. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
72 and VBoxTpG and build time. */
[49395]73# include "dtrace.h"
74# else
75/* DTrace experiments with the Unbreakable Enterprise Kernel (UEKR3)
76 (Oracle Linux).
77 1. To generate the missing entries for the dtrace module in Module.symvers
78 of UEK:
79 nm /lib/modules/....../kernel/drivers/dtrace/dtrace.ko \
80 | grep _crc_ \
81 | sed -e 's/^......../0x/' -e 's/ A __crc_/\t/' \
82 -e 's/$/\tdrivers\/dtrace\/dtrace\tEXPORT_SYMBOL/' \
83 >> Module.symvers
84 Update: Althernative workaround (active), resolve symbols dynamically.
85 2. No tracepoints in vboxdrv, vboxnet* or vboxpci yet. This requires yasm
86 and VBoxTpG and build time. */
87# include <dtrace/provider.h>
88# include <dtrace/enabling.h> /* Missing from provider.h. */
89# include <dtrace/arg.h> /* Missing from provider.h. */
90# endif
91# include <linux/kallsyms.h>
92/** Status code fixer (UEK uses linux convension unlike the others). */
[41357]93# define FIX_UEK_RC(a_rc) (-(a_rc))
[40602]94#else
95# include <sys/dtrace.h>
96#endif
[40518]97
98
[48952]99/**
100 * The UEK DTrace port is trying to be smart and seems to have turned all
[41357]101 * errno return codes negative. While this conforms to the linux kernel way of
[48952]102 * doing things, it breaks with the way the interfaces work on Solaris and
[41357]103 * Mac OS X.
104 */
105#ifndef FIX_UEK_RC
[48952]106# define FIX_UEK_RC(a_rc) (a_rc)
[41357]107#endif
108
109
[64584]110/** @name Macros for preserving EFLAGS.AC (despair / paranoid)
111 * @remarks We have to restore it unconditionally on darwin.
112 * @{ */
113#if defined(RT_OS_DARWIN) \
114 || ( defined(RT_OS_LINUX) \
115 && (defined(CONFIG_X86_SMAP) || defined(RT_STRICT) || defined(IPRT_WITH_EFLAGS_AC_PRESERVING) ) )
116# include <iprt/asm-amd64-x86.h>
117# include <iprt/x86.h>
118# define SUPDRV_SAVE_EFL_AC() RTCCUINTREG const fSavedEfl = ASMGetFlags();
119# define SUPDRV_RESTORE_EFL_AC() ASMSetFlags(fSavedEfl)
120# define SUPDRV_RESTORE_EFL_ONLY_AC() ASMChangeFlags(~X86_EFL_AC, fSavedEfl & X86_EFL_AC)
121#else
122# define SUPDRV_SAVE_EFL_AC() do { } while (0)
123# define SUPDRV_RESTORE_EFL_AC() do { } while (0)
124# define SUPDRV_RESTORE_EFL_ONLY_AC() do { } while (0)
125#endif
126/** @} */
127
128
[57358]129/*********************************************************************************************************************************
130* Structures and Typedefs *
131*********************************************************************************************************************************/
[40602]132/* Seems there is some return code difference here. Keep the return code and
133 case it to whatever the host desires. */
[40893]134#ifdef RT_OS_DARWIN
135# if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
[40602]136typedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
[40893]137# else
138typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
139# endif
[40602]140#else
141typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
142#endif
[40600]143
[41130]144/** Caller indicator. */
145typedef enum VBOXDTCALLER
146{
147 kVBoxDtCaller_Invalid = 0,
148 kVBoxDtCaller_Generic,
149 kVBoxDtCaller_ProbeFireUser,
150 kVBoxDtCaller_ProbeFireKernel
151} VBOXDTCALLER;
[40602]152
[41130]153
[40851]154/**
155 * Stack data planted before calling dtrace_probe so that we can easily find the
156 * stack argument later.
157 */
[41130]158typedef struct VBDTSTACKDATA
[40851]159{
160 /** Eyecatcher no. 1 (SUPDRVDT_STACK_DATA_MAGIC2). */
161 uint32_t u32Magic1;
162 /** Eyecatcher no. 2 (SUPDRVDT_STACK_DATA_MAGIC2). */
163 uint32_t u32Magic2;
[41130]164 /** The format of the caller specific data. */
165 VBOXDTCALLER enmCaller;
166 /** Caller specific data. */
167 union
168 {
169 /** kVBoxDtCaller_ProbeFireKernel. */
170 struct
171 {
172 /** Pointer to the stack arguments of a probe function call. */
173 uintptr_t *pauStackArgs;
174 } ProbeFireKernel;
175 /** kVBoxDtCaller_ProbeFireUser. */
176 struct
177 {
178 /** The user context. */
179 PCSUPDRVTRACERUSRCTX pCtx;
180 /** The argument displacement caused by 64-bit arguments passed directly to
181 * dtrace_probe. */
182 int offArg;
183 } ProbeFireUser;
184 } u;
[40851]185 /** Pointer to this structure.
186 * This is the final bit of integrity checking. */
[41130]187 struct VBDTSTACKDATA *pSelf;
188} VBDTSTACKDATA;
[40851]189/** Pointer to the on-stack thread specific data. */
[41130]190typedef VBDTSTACKDATA *PVBDTSTACKDATA;
[40704]191
[40865]192
[57358]193/*********************************************************************************************************************************
194* Defined Constants And Macros *
195*********************************************************************************************************************************/
[40851]196/** The first magic value. */
197#define SUPDRVDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('S', 'U', 'P', 'D')
198/** The second magic value. */
199#define SUPDRVDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
[40518]200
[40851]201/** The alignment of the stack data.
202 * The data doesn't require more than sizeof(uintptr_t) alignment, but the
203 * greater alignment the quicker lookup. */
204#define SUPDRVDT_STACK_DATA_ALIGN 32
[40518]205
[40851]206/** Plants the stack data. */
[41130]207#define VBDT_SETUP_STACK_DATA(a_enmCaller) \
208 uint8_t abBlob[sizeof(VBDTSTACKDATA) + SUPDRVDT_STACK_DATA_ALIGN - 1]; \
209 PVBDTSTACKDATA pStackData = (PVBDTSTACKDATA)( (uintptr_t)&abBlob[SUPDRVDT_STACK_DATA_ALIGN - 1] \
210 & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1)); \
[40851]211 pStackData->u32Magic1 = SUPDRVDT_STACK_DATA_MAGIC1; \
212 pStackData->u32Magic2 = SUPDRVDT_STACK_DATA_MAGIC2; \
[41130]213 pStackData->enmCaller = a_enmCaller; \
[40851]214 pStackData->pSelf = pStackData
[40518]215
[40851]216/** Passifies the stack data and frees up resource held within it. */
[41130]217#define VBDT_CLEAR_STACK_DATA() \
[40851]218 do \
219 { \
220 pStackData->u32Magic1 = 0; \
221 pStackData->u32Magic2 = 0; \
222 pStackData->pSelf = NULL; \
223 } while (0)
224
[40867]225/** Simple SUPR0Printf-style logging. */
226#if 0 /*def DEBUG_bird*/
[40865]227# define LOG_DTRACE(a) SUPR0Printf a
228#else
229# define LOG_DTRACE(a) do { } while (0)
230#endif
[40851]231
[40865]232
[57358]233/*********************************************************************************************************************************
234* Global Variables *
235*********************************************************************************************************************************/
[49395]236#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
237/** @name DTrace kernel interface used on Darwin and Linux.
[40857]238 * @{ */
239static void (* g_pfnDTraceProbeFire)(dtrace_id_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
240static dtrace_id_t (* g_pfnDTraceProbeCreate)(dtrace_provider_id_t, const char *, const char *, const char *, int, void *);
241static dtrace_id_t (* g_pfnDTraceProbeLookup)(dtrace_provider_id_t, const char *, const char *, const char *);
242static int (* g_pfnDTraceProviderRegister)(const char *, const dtrace_pattr_t *, uint32_t, /*cred_t*/ void *,
243 const dtrace_pops_t *, void *, dtrace_provider_id_t *);
244static void (* g_pfnDTraceProviderInvalidate)(dtrace_provider_id_t);
245static int (* g_pfnDTraceProviderUnregister)(dtrace_provider_id_t);
246
247#define dtrace_probe g_pfnDTraceProbeFire
248#define dtrace_probe_create g_pfnDTraceProbeCreate
249#define dtrace_probe_lookup g_pfnDTraceProbeLookup
250#define dtrace_register g_pfnDTraceProviderRegister
251#define dtrace_invalidate g_pfnDTraceProviderInvalidate
252#define dtrace_unregister g_pfnDTraceProviderUnregister
253
[40851]254/** @} */
[40704]255#endif
[40518]256
257
[41130]258/**
259 * Gets the stack data.
260 *
261 * @returns Pointer to the stack data. Never NULL.
262 */
263static PVBDTSTACKDATA vboxDtGetStackData(void)
264{
265 /*
266 * Locate the caller of probe_dtrace.
267 */
268 int volatile iDummy = 1; /* use this to get the stack address. */
269 PVBDTSTACKDATA pData = (PVBDTSTACKDATA)( ((uintptr_t)&iDummy + SUPDRVDT_STACK_DATA_ALIGN - 1)
270 & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1));
271 for (;;)
272 {
273 if ( pData->u32Magic1 == SUPDRVDT_STACK_DATA_MAGIC1
274 && pData->u32Magic2 == SUPDRVDT_STACK_DATA_MAGIC2
275 && pData->pSelf == pData)
276 return pData;
277 pData = (PVBDTSTACKDATA)((uintptr_t)pData + SUPDRVDT_STACK_DATA_ALIGN);
278 }
279}
280
281
[40851]282/*
[40602]283 *
[40851]284 * Helpers for handling VTG structures.
285 * Helpers for handling VTG structures.
286 * Helpers for handling VTG structures.
287 *
[40600]288 */
289
[40601]290
[40600]291
[40518]292/**
[40602]293 * Converts an attribute from VTG description speak to DTrace.
294 *
295 * @param pDtAttr The DTrace attribute (dst).
296 * @param pVtgAttr The VTG attribute descriptor (src).
297 */
[40851]298static void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
[40602]299{
300 pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
301 pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
302 pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
303}
304
305/**
306 * Gets a string from the string table.
307 *
308 * @returns Pointer to the string.
309 * @param pVtgHdr The VTG object header.
310 * @param offStrTab The string table offset.
311 */
[41130]312static const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
[40602]313{
314 Assert(offStrTab < pVtgHdr->cbStrTab);
[41130]315 return (const char *)pVtgHdr + pVtgHdr->offStrTab + offStrTab;
[40602]316}
317
318
[40675]319
[40851]320/*
[40756]321 *
[40851]322 * DTrace Provider Interface.
323 * DTrace Provider Interface.
324 * DTrace Provider Interface.
[40756]325 *
[40704]326 */
327
328
329/**
[40602]330 * @callback_method_impl{dtrace_pops_t,dtps_provide}
[40518]331 */
[41130]332static void vboxDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
[40518]333{
[41130]334 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
[40865]335 AssertPtrReturnVoid(pProv);
[41130]336 LOG_DTRACE(("%s: %p / %p pDtProbeDesc=%p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc));
[40602]337
338 if (pDtProbeDesc)
339 return; /* We don't generate probes, so never mind these requests. */
340
[40851]341 if (pProv->TracerData.DTrace.fZombie)
[40675]342 return;
343
[41130]344 dtrace_provider_id_t const idProvider = pProv->TracerData.DTrace.idProvider;
[40898]345 AssertPtrReturnVoid(idProvider);
[40975]346
[40898]347 AssertPtrReturnVoid(pProv->pHdr);
[41130]348 AssertReturnVoid(pProv->pHdr->offProbeLocs != 0);
349 uint32_t const cProbeLocs = pProv->pHdr->cbProbeLocs / sizeof(VTGPROBELOC);
[40617]350
[41130]351 /* Need a buffer for extracting the function names and mangling them in
352 case of collision. */
353 size_t const cbFnNmBuf = _4K + _1K;
354 char *pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
355 if (!pszFnNmBuf)
[40602]356 return;
357
[41130]358 /*
359 * Itereate the probe location list and register all probes related to
360 * this provider.
361 */
362 uint16_t const idxProv = (uint16_t)((PVTGDESCPROVIDER)((uintptr_t)pProv->pHdr + pProv->pHdr->offProviders) - pProv->pDesc);
[41354]363 uint32_t idxProbeLoc;
364 for (idxProbeLoc = 0; idxProbeLoc < cProbeLocs; idxProbeLoc++)
[41130]365 {
366 /* Skip probe location belonging to other providers or once that
367 we've already reported. */
368 PCVTGPROBELOC pProbeLocRO = &pProv->paProbeLocsRO[idxProbeLoc];
369 PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
370 if (pProbeDesc->idxProvider != idxProv)
371 continue;
372
373 uint32_t *pidProbe;
374 if (!pProv->fUmod)
375 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
376 else
377 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
378 if (*pidProbe != 0)
379 continue;
380
381 /* The function name may need to be stripped since we're using C++
382 compilers for most of the code. ASSUMES nobody are brave/stupid
383 enough to use function pointer returns without typedef'ing
384 properly them (e.g. signal). */
385 const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName);
386 const char *pszFunc = pProbeLocRO->pszFunction;
387 const char *psz = strchr(pProbeLocRO->pszFunction, '(');
388 size_t cch;
389 if (psz)
[40602]390 {
[41130]391 /* skip blanks preceeding the parameter parenthesis. */
392 while ( (uintptr_t)psz > (uintptr_t)pProbeLocRO->pszFunction
393 && RT_C_IS_BLANK(psz[-1]))
394 psz--;
395
396 /* Find the start of the function name. */
397 pszFunc = psz - 1;
398 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLocRO->pszFunction)
[40602]399 {
[41130]400 char ch = pszFunc[-1];
401 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
402 break;
403 pszFunc--;
[40602]404 }
[41130]405 cch = psz - pszFunc;
406 }
407 else
408 cch = strlen(pszFunc);
409 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
[40602]410
[41130]411 /* Look up the probe, if we have one in the same function, mangle
412 the function name a little to avoid having to deal with having
413 multiple location entries with the same probe ID. (lazy bird) */
414 Assert(!*pidProbe);
415 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
416 {
417 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLocRO->uLine);
[40851]418 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
[40605]419 {
[41130]420 unsigned iOrd = 2;
421 while (iOrd < 128)
[40605]422 {
[41130]423 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLocRO->uLine, iOrd);
424 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
425 break;
426 iOrd++;
[40605]427 }
[41130]428 if (iOrd >= 128)
429 {
430 LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
431 pProbeLocRO->uLine, pProbeLocRO->pszFunction, pszFnNmBuf, pszPrbName));
432 continue;
433 }
[40605]434 }
[40602]435 }
436
[41130]437 /* Create the probe. */
438 AssertCompile(sizeof(*pidProbe) == sizeof(dtrace_id_t));
439 *pidProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName,
440 1 /*aframes*/, (void *)(uintptr_t)idxProbeLoc);
441 pProv->TracerData.DTrace.cProvidedProbes++;
[40602]442 }
443
444 RTMemFree(pszFnNmBuf);
[41130]445 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
[40518]446}
447
448
449/**
450 * @callback_method_impl{dtrace_pops_t,dtps_enable}
451 */
[41130]452static int vboxDtPOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
[40518]453{
[41130]454 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
[63510]455 RT_NOREF(idProbe);
[41130]456 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
[40865]457 AssertPtrReturn(pProv->TracerData.DTrace.idProvider, EINVAL);
458
[40851]459 if (!pProv->TracerData.DTrace.fZombie)
[40675]460 {
[41130]461 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
462 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
463 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
464 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
465 uint32_t const idxProbe = pProbeDesc->idxEnabled;
[40602]466
[41130]467 if (!pProv->fUmod)
[40675]468 {
[41130]469 if (!pProbeLocEn->fEnabled)
470 {
471 pProbeLocEn->fEnabled = 1;
472 ASMAtomicIncU32(&pProv->pacProbeEnabled[idxProbe]);
[58920]473 ASMAtomicIncU32(&pProv->pDesc->cProbesEnabled);
[58976]474 ASMAtomicIncU32(&pProv->pDesc->uSettingsSerialNo);
[41130]475 }
[40675]476 }
[41130]477 else
478 {
479 /* Update kernel mode structure */
480 if (!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
481 {
482 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 1;
483 ASMAtomicIncU32(&pProv->paR0Probes[idxProbe].cEnabled);
[58920]484 ASMAtomicIncU32(&pProv->pDesc->cProbesEnabled);
[58976]485 ASMAtomicIncU32(&pProv->pDesc->uSettingsSerialNo);
[41130]486 }
487
488 /* Update user mode structure. */
489 pProbeLocEn->fEnabled = 1;
490 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
491 }
[40602]492 }
493
494 return 0;
[40518]495}
496
497
498/**
499 * @callback_method_impl{dtrace_pops_t,dtps_disable}
500 */
[41130]501static void vboxDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
[40518]502{
[40851]503 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
[40865]504 AssertPtrReturnVoid(pProv);
[63510]505 RT_NOREF(idProbe);
[41130]506 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
[40865]507 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
508
[40851]509 if (!pProv->TracerData.DTrace.fZombie)
[40675]510 {
[41130]511 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
512 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
513 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
514 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
515 uint32_t const idxProbe = pProbeDesc->idxEnabled;
[40602]516
[41130]517 if (!pProv->fUmod)
[40675]518 {
[41130]519 if (pProbeLocEn->fEnabled)
520 {
521 pProbeLocEn->fEnabled = 0;
522 ASMAtomicDecU32(&pProv->pacProbeEnabled[idxProbe]);
[58920]523 ASMAtomicIncU32(&pProv->pDesc->cProbesEnabled);
[58976]524 ASMAtomicIncU32(&pProv->pDesc->uSettingsSerialNo);
[41130]525 }
[40675]526 }
[41130]527 else
528 {
529 /* Update kernel mode structure */
530 if (pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
531 {
532 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 0;
533 ASMAtomicDecU32(&pProv->paR0Probes[idxProbe].cEnabled);
[58920]534 ASMAtomicDecU32(&pProv->pDesc->cProbesEnabled);
[58976]535 ASMAtomicIncU32(&pProv->pDesc->uSettingsSerialNo);
[41130]536 }
537
538 /* Update user mode structure. */
539 pProbeLocEn->fEnabled = 0;
540 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
541 }
[40602]542 }
[40518]543}
544
545
546/**
547 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
548 */
[41130]549static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
550 dtrace_argdesc_t *pArgDesc)
[40518]551{
[40851]552 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
553 unsigned uArg = pArgDesc->dtargd_ndx;
[63510]554 RT_NOREF(idProbe);
[40602]555
[40865]556 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
557 AssertPtrReturnVoid(pProv);
[41130]558 LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
[40865]559 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
560
[40851]561 if (!pProv->TracerData.DTrace.fZombie)
[40602]562 {
[41130]563 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
564 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
565 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
566 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
567 + pProv->pHdr->offArgLists
568 + pProbeDesc->offArgList);
569 AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
[40675]570
[40885]571 if (uArg < pArgList->cArgs)
[40617]572 {
[40851]573 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
[40675]574 size_t cchType = strlen(pszType);
575 if (cchType < sizeof(pArgDesc->dtargd_native))
576 {
577 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
[40878]578 /** @todo mapping? */
[40865]579 pArgDesc->dtargd_ndx = uArg;
[41130]580 LOG_DTRACE(("%s: returns dtargd_native = %s\n", __FUNCTION__, pArgDesc->dtargd_native));
[40675]581 return;
582 }
[40617]583 }
[40602]584 }
[40518]585}
586
587
588/**
[40857]589 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
590 *
591 *
592 * We just cook our own stuff here, using a stack marker for finding the
593 * required information. That's more reliable than subjecting oneself to the
594 * solaris bugs and 32-bit apple peculiarities.
595 *
596 *
[40851]597 * @remarks Solaris Bug
[40857]598 *
599 * dtrace_getarg on AMD64 has a different opinion about how to use the cFrames
600 * argument than dtrace_caller() and/or dtrace_getpcstack(), at least when the
601 * probe is fired by dtrace_probe() the way we do.
602 *
[40851]603 * Setting aframes to 1 when calling dtrace_probe_create gives me the right
604 * arguments, but the wrong 'caller'. Since I cannot do anything about
605 * 'caller', the only solution is this hack.
[40857]606 *
[40851]607 * Not sure why the Solaris guys hasn't seen this issue before, but maybe there
[40857]608 * isn't anyone using the default argument getter path for ring-0 dtrace_probe()
609 * calls, SDT surely isn't.
610 *
[40851]611 * @todo File a solaris bug on dtrace_probe() + dtrace_getarg().
[40857]612 *
613 *
614 * @remarks 32-bit XNU (Apple)
615 *
616 * The dtrace_probe arguments are 64-bit unsigned integers instead of uintptr_t,
617 * so we need to make an extra call.
618 *
[40518]619 */
[41130]620static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
621 int iArg, int cFrames)
[40518]622{
[41130]623 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
[40865]624 AssertPtrReturn(pProv, UINT64_MAX);
[63510]625 RT_NOREF(idProbe, cFrames);
[41130]626 LOG_DTRACE(("%s: %p / %p - %#x / %p iArg=%d cFrames=%u\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
[40851]627 AssertReturn(iArg >= 5, UINT64_MAX);
[41130]628 if (pProv->TracerData.DTrace.fZombie)
629 return UINT64_MAX;
[40756]630
[41130]631 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
632 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
633 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
634 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
635 + pProv->pHdr->offArgLists
636 + pProbeDesc->offArgList);
637 AssertReturn(pProbeDesc->offArgList < pProv->pHdr->cbArgLists, UINT64_MAX);
[40756]638
[41130]639 PVBDTSTACKDATA pData = vboxDtGetStackData();
640
[40892]641 /*
642 * Get the stack data. This is a wee bit complicated on 32-bit systems
643 * since we want to support 64-bit integer arguments.
644 */
[41130]645 uint64_t u64Ret;
646 if (iArg >= 20)
647 u64Ret = UINT64_MAX;
648 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
649 {
[40878]650#if ARCH_BITS == 64
[41130]651 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
[40878]652#else
[41130]653 if ( !pArgList->fHaveLargeArgs
654 || iArg >= pArgList->cArgs)
655 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
656 else
657 {
658 /* Similar to what we did for mac in when calling dtrace_probe(). */
659 uint32_t offArg = 0;
660 for (int i = 5; i < iArg; i++)
661 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
662 offArg++;
663 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg];
[40892]664 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
[41130]665 u64Ret |= (uint64_t)pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg + 1] << 32;
666 }
667#endif
[40878]668 }
[41130]669 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
670 {
671 int offArg = pData->u.ProbeFireUser.offArg;
672 PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
673 AssertPtrReturn(pCtx, UINT64_MAX);
[40878]674
[41130]675 if (pCtx->cBits == 32)
676 {
677 if ( !pArgList->fHaveLargeArgs
678 || iArg >= pArgList->cArgs)
679 {
680 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
[41164]681 u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
[41130]682 else
683 u64Ret = UINT64_MAX;
684 }
685 else
686 {
[41354]687 int i;
688 for (i = 5; i < iArg; i++)
[41130]689 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
690 offArg++;
691 if (offArg + iArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
692 {
693 u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
694 if ( VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType)
695 && offArg + iArg + 1 < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
696 u64Ret |= (uint64_t)pCtx->u.X86.aArgs[iArg + offArg + 1] << 32;
697 }
698 else
699 u64Ret = UINT64_MAX;
700 }
701 }
702 else
703 {
704 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.Amd64.aArgs))
705 u64Ret = pCtx->u.Amd64.aArgs[iArg + offArg];
706 else
707 u64Ret = UINT64_MAX;
708 }
709 }
710 else
711 AssertFailedReturn(UINT64_MAX);
712
713 LOG_DTRACE(("%s: returns %#llx\n", __FUNCTION__, u64Ret));
[40878]714 return u64Ret;
[40518]715}
716
717
718/**
719 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
720 */
[41130]721static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
[40518]722{
[40851]723 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
[40865]724 AssertPtrReturnVoid(pProv);
[41130]725 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
[40865]726 AssertReturnVoid(pProv->TracerData.DTrace.cProvidedProbes > 0);
727 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
728
[40851]729 if (!pProv->TracerData.DTrace.fZombie)
[40675]730 {
[41130]731 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
732 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
733 uint32_t *pidProbe;
734 if (!pProv->fUmod)
735 {
736 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
737 Assert(!pProbeLocRO->fEnabled);
738 Assert(*pidProbe == idProbe);
739 }
740 else
741 {
742 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
743 Assert(!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled);
744 Assert(*pidProbe == idProbe); NOREF(idProbe);
745 }
746 *pidProbe = 0;
[40675]747 }
[40851]748 pProv->TracerData.DTrace.cProvidedProbes--;
[40518]749}
750
[40851]751
752
753/**
754 * DTrace provider method table.
755 */
756static const dtrace_pops_t g_vboxDtVtgProvOps =
757{
[41130]758 /* .dtps_provide = */ vboxDtPOps_Provide,
[40851]759 /* .dtps_provide_module = */ NULL,
[41130]760 /* .dtps_enable = */ (FNPOPS_ENABLE *)vboxDtPOps_Enable,
761 /* .dtps_disable = */ vboxDtPOps_Disable,
[40851]762 /* .dtps_suspend = */ NULL,
763 /* .dtps_resume = */ NULL,
[41130]764 /* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
765 /* .dtps_getargval = */ vboxDtPOps_GetArgVal,
[40851]766 /* .dtps_usermode = */ NULL,
[41130]767 /* .dtps_destroy = */ vboxDtPOps_Destroy
[40851]768};
769
770
771
772
773/*
774 *
775 * Support Driver Tracer Interface.
776 * Support Driver Tracer Interface.
777 * Support Driver Tracer Interface.
778 *
779 */
780
781
782
783/**
[41130]784 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
[40851]785 */
[41130]786static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
787 uintptr_t uArg3, uintptr_t uArg4)
[40851]788{
[40865]789 AssertPtrReturnVoid(pVtgProbeLoc);
[41130]790 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pVtgProbeLoc, pVtgProbeLoc->idProbe));
791 AssertPtrReturnVoid(pVtgProbeLoc->pProbe);
[40865]792 AssertPtrReturnVoid(pVtgProbeLoc->pszFunction);
793
[64584]794 SUPDRV_SAVE_EFL_AC();
[41130]795 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
[40851]796
[41130]797 pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
[40892]798
799#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
800 /*
801 * Convert arguments from uintptr_t to uint64_t.
802 */
[41144]803 PVTGDESCPROBE pProbe = (PVTGDESCPROBE)((PVTGPROBELOC)pVtgProbeLoc)->pProbe;
[40892]804 AssertPtrReturnVoid(pProbe);
805 PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)((uintptr_t)pProbe + pProbe->offObjHdr);
806 AssertPtrReturnVoid(pVtgHdr);
[41130]807 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
[40892]808 AssertPtrReturnVoid(pArgList);
809 if (!pArgList->fHaveLargeArgs)
810 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
811 else
812 {
813 uintptr_t *auSrcArgs = &uArg0;
814 uint32_t iSrcArg = 0;
815 uint32_t iDstArg = 0;
816 uint64_t au64DstArgs[5];
817
818 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
819 && iSrcArg < pArgList->cArgs)
820 {
821 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
822 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
823 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
824 iSrcArg++;
825 iDstArg++;
826 }
827 while (iDstArg < RT_ELEMENTS(au64DstArgs))
828 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
829
[41144]830 pStackData->u.ProbeFireKernel.pauStackArgs = &auSrcArgs[iSrcArg];
[40892]831 dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
832 }
833#else
[40851]834 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
[40892]835#endif
[40851]836
[41130]837 VBDT_CLEAR_STACK_DATA();
[64584]838 SUPDRV_RESTORE_EFL_AC();
[41130]839 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
[40851]840}
841
842
843/**
844 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
845 */
[41130]846static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
847 PCVTGOBJHDR pVtgHdr, PCVTGPROBELOC pProbeLocRO)
[40851]848{
[63510]849 RT_NOREF(pThis, pSession);
[41130]850 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pCtx, pCtx->idProbe));
851 AssertPtrReturnVoid(pProbeLocRO);
852 AssertPtrReturnVoid(pVtgHdr);
853
[64584]854 SUPDRV_SAVE_EFL_AC();
[41130]855 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
856
857 if (pCtx->cBits == 32)
858 {
859 pStackData->u.ProbeFireUser.pCtx = pCtx;
860 pStackData->u.ProbeFireUser.offArg = 0;
861
862#if ARCH_BITS == 64 || defined(RT_OS_DARWIN)
863 /*
864 * Combine two 32-bit arguments into one 64-bit argument where needed.
865 */
866 PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
867 AssertPtrReturnVoid(pProbeDesc);
868 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
869 AssertPtrReturnVoid(pArgList);
870
871 if (!pArgList->fHaveLargeArgs)
872 dtrace_probe(pCtx->idProbe,
873 pCtx->u.X86.aArgs[0],
874 pCtx->u.X86.aArgs[1],
875 pCtx->u.X86.aArgs[2],
876 pCtx->u.X86.aArgs[3],
877 pCtx->u.X86.aArgs[4]);
878 else
879 {
880 uint32_t const *auSrcArgs = &pCtx->u.X86.aArgs[0];
881 uint32_t iSrcArg = 0;
882 uint32_t iDstArg = 0;
883 uint64_t au64DstArgs[5];
884
885 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
886 && iSrcArg < pArgList->cArgs)
887 {
888 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
889 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
890 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
891 iSrcArg++;
892 iDstArg++;
893 }
894 while (iDstArg < RT_ELEMENTS(au64DstArgs))
895 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
896
897 pStackData->u.ProbeFireUser.offArg = iSrcArg - RT_ELEMENTS(au64DstArgs);
898 dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
899 }
900#else
901 dtrace_probe(pCtx->idProbe,
902 pCtx->u.X86.aArgs[0],
903 pCtx->u.X86.aArgs[1],
904 pCtx->u.X86.aArgs[2],
905 pCtx->u.X86.aArgs[3],
906 pCtx->u.X86.aArgs[4]);
907#endif
908 }
909 else if (pCtx->cBits == 64)
910 {
911 pStackData->u.ProbeFireUser.pCtx = pCtx;
912 pStackData->u.ProbeFireUser.offArg = 0;
913 dtrace_probe(pCtx->idProbe,
914 pCtx->u.Amd64.aArgs[0],
915 pCtx->u.Amd64.aArgs[1],
916 pCtx->u.Amd64.aArgs[2],
917 pCtx->u.Amd64.aArgs[3],
918 pCtx->u.Amd64.aArgs[4]);
919 }
920 else
921 AssertFailed();
922
923 VBDT_CLEAR_STACK_DATA();
[64584]924 SUPDRV_RESTORE_EFL_AC();
[41130]925 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
[40851]926}
927
928
929/**
930 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
931 */
[41130]932static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
933 uintptr_t uArg, uintptr_t *puSessionData)
[40851]934{
935 NOREF(pThis); NOREF(pSession); NOREF(uCookie); NOREF(uArg);
936 *puSessionData = 0;
937 return VERR_NOT_SUPPORTED;
938}
939
940
941/**
942 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
943 */
[41130]944static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
945 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
[40851]946{
947 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
948 NOREF(uCmd); NOREF(uArg); NOREF(piRetVal);
949 return VERR_NOT_SUPPORTED;
950}
951
952
953/**
954 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
955 */
[41130]956static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
[40851]957{
958 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
959 return;
960}
961
962
963/**
964 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
965 */
[41130]966static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
[40851]967{
[63510]968 RT_NOREF(pThis);
[41130]969 LOG_DTRACE(("%s: %p %s/%s\n", __FUNCTION__, pThis, pCore->pszModName, pCore->pszName));
970 AssertReturn(pCore->TracerData.DTrace.idProvider == 0, VERR_INTERNAL_ERROR_3);
[40851]971
972 PVTGDESCPROVIDER pDesc = pCore->pDesc;
973 dtrace_pattr_t DtAttrs;
974 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
975 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
976 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
977 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
978 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
979
[40865]980 /* Note! DTrace may call us back before dtrace_register returns, so we
981 have to point it to pCore->TracerData.DTrace.idProvider. */
[41130]982 AssertCompile(sizeof(dtrace_provider_id_t) == sizeof(pCore->TracerData.DTrace.idProvider));
[64584]983 SUPDRV_SAVE_EFL_AC();
[40851]984 int rc = dtrace_register(pCore->pszName,
985 &DtAttrs,
986 DTRACE_PRIV_KERNEL,
987 NULL /* cred */,
988 &g_vboxDtVtgProvOps,
989 pCore,
[40865]990 &pCore->TracerData.DTrace.idProvider);
[64584]991 SUPDRV_RESTORE_EFL_AC();
[40851]992 if (!rc)
993 {
[41130]994 LOG_DTRACE(("%s: idProvider=%p\n", __FUNCTION__, pCore->TracerData.DTrace.idProvider));
[40865]995 AssertPtr(pCore->TracerData.DTrace.idProvider);
[40851]996 rc = VINF_SUCCESS;
997 }
998 else
[40865]999 {
[41130]1000 pCore->TracerData.DTrace.idProvider = 0;
[41357]1001 rc = RTErrConvertFromErrno(FIX_UEK_RC(rc));
[40865]1002 }
[40851]1003
[41130]1004 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
[40851]1005 return rc;
1006}
1007
1008
1009/**
1010 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
1011 */
[41130]1012static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
[40851]1013{
1014 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
[63510]1015 RT_NOREF(pThis);
[41130]1016 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
[40865]1017 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
[40851]1018
[64584]1019 SUPDRV_SAVE_EFL_AC();
[40851]1020 dtrace_invalidate(idProvider);
1021 int rc = dtrace_unregister(idProvider);
[64584]1022 SUPDRV_RESTORE_EFL_AC();
[40851]1023 if (!rc)
1024 {
[41130]1025 pCore->TracerData.DTrace.idProvider = 0;
[40851]1026 rc = VINF_SUCCESS;
1027 }
1028 else
1029 {
[41357]1030 AssertMsg(FIX_UEK_RC(rc) == EBUSY, ("%d\n", rc));
[40851]1031 pCore->TracerData.DTrace.fZombie = true;
1032 rc = VERR_TRY_AGAIN;
1033 }
1034
[41130]1035 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
[40851]1036 return rc;
1037}
1038
1039
1040/**
1041 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
1042 */
[41130]1043static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
[40851]1044{
1045 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
[63510]1046 RT_NOREF(pThis);
[41130]1047 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
[40865]1048 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
[40851]1049 Assert(pCore->TracerData.DTrace.fZombie);
1050
[64584]1051 SUPDRV_SAVE_EFL_AC();
[40851]1052 int rc = dtrace_unregister(idProvider);
[64584]1053 SUPDRV_RESTORE_EFL_AC();
[40851]1054 if (!rc)
1055 {
[41130]1056 pCore->TracerData.DTrace.idProvider = 0;
[40851]1057 rc = VINF_SUCCESS;
1058 }
1059 else
1060 {
[41357]1061 AssertMsg(FIX_UEK_RC(rc) == EBUSY, ("%d\n", rc));
[40851]1062 rc = VERR_TRY_AGAIN;
1063 }
1064
[41130]1065 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
[40851]1066 return rc;
1067}
1068
1069
1070
1071/**
1072 * The tracer registration record of the VBox DTrace implementation
1073 */
[41130]1074static SUPDRVTRACERREG g_VBoxDTraceReg =
[40851]1075{
1076 SUPDRVTRACERREG_MAGIC,
1077 SUPDRVTRACERREG_VERSION,
[41130]1078 vboxDtTOps_ProbeFireKernel,
1079 vboxDtTOps_ProbeFireUser,
1080 vboxDtTOps_TracerOpen,
1081 vboxDtTOps_TracerIoCtl,
1082 vboxDtTOps_TracerClose,
1083 vboxDtTOps_ProviderRegister,
1084 vboxDtTOps_ProviderDeregister,
1085 vboxDtTOps_ProviderDeregisterZombie,
[40851]1086 SUPDRVTRACERREG_MAGIC
1087};
1088
1089
1090
1091/**
1092 * Module initialization code.
1093 */
1094const SUPDRVTRACERREG * VBOXCALL supdrvDTraceInit(void)
1095{
[49395]1096#if defined(RT_OS_DARWIN) || defined(RT_OS_LINUX)
[40851]1097 /*
1098 * Resolve the kernel symbols we need.
1099 */
[49395]1100# ifndef RT_OS_LINUX
[40851]1101 RTDBGKRNLINFO hKrnlInfo;
1102 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
1103 if (RT_FAILURE(rc))
1104 {
1105 SUPR0Printf("supdrvDTraceInit: RTR0DbgKrnlInfoOpen failed with rc=%d.\n", rc);
1106 return NULL;
1107 }
[49395]1108# endif
[40851]1109
1110 static const struct
1111 {
1112 const char *pszName;
1113 PFNRT *ppfn;
1114 } s_aDTraceFunctions[] =
[40857]1115 {
[40851]1116 { "dtrace_probe", (PFNRT*)&dtrace_probe },
1117 { "dtrace_probe_create", (PFNRT*)&dtrace_probe_create },
1118 { "dtrace_probe_lookup", (PFNRT*)&dtrace_probe_lookup },
1119 { "dtrace_register", (PFNRT*)&dtrace_register },
1120 { "dtrace_invalidate", (PFNRT*)&dtrace_invalidate },
1121 { "dtrace_unregister", (PFNRT*)&dtrace_unregister },
1122 };
[49395]1123 unsigned i;
1124 for (i = 0; i < RT_ELEMENTS(s_aDTraceFunctions); i++)
[40851]1125 {
[49395]1126# ifndef RT_OS_LINUX
[40857]1127 rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, s_aDTraceFunctions[i].pszName,
[40851]1128 (void **)s_aDTraceFunctions[i].ppfn);
1129 if (RT_FAILURE(rc))
1130 {
1131 SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (rc=%Rrc, i=%u).\n", s_aDTraceFunctions[i].pszName, rc, i);
1132 break;
1133 }
[49395]1134# else
1135 unsigned long ulAddr = kallsyms_lookup_name(s_aDTraceFunctions[i].pszName);
1136 if (!ulAddr)
1137 {
1138 SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (i=%u).\n", s_aDTraceFunctions[i].pszName, i);
[49396]1139 return NULL;
[49395]1140 }
1141 *s_aDTraceFunctions[i].ppfn = (PFNRT)ulAddr;
1142# endif
[40851]1143 }
1144
[49395]1145# ifndef RT_OS_LINUX
[40851]1146 RTR0DbgKrnlInfoRelease(hKrnlInfo);
1147 if (RT_FAILURE(rc))
1148 return NULL;
[49396]1149# else
1150 /** @todo grab a reference to the dtrace module... */
[49395]1151# endif
[40851]1152#endif
1153
[41130]1154 return &g_VBoxDTraceReg;
[40851]1155}
1156
[40975]1157#ifndef VBOX_WITH_NATIVE_DTRACE
1158# error "VBOX_WITH_NATIVE_DTRACE is not defined as it should"
[40851]1159#endif
1160
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use