VirtualBox

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

Last change on this file since 85637 was 85172, checked in by vboxsync, 5 years ago

SUPDrv: Build fixes for Xcode 11 / SDK 10.13. bugref:9790

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