VirtualBox

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

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

64-bit probe arguments (on mac)

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