VirtualBox

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

Last change on this file since 64281 was 63510, checked in by vboxsync, 8 years ago

SUP: warnings (clang)

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

© 2023 Oracle
ContactPrivacy policyTerms of Use