VirtualBox

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

Last change on this file since 90520 was 85771, checked in by vboxsync, 4 years ago

SUPDrv: Use symbol_get to resolve dtrace symbols on linux. Needed for 5.7+ and fixes reference issue. (untested) [include fix] bugref:9733

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