VirtualBox

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

Last change on this file since 96407 was 96407, checked in by vboxsync, 22 months ago

scm copyright and license note update

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

© 2023 Oracle
ContactPrivacy policyTerms of Use