VirtualBox

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

Last change on this file since 40975 was 40975, checked in by vboxsync, 13 years ago

VBoxTpG,SUPDrv,VBoxVMM: Working on static user land probes for the non-native platforms.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.1 KB
Line 
1/* $Id: SUPDrv-dtrace.cpp 40975 2012-04-18 14:49:24Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - DTrace Provider.
4 */
5
6/*
7 * Copyright (C) 2012 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#else
49# include <sys/dtrace.h>
50#endif
51
52
53/*******************************************************************************
54* Structures and Typedefs *
55*******************************************************************************/
56/* Seems there is some return code difference here. Keep the return code and
57 case it to whatever the host desires. */
58#ifdef RT_OS_DARWIN
59# if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
60typedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
61# else
62typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
63# endif
64#else
65typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
66#endif
67
68
69/**
70 * Stack data planted before calling dtrace_probe so that we can easily find the
71 * stack argument later.
72 */
73typedef struct SUPDRVDTSTACKDATA
74{
75 /** Eyecatcher no. 1 (SUPDRVDT_STACK_DATA_MAGIC2). */
76 uint32_t u32Magic1;
77 /** Eyecatcher no. 2 (SUPDRVDT_STACK_DATA_MAGIC2). */
78 uint32_t u32Magic2;
79 /** Pointer to the stack arguments of a probe function call. */
80 uintptr_t *pauStackArgs;
81 /** Pointer to this structure.
82 * This is the final bit of integrity checking. */
83 struct SUPDRVDTSTACKDATA *pSelf;
84} SUPDRVDTSTACKDATA;
85/** Pointer to the on-stack thread specific data. */
86typedef SUPDRVDTSTACKDATA *PSUPDRVDTSTACKDATA;
87
88
89/*******************************************************************************
90* Defined Constants And Macros *
91*******************************************************************************/
92/** The first magic value. */
93#define SUPDRVDT_STACK_DATA_MAGIC1 RT_MAKE_U32_FROM_U8('S', 'U', 'P', 'D')
94/** The second magic value. */
95#define SUPDRVDT_STACK_DATA_MAGIC2 RT_MAKE_U32_FROM_U8('D', 'T', 'r', 'c')
96
97/** The alignment of the stack data.
98 * The data doesn't require more than sizeof(uintptr_t) alignment, but the
99 * greater alignment the quicker lookup. */
100#define SUPDRVDT_STACK_DATA_ALIGN 32
101
102/** Plants the stack data. */
103#define SUPDRVDT_SETUP_STACK_DATA() \
104 uint8_t abBlob[sizeof(SUPDRVDTSTACKDATA) + SUPDRVDT_STACK_DATA_ALIGN - 1]; \
105 PSUPDRVDTSTACKDATA pStackData = (PSUPDRVDTSTACKDATA)( (uintptr_t)&abBlob[SUPDRVDT_STACK_DATA_ALIGN - 1] \
106 & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1)); \
107 pStackData->u32Magic1 = SUPDRVDT_STACK_DATA_MAGIC1; \
108 pStackData->u32Magic2 = SUPDRVDT_STACK_DATA_MAGIC2; \
109 pStackData->pSelf = pStackData
110
111/** Passifies the stack data and frees up resource held within it. */
112#define SUPDRVDT_CLEAR_STACK_DATA() \
113 do \
114 { \
115 pStackData->u32Magic1 = 0; \
116 pStackData->u32Magic2 = 0; \
117 pStackData->pSelf = NULL; \
118 } while (0)
119
120/** Simple SUPR0Printf-style logging. */
121#if 0 /*def DEBUG_bird*/
122# define LOG_DTRACE(a) SUPR0Printf a
123#else
124# define LOG_DTRACE(a) do { } while (0)
125#endif
126
127
128/*******************************************************************************
129* Global Variables *
130*******************************************************************************/
131#ifdef RT_OS_DARWIN
132/** @name DTrace kernel interface used on Darwin
133 * @{ */
134static void (* g_pfnDTraceProbeFire)(dtrace_id_t, uint64_t, uint64_t, uint64_t, uint64_t, uint64_t);
135static dtrace_id_t (* g_pfnDTraceProbeCreate)(dtrace_provider_id_t, const char *, const char *, const char *, int, void *);
136static dtrace_id_t (* g_pfnDTraceProbeLookup)(dtrace_provider_id_t, const char *, const char *, const char *);
137static int (* g_pfnDTraceProviderRegister)(const char *, const dtrace_pattr_t *, uint32_t, /*cred_t*/ void *,
138 const dtrace_pops_t *, void *, dtrace_provider_id_t *);
139static void (* g_pfnDTraceProviderInvalidate)(dtrace_provider_id_t);
140static int (* g_pfnDTraceProviderUnregister)(dtrace_provider_id_t);
141
142#define dtrace_probe g_pfnDTraceProbeFire
143#define dtrace_probe_create g_pfnDTraceProbeCreate
144#define dtrace_probe_lookup g_pfnDTraceProbeLookup
145#define dtrace_register g_pfnDTraceProviderRegister
146#define dtrace_invalidate g_pfnDTraceProviderInvalidate
147#define dtrace_unregister g_pfnDTraceProviderUnregister
148
149/** @} */
150#endif
151
152
153/*
154 *
155 * Helpers for handling VTG structures.
156 * Helpers for handling VTG structures.
157 * Helpers for handling VTG structures.
158 *
159 */
160
161
162
163/**
164 * Converts an attribute from VTG description speak to DTrace.
165 *
166 * @param pDtAttr The DTrace attribute (dst).
167 * @param pVtgAttr The VTG attribute descriptor (src).
168 */
169static void vboxDtVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
170{
171 pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
172 pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
173 pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
174}
175
176/**
177 * Gets a string from the string table.
178 *
179 * @returns Pointer to the string.
180 * @param pVtgHdr The VTG object header.
181 * @param offStrTab The string table offset.
182 */
183static const char *vboxDtVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
184{
185 Assert(offStrTab < pVtgHdr->cbStrTab);
186 return &pVtgHdr->pachStrTab[offStrTab];
187}
188
189
190
191/*
192 *
193 * DTrace Provider Interface.
194 * DTrace Provider Interface.
195 * DTrace Provider Interface.
196 *
197 */
198
199
200/**
201 * @callback_method_impl{dtrace_pops_t,dtps_provide}
202 */
203static void supdrvDtPOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
204{
205 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
206 AssertPtrReturnVoid(pProv);
207 LOG_DTRACE(("supdrvDtPOps_Provide: %p / %p pDtProbeDesc=%p\n", pProv, pProv->TracerData.DTrace.idProvider, pDtProbeDesc));
208 size_t const cbFnNmBuf = _4K + _1K;
209 char *pszFnNmBuf;
210 uint16_t idxProv;
211
212 if (pDtProbeDesc)
213 return; /* We don't generate probes, so never mind these requests. */
214
215 if (pProv->TracerData.DTrace.fZombie)
216 return;
217
218 dtrace_provider_id_t idProvider = pProv->TracerData.DTrace.idProvider;
219 AssertPtrReturnVoid(idProvider);
220
221 AssertPtrReturnVoid(pProv->pHdr);
222 PVTGPROBELOC pProbeLoc = pProv->pHdr->paProbLocs;
223 AssertPtrReturnVoid(pProbeLoc);
224 PVTGPROBELOC pProbeLocEnd = pProv->pHdr->paProbLocsEnd;
225 AssertPtrReturnVoid(pProbeLocEnd);
226 if (pProv->TracerData.DTrace.cProvidedProbes >= (uintptr_t)(pProbeLocEnd - pProbeLoc))
227 return;
228
229 /* Need a buffer for extracting the function names and mangling them in
230 case of collision. */
231 pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
232 if (!pszFnNmBuf)
233 return;
234
235 /*
236 * Itereate the probe location list and register all probes related to
237 * this provider.
238 */
239 idxProv = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
240 while ((uintptr_t)pProbeLoc < (uintptr_t)pProbeLocEnd)
241 {
242 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
243 if ( pProbeDesc->idxProvider == idxProv
244 && pProbeLoc->idProbe == UINT32_MAX)
245 {
246 /* The function name normally needs to be stripped since we're
247 using C++ compilers for most of the code. ASSUMES nobody are
248 brave/stupid enough to use function pointer returns without
249 typedef'ing properly them. */
250 const char *pszPrbName = vboxDtVtgGetString(pProv->pHdr, pProbeDesc->offName);
251 const char *pszFunc = pProbeLoc->pszFunction;
252 const char *psz = strchr(pProbeLoc->pszFunction, '(');
253 size_t cch;
254 if (psz)
255 {
256 /* skip blanks preceeding the parameter parenthesis. */
257 while ( (uintptr_t)psz > (uintptr_t)pProbeLoc->pszFunction
258 && RT_C_IS_BLANK(psz[-1]))
259 psz--;
260
261 /* Find the start of the function name. */
262 pszFunc = psz - 1;
263 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLoc->pszFunction)
264 {
265 char ch = pszFunc[-1];
266 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
267 break;
268 pszFunc--;
269 }
270 cch = psz - pszFunc;
271 }
272 else
273 cch = strlen(pszFunc);
274 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
275
276 /* Look up the probe, if we have one in the same function, mangle
277 the function name a little to avoid having to deal with having
278 multiple location entries with the same probe ID. (lazy bird) */
279 Assert(pProbeLoc->idProbe == UINT32_MAX);
280 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
281 {
282 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLoc->uLine);
283 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
284 {
285 unsigned iOrd = 2;
286 while (iOrd < 128)
287 {
288 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLoc->uLine, iOrd);
289 if (dtrace_probe_lookup(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
290 break;
291 iOrd++;
292 }
293 if (iOrd >= 128)
294 {
295 LogRel(("VBoxDrv: More than 128 duplicate probe location instances %s at line %u in function %s [%s], probe %s\n",
296 pProbeLoc->uLine, pProbeLoc->pszFunction, pszFnNmBuf, pszPrbName));
297 continue;
298 }
299 }
300 }
301
302 /* Create the probe. */
303 AssertCompile(sizeof(pProbeLoc->idProbe) == sizeof(dtrace_id_t));
304 pProbeLoc->idProbe = dtrace_probe_create(idProvider, pProv->pszModName, pszFnNmBuf, pszPrbName,
305 1 /*aframes*/, pProbeLoc);
306 pProv->TracerData.DTrace.cProvidedProbes++;
307 }
308
309 pProbeLoc++;
310 }
311
312 RTMemFree(pszFnNmBuf);
313 LOG_DTRACE(("supdrvDtPOps_Provide: returns\n"));
314}
315
316
317/**
318 * @callback_method_impl{dtrace_pops_t,dtps_enable}
319 */
320static int supdrvDtPOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
321{
322 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
323 AssertPtrReturn(pProv, EINVAL);
324 LOG_DTRACE(("supdrvDtPOps_Enable: %p / %p - %#x / %p\n", pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
325 AssertPtrReturn(pvProbe, EINVAL);
326 AssertPtrReturn(pProv->TracerData.DTrace.idProvider, EINVAL);
327
328 if (!pProv->TracerData.DTrace.fZombie)
329 {
330 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
331 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
332
333 if (!pProbeLoc->fEnabled)
334 {
335 pProbeLoc->fEnabled = 1;
336 if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
337 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
338 }
339 }
340
341 return 0;
342}
343
344
345/**
346 * @callback_method_impl{dtrace_pops_t,dtps_disable}
347 */
348static void supdrvDtPOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
349{
350 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
351 AssertPtrReturnVoid(pProv);
352 LOG_DTRACE(("supdrvDtPOps_Disable: %p / %p - %#x / %p\n", pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
353 AssertPtrReturnVoid(pvProbe);
354 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
355
356 if (!pProv->TracerData.DTrace.fZombie)
357 {
358 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
359 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
360 AssertPtrReturnVoid(pProbeDesc);
361
362 if (pProbeLoc->fEnabled)
363 {
364 pProbeLoc->fEnabled = 0;
365 if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
366 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 0;
367 }
368 }
369}
370
371
372/**
373 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
374 */
375static void supdrvDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
376 dtrace_argdesc_t *pArgDesc)
377{
378 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
379 unsigned uArg = pArgDesc->dtargd_ndx;
380
381 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
382 AssertPtrReturnVoid(pProv);
383 LOG_DTRACE(("supdrvDtPOps_GetArgDesc: %p / %p - %#x / %p uArg=%d\n", pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
384 AssertPtrReturnVoid(pvProbe);
385 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
386
387 if (!pProv->TracerData.DTrace.fZombie)
388 {
389 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
390 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
391 AssertPtrReturnVoid(pProbeDesc);
392 AssertPtrReturnVoid(pProv->pHdr);
393 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
394 AssertPtrReturnVoid(pArgList);
395
396 AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
397 if (uArg < pArgList->cArgs)
398 {
399 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
400 size_t cchType = strlen(pszType);
401 if (cchType < sizeof(pArgDesc->dtargd_native))
402 {
403 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
404 /** @todo mapping? */
405 pArgDesc->dtargd_ndx = uArg;
406SUPR0Printf("supdrvDtPOps_GetArgVal: returns dtargd_native = %s for #%u\n", pArgDesc->dtargd_native, uArg);
407 LOG_DTRACE(("supdrvDtPOps_GetArgVal: returns dtargd_native = %s\n", pArgDesc->dtargd_native));
408 return;
409 }
410 }
411 }
412SUPR0Printf("supdrvDtPOps_GetArgVal: returns faiure for #%u\n", uArg);
413}
414
415
416/**
417 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
418 *
419 *
420 * We just cook our own stuff here, using a stack marker for finding the
421 * required information. That's more reliable than subjecting oneself to the
422 * solaris bugs and 32-bit apple peculiarities.
423 *
424 *
425 * @remarks Solaris Bug
426 *
427 * dtrace_getarg on AMD64 has a different opinion about how to use the cFrames
428 * argument than dtrace_caller() and/or dtrace_getpcstack(), at least when the
429 * probe is fired by dtrace_probe() the way we do.
430 *
431 * Setting aframes to 1 when calling dtrace_probe_create gives me the right
432 * arguments, but the wrong 'caller'. Since I cannot do anything about
433 * 'caller', the only solution is this hack.
434 *
435 * Not sure why the Solaris guys hasn't seen this issue before, but maybe there
436 * isn't anyone using the default argument getter path for ring-0 dtrace_probe()
437 * calls, SDT surely isn't.
438 *
439 * @todo File a solaris bug on dtrace_probe() + dtrace_getarg().
440 *
441 *
442 * @remarks 32-bit XNU (Apple)
443 *
444 * The dtrace_probe arguments are 64-bit unsigned integers instead of uintptr_t,
445 * so we need to make an extra call.
446 *
447 */
448static uint64_t supdrvDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
449 int iArg, int cFrames)
450{
451 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
452 AssertPtrReturn(pProv, UINT64_MAX);
453 LOG_DTRACE(("supdrvDtPOps_GetArgVal: %p / %p - %#x / %p iArg=%d cFrames=%u\n", pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
454 AssertReturn(iArg >= 5, UINT64_MAX);
455 AssertPtrReturn(pvProbe, UINT64_MAX);
456 AssertReturn(!pProv->TracerData.DTrace.fZombie, UINT64_MAX);
457 AssertPtrReturn(pProv->TracerData.DTrace.idProvider, UINT64_MAX);
458 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
459 AssertPtrReturn(pProbeLoc, UINT64_MAX);
460 PVTGDESCPROBE pProbe = (PVTGDESCPROBE)pProbeLoc->pbProbe;
461 AssertPtrReturn(pProbe, UINT64_MAX);
462 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbe->offArgList);
463 AssertPtrReturn(pArgList, UINT64_MAX);
464
465 /* Locate the caller of probe_dtrace, . */
466 int volatile iDummy = 1; /* use this to get the stack address. */
467 PSUPDRVDTSTACKDATA pData = (PSUPDRVDTSTACKDATA)( ((uintptr_t)&iDummy + SUPDRVDT_STACK_DATA_ALIGN - 1)
468 & ~(uintptr_t)(SUPDRVDT_STACK_DATA_ALIGN - 1));
469 for (;;)
470 {
471 if ( pData->u32Magic1 == SUPDRVDT_STACK_DATA_MAGIC1
472 && pData->u32Magic2 == SUPDRVDT_STACK_DATA_MAGIC2
473 && pData->pSelf == pData)
474 break;
475 pData = (PSUPDRVDTSTACKDATA)((uintptr_t)pData + SUPDRVDT_STACK_DATA_ALIGN);
476 }
477
478 /*
479 * Get the stack data. This is a wee bit complicated on 32-bit systems
480 * since we want to support 64-bit integer arguments.
481 */
482#if ARCH_BITS == 64
483 uint64_t u64Ret = pData->pauStackArgs[iArg - 5];
484#else
485 uint64_t u64Ret;
486 if ( !pArgList->fHaveLargeArgs
487 || pArgList->cArgs <= iArg)
488 u64Ret = pData->pauStackArgs[iArg - 5];
489 else
490 {
491 /* Similar to what we did for mac in when calling dtrace_probe(). */
492 uint32_t off = 0;
493 for (int i = 5; i < iArg; i++)
494 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
495 off++;
496 u64Ret = pData->pauStackArgs[iArg - 5 + off];
497 if ( (pArgList->aArgs[iArg].fType & VTG_TYPE_FIXED_SIZED)
498 && (pArgList->aArgs[iArg].fType & VTG_TYPE_SIZE_MASK) == 8 )
499 u64Ret |= (uint64_t)pData->pauStackArgs[iArg - 5 + off + 1] << 32;
500 }
501#endif
502
503 LOG_DTRACE(("supdrvDtPOps_GetArgVal: returns %#llx\n", u64Ret));
504 return u64Ret;
505}
506
507
508/**
509 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
510 */
511static void supdrvDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
512{
513 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
514 AssertPtrReturnVoid(pProv);
515 LOG_DTRACE(("supdrvDtPOps_Destroy: %p / %p - %#x / %p\n", pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
516 AssertReturnVoid(pProv->TracerData.DTrace.cProvidedProbes > 0);
517 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
518
519 if (!pProv->TracerData.DTrace.fZombie)
520 {
521 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
522 AssertPtrReturnVoid(pProbeLoc);
523 AssertPtrReturnVoid(pProbeLoc->pszFunction);
524 Assert(!pProbeLoc->fEnabled);
525 AssertReturnVoid(pProbeLoc->idProbe == idProbe);
526
527 pProbeLoc->idProbe = UINT32_MAX;
528 }
529 pProv->TracerData.DTrace.cProvidedProbes--;
530}
531
532
533
534/**
535 * DTrace provider method table.
536 */
537static const dtrace_pops_t g_vboxDtVtgProvOps =
538{
539 /* .dtps_provide = */ supdrvDtPOps_Provide,
540 /* .dtps_provide_module = */ NULL,
541 /* .dtps_enable = */ (FNPOPS_ENABLE *)supdrvDtPOps_Enable,
542 /* .dtps_disable = */ supdrvDtPOps_Disable,
543 /* .dtps_suspend = */ NULL,
544 /* .dtps_resume = */ NULL,
545 /* .dtps_getargdesc = */ supdrvDtPOps_GetArgDesc,
546 /* .dtps_getargval = */ supdrvDtPOps_GetArgVal,
547 /* .dtps_usermode = */ NULL,
548 /* .dtps_destroy = */ supdrvDtPOps_Destroy
549};
550
551
552
553
554/*
555 *
556 * Support Driver Tracer Interface.
557 * Support Driver Tracer Interface.
558 * Support Driver Tracer Interface.
559 *
560 */
561
562
563
564/**
565 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
566 */
567static DECLCALLBACK(void) supdrvDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
568 uintptr_t uArg3, uintptr_t uArg4)
569{
570 AssertPtrReturnVoid(pVtgProbeLoc);
571 LOG_DTRACE(("supdrvDtTOps_ProbeFireKernel: %p / %p\n", pVtgProbeLoc, pVtgProbeLoc->idProbe));
572 AssertPtrReturnVoid(pVtgProbeLoc->pbProbe);
573 AssertPtrReturnVoid(pVtgProbeLoc->pszFunction);
574
575 SUPDRVDT_SETUP_STACK_DATA();
576
577 pStackData->pauStackArgs = &uArg4 + 1;
578
579#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
580 /*
581 * Convert arguments from uintptr_t to uint64_t.
582 */
583 PVTGDESCPROBE pProbe = (PVTGDESCPROBE)((PVTGPROBELOC)pVtgProbeLoc)->pbProbe;
584 AssertPtrReturnVoid(pProbe);
585 PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)((uintptr_t)pProbe + pProbe->offObjHdr);
586 AssertPtrReturnVoid(pVtgHdr);
587 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr->paArgLists + pProbe->offArgList);
588 AssertPtrReturnVoid(pArgList);
589 if (!pArgList->fHaveLargeArgs)
590 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
591 else
592 {
593 uintptr_t *auSrcArgs = &uArg0;
594 uint32_t iSrcArg = 0;
595 uint32_t iDstArg = 0;
596 uint64_t au64DstArgs[5];
597
598 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
599 && iSrcArg < pArgList->cArgs)
600 {
601 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
602 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
603 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
604 iSrcArg++;
605 iDstArg++;
606 }
607 while (iDstArg < RT_ELEMENTS(au64DstArgs))
608 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
609
610 pStackData->pauStackArgs = &auSrcArgs[iSrcArg];
611 dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
612 }
613#else
614 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
615#endif
616
617 SUPDRVDT_CLEAR_STACK_DATA();
618 LOG_DTRACE(("supdrvDtTOps_ProbeFireKernel: returns\n"));
619}
620
621
622/**
623 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
624 */
625static DECLCALLBACK(void) supdrvDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx)
626{
627 NOREF(pThis); NOREF(pSession); NOREF(pCtx);
628 return;
629}
630
631
632/**
633 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
634 */
635static DECLCALLBACK(int) supdrvDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
636 uintptr_t uArg, uintptr_t *puSessionData)
637{
638 NOREF(pThis); NOREF(pSession); NOREF(uCookie); NOREF(uArg);
639 *puSessionData = 0;
640 return VERR_NOT_SUPPORTED;
641}
642
643
644/**
645 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
646 */
647static DECLCALLBACK(int) supdrvDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
648 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
649{
650 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
651 NOREF(uCmd); NOREF(uArg); NOREF(piRetVal);
652 return VERR_NOT_SUPPORTED;
653}
654
655
656/**
657 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
658 */
659static DECLCALLBACK(void) supdrvDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
660{
661 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
662 return;
663}
664
665
666/**
667 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
668 */
669static DECLCALLBACK(int) supdrvDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
670{
671 LOG_DTRACE(("supdrvDtTOps_ProviderRegister: %p %s/%s\n", pThis, pCore->pszModName, pCore->pszName));
672 AssertReturn(pCore->TracerData.DTrace.idProvider == UINT32_MAX || pCore->TracerData.DTrace.idProvider == 0,
673 VERR_INTERNAL_ERROR_3);
674
675 PVTGDESCPROVIDER pDesc = pCore->pDesc;
676 dtrace_pattr_t DtAttrs;
677 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
678 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
679 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
680 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
681 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
682
683 /* Note! DTrace may call us back before dtrace_register returns, so we
684 have to point it to pCore->TracerData.DTrace.idProvider. */
685 int rc = dtrace_register(pCore->pszName,
686 &DtAttrs,
687 DTRACE_PRIV_KERNEL,
688 NULL /* cred */,
689 &g_vboxDtVtgProvOps,
690 pCore,
691 &pCore->TracerData.DTrace.idProvider);
692 LOG_DTRACE(("supdrvDtTOps_ProviderRegister: idProvider=%p\n", pCore->TracerData.DTrace.idProvider));
693 if (!rc)
694 {
695 Assert(pCore->TracerData.DTrace.idProvider != UINT32_MAX && pCore->TracerData.DTrace.idProvider != 0);
696 AssertPtr(pCore->TracerData.DTrace.idProvider);
697 rc = VINF_SUCCESS;
698 }
699 else
700 {
701 pCore->TracerData.DTrace.idProvider = UINT32_MAX;
702 rc = RTErrConvertFromErrno(rc);
703 }
704
705 LOG_DTRACE(("supdrvDtTOps_ProviderRegister: returns %Rrc\n", rc));
706 return rc;
707}
708
709
710/**
711 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
712 */
713static DECLCALLBACK(int) supdrvDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
714{
715 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
716 LOG_DTRACE(("supdrvDtTOps_ProviderDeregister: %p / %p\n", pThis, idProvider));
717 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
718 AssertReturn(idProvider != UINT32_MAX && idProvider != 0, VERR_INTERNAL_ERROR_4);
719
720 dtrace_invalidate(idProvider);
721 int rc = dtrace_unregister(idProvider);
722 if (!rc)
723 {
724 pCore->TracerData.DTrace.idProvider = UINT32_MAX;
725 rc = VINF_SUCCESS;
726 }
727 else
728 {
729 AssertMsg(rc == EBUSY, ("%d\n", rc));
730 pCore->TracerData.DTrace.fZombie = true;
731 rc = VERR_TRY_AGAIN;
732 }
733
734 LOG_DTRACE(("supdrvDtTOps_ProviderDeregister: returns %Rrc\n", rc));
735 return rc;
736}
737
738
739/**
740 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
741 */
742static DECLCALLBACK(int) supdrvDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
743{
744 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
745 LOG_DTRACE(("supdrvDtTOps_ProviderDeregisterZombie: %p / %p\n", pThis, idProvider));
746 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
747 AssertReturn(idProvider != UINT32_MAX && idProvider != 0, VERR_INTERNAL_ERROR_4);
748 Assert(pCore->TracerData.DTrace.fZombie);
749
750 int rc = dtrace_unregister(idProvider);
751 if (!rc)
752 {
753 pCore->TracerData.DTrace.idProvider = UINT32_MAX;
754 rc = VINF_SUCCESS;
755 }
756 else
757 {
758 AssertMsg(rc == EBUSY, ("%d\n", rc));
759 rc = VERR_TRY_AGAIN;
760 }
761
762 LOG_DTRACE(("supdrvDtTOps_ProviderDeregisterZombie: returns %Rrc\n", rc));
763 return rc;
764}
765
766
767
768/**
769 * The tracer registration record of the VBox DTrace implementation
770 */
771static SUPDRVTRACERREG g_supdrvDTraceReg =
772{
773 SUPDRVTRACERREG_MAGIC,
774 SUPDRVTRACERREG_VERSION,
775 supdrvDtTOps_ProbeFireKernel,
776 supdrvDtTOps_ProbeFireUser,
777 supdrvDtTOps_TracerOpen,
778 supdrvDtTOps_TracerIoCtl,
779 supdrvDtTOps_TracerClose,
780 supdrvDtTOps_ProviderRegister,
781 supdrvDtTOps_ProviderDeregister,
782 supdrvDtTOps_ProviderDeregisterZombie,
783 SUPDRVTRACERREG_MAGIC
784};
785
786
787
788/**
789 * Module initialization code.
790 *
791 * @param hMod Opque module handle.
792 */
793const SUPDRVTRACERREG * VBOXCALL supdrvDTraceInit(void)
794{
795#ifdef RT_OS_DARWIN
796 /*
797 * Resolve the kernel symbols we need.
798 */
799 RTDBGKRNLINFO hKrnlInfo;
800 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
801 if (RT_FAILURE(rc))
802 {
803 SUPR0Printf("supdrvDTraceInit: RTR0DbgKrnlInfoOpen failed with rc=%d.\n", rc);
804 return NULL;
805 }
806
807 static const struct
808 {
809 const char *pszName;
810 PFNRT *ppfn;
811 } s_aDTraceFunctions[] =
812 {
813 { "dtrace_probe", (PFNRT*)&dtrace_probe },
814 { "dtrace_probe_create", (PFNRT*)&dtrace_probe_create },
815 { "dtrace_probe_lookup", (PFNRT*)&dtrace_probe_lookup },
816 { "dtrace_register", (PFNRT*)&dtrace_register },
817 { "dtrace_invalidate", (PFNRT*)&dtrace_invalidate },
818 { "dtrace_unregister", (PFNRT*)&dtrace_unregister },
819 };
820 for (unsigned i = 0; i < RT_ELEMENTS(s_aDTraceFunctions); i++)
821 {
822 rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, s_aDTraceFunctions[i].pszName,
823 (void **)s_aDTraceFunctions[i].ppfn);
824 if (RT_FAILURE(rc))
825 {
826 SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (rc=%Rrc, i=%u).\n", s_aDTraceFunctions[i].pszName, rc, i);
827 break;
828 }
829 }
830
831 RTR0DbgKrnlInfoRelease(hKrnlInfo);
832 if (RT_FAILURE(rc))
833 return NULL;
834#endif
835
836 return &g_supdrvDTraceReg;
837}
838
839#ifndef VBOX_WITH_NATIVE_DTRACE
840# error "VBOX_WITH_NATIVE_DTRACE is not defined as it should"
841#endif
842
Note: See TracBrowser for help on using the repository browser.

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