VirtualBox

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

Last change on this file since 107044 was 106061, checked in by vboxsync, 2 months ago

Copyright year updates by scm.

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette