VirtualBox

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

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

SUPDrv-dtrace.cpp: Made it build again.

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