VirtualBox

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

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

SUPDrv: tracing bugfixes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.6 KB
Line 
1/* $Id: SUPDrv-dtrace.cpp 41133 2012-05-03 13:19:10Z 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(pProv->TracerData.DTrace.idProvider);
425
426 if (!pProv->TracerData.DTrace.fZombie)
427 {
428 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
429 PVTGPROBELOC32 pProbeLocEn = (PVTGPROBELOC32)( (uintptr_t)pProv->pvProbeLocsEn + idxProbeLoc * pProv->cbProbeLocsEn);
430 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
431 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
432 uint32_t const idxProbe = pProbeDesc->idxEnabled;
433
434 if (!pProv->fUmod)
435 {
436 if (pProbeLocEn->fEnabled)
437 {
438 pProbeLocEn->fEnabled = 0;
439 ASMAtomicDecU32(&pProv->pacProbeEnabled[idxProbe]);
440 }
441 }
442 else
443 {
444 /* Update kernel mode structure */
445 if (pProv->paR0ProbeLocs[idxProbeLoc].fEnabled)
446 {
447 pProv->paR0ProbeLocs[idxProbeLoc].fEnabled = 0;
448 ASMAtomicDecU32(&pProv->paR0Probes[idxProbe].cEnabled);
449 }
450
451 /* Update user mode structure. */
452 pProbeLocEn->fEnabled = 0;
453 pProv->pacProbeEnabled[idxProbe] = pProv->paR0Probes[idxProbe].cEnabled;
454 }
455 }
456}
457
458
459/**
460 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
461 */
462static void vboxDtPOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
463 dtrace_argdesc_t *pArgDesc)
464{
465 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
466 unsigned uArg = pArgDesc->dtargd_ndx;
467
468 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
469 AssertPtrReturnVoid(pProv);
470 LOG_DTRACE(("%s: %p / %p - %#x / %p uArg=%d\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, uArg));
471 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
472
473 if (!pProv->TracerData.DTrace.fZombie)
474 {
475 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
476 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
477 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
478 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
479 + pProv->pHdr->offArgLists
480 + pProbeDesc->offArgList);
481 AssertReturnVoid(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
482
483 if (uArg < pArgList->cArgs)
484 {
485 const char *pszType = vboxDtVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
486 size_t cchType = strlen(pszType);
487 if (cchType < sizeof(pArgDesc->dtargd_native))
488 {
489 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
490 /** @todo mapping? */
491 pArgDesc->dtargd_ndx = uArg;
492 LOG_DTRACE(("%s: returns dtargd_native = %s\n", __FUNCTION__, pArgDesc->dtargd_native));
493 return;
494 }
495 }
496 }
497}
498
499
500/**
501 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
502 *
503 *
504 * We just cook our own stuff here, using a stack marker for finding the
505 * required information. That's more reliable than subjecting oneself to the
506 * solaris bugs and 32-bit apple peculiarities.
507 *
508 *
509 * @remarks Solaris Bug
510 *
511 * dtrace_getarg on AMD64 has a different opinion about how to use the cFrames
512 * argument than dtrace_caller() and/or dtrace_getpcstack(), at least when the
513 * probe is fired by dtrace_probe() the way we do.
514 *
515 * Setting aframes to 1 when calling dtrace_probe_create gives me the right
516 * arguments, but the wrong 'caller'. Since I cannot do anything about
517 * 'caller', the only solution is this hack.
518 *
519 * Not sure why the Solaris guys hasn't seen this issue before, but maybe there
520 * isn't anyone using the default argument getter path for ring-0 dtrace_probe()
521 * calls, SDT surely isn't.
522 *
523 * @todo File a solaris bug on dtrace_probe() + dtrace_getarg().
524 *
525 *
526 * @remarks 32-bit XNU (Apple)
527 *
528 * The dtrace_probe arguments are 64-bit unsigned integers instead of uintptr_t,
529 * so we need to make an extra call.
530 *
531 */
532static uint64_t vboxDtPOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
533 int iArg, int cFrames)
534{
535 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
536 AssertPtrReturn(pProv, UINT64_MAX);
537 LOG_DTRACE(("%s: %p / %p - %#x / %p iArg=%d cFrames=%u\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe, iArg, cFrames));
538 AssertReturn(iArg >= 5, UINT64_MAX);
539 if (pProv->TracerData.DTrace.fZombie)
540 return UINT64_MAX;
541
542 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
543 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
544 PCVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
545 PCVTGDESCARGLIST pArgList = (PCVTGDESCARGLIST)( (uintptr_t)pProv->pHdr
546 + pProv->pHdr->offArgLists
547 + pProbeDesc->offArgList);
548 AssertReturn(pProbeDesc->offArgList < pProv->pHdr->cbArgLists, UINT64_MAX);
549
550 PVBDTSTACKDATA pData = vboxDtGetStackData();
551
552 /*
553 * Get the stack data. This is a wee bit complicated on 32-bit systems
554 * since we want to support 64-bit integer arguments.
555 */
556 uint64_t u64Ret;
557 if (iArg >= 20)
558 u64Ret = UINT64_MAX;
559 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireKernel)
560 {
561#if ARCH_BITS == 64
562 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
563#else
564 if ( !pArgList->fHaveLargeArgs
565 || iArg >= pArgList->cArgs)
566 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5];
567 else
568 {
569 /* Similar to what we did for mac in when calling dtrace_probe(). */
570 uint32_t offArg = 0;
571 for (int i = 5; i < iArg; i++)
572 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
573 offArg++;
574 u64Ret = pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg];
575 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
576 u64Ret |= (uint64_t)pData->u.ProbeFireKernel.pauStackArgs[iArg - 5 + offArg + 1] << 32;
577 }
578#endif
579 }
580 else if (pData->enmCaller == kVBoxDtCaller_ProbeFireUser)
581 {
582 int offArg = pData->u.ProbeFireUser.offArg;
583 PCSUPDRVTRACERUSRCTX pCtx = pData->u.ProbeFireUser.pCtx;
584 AssertPtrReturn(pCtx, UINT64_MAX);
585
586 if (pCtx->cBits == 32)
587 {
588 if ( !pArgList->fHaveLargeArgs
589 || iArg >= pArgList->cArgs)
590 {
591 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
592 u64Ret = pCtx->u.Amd64.aArgs[iArg + offArg];
593 else
594 u64Ret = UINT64_MAX;
595 }
596 else
597 {
598 for (int i = 5; i < iArg; i++)
599 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
600 offArg++;
601 if (offArg + iArg < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
602 {
603 u64Ret = pCtx->u.X86.aArgs[iArg + offArg];
604 if ( VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType)
605 && offArg + iArg + 1 < (int)RT_ELEMENTS(pCtx->u.X86.aArgs))
606 u64Ret |= (uint64_t)pCtx->u.X86.aArgs[iArg + offArg + 1] << 32;
607 }
608 else
609 u64Ret = UINT64_MAX;
610 }
611 }
612 else
613 {
614 if (iArg + offArg < (int)RT_ELEMENTS(pCtx->u.Amd64.aArgs))
615 u64Ret = pCtx->u.Amd64.aArgs[iArg + offArg];
616 else
617 u64Ret = UINT64_MAX;
618 }
619 }
620 else
621 AssertFailedReturn(UINT64_MAX);
622
623 LOG_DTRACE(("%s: returns %#llx\n", __FUNCTION__, u64Ret));
624 return u64Ret;
625}
626
627
628/**
629 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
630 */
631static void vboxDtPOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
632{
633 PSUPDRVVDTPROVIDERCORE pProv = (PSUPDRVVDTPROVIDERCORE)pvProv;
634 AssertPtrReturnVoid(pProv);
635 LOG_DTRACE(("%s: %p / %p - %#x / %p\n", __FUNCTION__, pProv, pProv->TracerData.DTrace.idProvider, idProbe, pvProbe));
636 AssertReturnVoid(pProv->TracerData.DTrace.cProvidedProbes > 0);
637 AssertPtrReturnVoid(pProv->TracerData.DTrace.idProvider);
638
639 if (!pProv->TracerData.DTrace.fZombie)
640 {
641 uint32_t idxProbeLoc = (uint32_t)(uintptr_t)pvProbe;
642 PCVTGPROBELOC pProbeLocRO = (PVTGPROBELOC)&pProv->paProbeLocsRO[idxProbeLoc];
643 uint32_t *pidProbe;
644 if (!pProv->fUmod)
645 {
646 pidProbe = (uint32_t *)&pProbeLocRO->idProbe;
647 Assert(!pProbeLocRO->fEnabled);
648 Assert(*pidProbe == idProbe);
649 }
650 else
651 {
652 pidProbe = &pProv->paR0ProbeLocs[idxProbeLoc].idProbe;
653 Assert(!pProv->paR0ProbeLocs[idxProbeLoc].fEnabled);
654 Assert(*pidProbe == idProbe); NOREF(idProbe);
655 }
656 *pidProbe = 0;
657 }
658 pProv->TracerData.DTrace.cProvidedProbes--;
659}
660
661
662
663/**
664 * DTrace provider method table.
665 */
666static const dtrace_pops_t g_vboxDtVtgProvOps =
667{
668 /* .dtps_provide = */ vboxDtPOps_Provide,
669 /* .dtps_provide_module = */ NULL,
670 /* .dtps_enable = */ (FNPOPS_ENABLE *)vboxDtPOps_Enable,
671 /* .dtps_disable = */ vboxDtPOps_Disable,
672 /* .dtps_suspend = */ NULL,
673 /* .dtps_resume = */ NULL,
674 /* .dtps_getargdesc = */ vboxDtPOps_GetArgDesc,
675 /* .dtps_getargval = */ vboxDtPOps_GetArgVal,
676 /* .dtps_usermode = */ NULL,
677 /* .dtps_destroy = */ vboxDtPOps_Destroy
678};
679
680
681
682
683/*
684 *
685 * Support Driver Tracer Interface.
686 * Support Driver Tracer Interface.
687 * Support Driver Tracer Interface.
688 *
689 */
690
691
692
693/**
694 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireKernel}
695 */
696static DECLCALLBACK(void) vboxDtTOps_ProbeFireKernel(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
697 uintptr_t uArg3, uintptr_t uArg4)
698{
699 AssertPtrReturnVoid(pVtgProbeLoc);
700 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pVtgProbeLoc, pVtgProbeLoc->idProbe));
701 AssertPtrReturnVoid(pVtgProbeLoc->pProbe);
702 AssertPtrReturnVoid(pVtgProbeLoc->pszFunction);
703
704 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireKernel);
705
706 pStackData->u.ProbeFireKernel.pauStackArgs = &uArg4 + 1;
707
708#if defined(RT_OS_DARWIN) && ARCH_BITS == 32
709 /*
710 * Convert arguments from uintptr_t to uint64_t.
711 */
712 PVTGDESCPROBE pProbe = (PVTGDESCPROBE)((PVTGPROBELOC)pVtgProbeLoc)->pbProbe;
713 AssertPtrReturnVoid(pProbe);
714 PVTGOBJHDR pVtgHdr = (PVTGOBJHDR)((uintptr_t)pProbe + pProbe->offObjHdr);
715 AssertPtrReturnVoid(pVtgHdr);
716 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbe->offArgList);
717 AssertPtrReturnVoid(pArgList);
718 if (!pArgList->fHaveLargeArgs)
719 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
720 else
721 {
722 uintptr_t *auSrcArgs = &uArg0;
723 uint32_t iSrcArg = 0;
724 uint32_t iDstArg = 0;
725 uint64_t au64DstArgs[5];
726
727 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
728 && iSrcArg < pArgList->cArgs)
729 {
730 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
731 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
732 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
733 iSrcArg++;
734 iDstArg++;
735 }
736 while (iDstArg < RT_ELEMENTS(au64DstArgs))
737 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
738
739 pStackData->u.ProbeFireK.pauStackArgs = &auSrcArgs[iSrcArg];
740 dtrace_probe(pVtgProbeLoc->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
741 }
742#else
743 dtrace_probe(pVtgProbeLoc->idProbe, uArg0, uArg1, uArg2, uArg3, uArg4);
744#endif
745
746 VBDT_CLEAR_STACK_DATA();
747 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
748}
749
750
751/**
752 * interface_method_impl{SUPDRVTRACERREG,pfnProbeFireUser}
753 */
754static DECLCALLBACK(void) vboxDtTOps_ProbeFireUser(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx,
755 PCVTGOBJHDR pVtgHdr, PCVTGPROBELOC pProbeLocRO)
756{
757 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pCtx, pCtx->idProbe));
758 AssertPtrReturnVoid(pProbeLocRO);
759 AssertPtrReturnVoid(pVtgHdr);
760
761 VBDT_SETUP_STACK_DATA(kVBoxDtCaller_ProbeFireUser);
762
763 if (pCtx->cBits == 32)
764 {
765 pStackData->u.ProbeFireUser.pCtx = pCtx;
766 pStackData->u.ProbeFireUser.offArg = 0;
767
768#if ARCH_BITS == 64 || defined(RT_OS_DARWIN)
769 /*
770 * Combine two 32-bit arguments into one 64-bit argument where needed.
771 */
772 PVTGDESCPROBE pProbeDesc = pProbeLocRO->pProbe;
773 AssertPtrReturnVoid(pProbeDesc);
774 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr + pVtgHdr->offArgLists + pProbeDesc->offArgList);
775 AssertPtrReturnVoid(pArgList);
776
777 if (!pArgList->fHaveLargeArgs)
778 dtrace_probe(pCtx->idProbe,
779 pCtx->u.X86.aArgs[0],
780 pCtx->u.X86.aArgs[1],
781 pCtx->u.X86.aArgs[2],
782 pCtx->u.X86.aArgs[3],
783 pCtx->u.X86.aArgs[4]);
784 else
785 {
786 uint32_t const *auSrcArgs = &pCtx->u.X86.aArgs[0];
787 uint32_t iSrcArg = 0;
788 uint32_t iDstArg = 0;
789 uint64_t au64DstArgs[5];
790
791 while ( iDstArg < RT_ELEMENTS(au64DstArgs)
792 && iSrcArg < pArgList->cArgs)
793 {
794 au64DstArgs[iDstArg] = auSrcArgs[iSrcArg];
795 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iDstArg].fType))
796 au64DstArgs[iDstArg] |= (uint64_t)auSrcArgs[++iSrcArg] << 32;
797 iSrcArg++;
798 iDstArg++;
799 }
800 while (iDstArg < RT_ELEMENTS(au64DstArgs))
801 au64DstArgs[iDstArg++] = auSrcArgs[iSrcArg++];
802
803 pStackData->u.ProbeFireUser.offArg = iSrcArg - RT_ELEMENTS(au64DstArgs);
804 dtrace_probe(pCtx->idProbe, au64DstArgs[0], au64DstArgs[1], au64DstArgs[2], au64DstArgs[3], au64DstArgs[4]);
805 }
806#else
807 dtrace_probe(pCtx->idProbe,
808 pCtx->u.X86.aArgs[0],
809 pCtx->u.X86.aArgs[1],
810 pCtx->u.X86.aArgs[2],
811 pCtx->u.X86.aArgs[3],
812 pCtx->u.X86.aArgs[4]);
813#endif
814 }
815 else if (pCtx->cBits == 64)
816 {
817 pStackData->u.ProbeFireUser.pCtx = pCtx;
818 pStackData->u.ProbeFireUser.offArg = 0;
819 dtrace_probe(pCtx->idProbe,
820 pCtx->u.Amd64.aArgs[0],
821 pCtx->u.Amd64.aArgs[1],
822 pCtx->u.Amd64.aArgs[2],
823 pCtx->u.Amd64.aArgs[3],
824 pCtx->u.Amd64.aArgs[4]);
825 }
826 else
827 AssertFailed();
828
829 VBDT_CLEAR_STACK_DATA();
830 LOG_DTRACE(("%s: returns\n", __FUNCTION__));
831}
832
833
834/**
835 * interface_method_impl{SUPDRVTRACERREG,pfnTracerOpen}
836 */
837static DECLCALLBACK(int) vboxDtTOps_TracerOpen(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie,
838 uintptr_t uArg, uintptr_t *puSessionData)
839{
840 NOREF(pThis); NOREF(pSession); NOREF(uCookie); NOREF(uArg);
841 *puSessionData = 0;
842 return VERR_NOT_SUPPORTED;
843}
844
845
846/**
847 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
848 */
849static DECLCALLBACK(int) vboxDtTOps_TracerIoCtl(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData,
850 uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
851{
852 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
853 NOREF(uCmd); NOREF(uArg); NOREF(piRetVal);
854 return VERR_NOT_SUPPORTED;
855}
856
857
858/**
859 * interface_method_impl{SUPDRVTRACERREG,pfnTracerClose}
860 */
861static DECLCALLBACK(void) vboxDtTOps_TracerClose(PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)
862{
863 NOREF(pThis); NOREF(pSession); NOREF(uSessionData);
864 return;
865}
866
867
868/**
869 * interface_method_impl{SUPDRVTRACERREG,pfnProviderRegister}
870 */
871static DECLCALLBACK(int) vboxDtTOps_ProviderRegister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
872{
873 LOG_DTRACE(("%s: %p %s/%s\n", __FUNCTION__, pThis, pCore->pszModName, pCore->pszName));
874 AssertReturn(pCore->TracerData.DTrace.idProvider == 0, VERR_INTERNAL_ERROR_3);
875
876 PVTGDESCPROVIDER pDesc = pCore->pDesc;
877 dtrace_pattr_t DtAttrs;
878 vboxDtVtgConvAttr(&DtAttrs.dtpa_provider, &pDesc->AttrSelf);
879 vboxDtVtgConvAttr(&DtAttrs.dtpa_mod, &pDesc->AttrModules);
880 vboxDtVtgConvAttr(&DtAttrs.dtpa_func, &pDesc->AttrFunctions);
881 vboxDtVtgConvAttr(&DtAttrs.dtpa_name, &pDesc->AttrNames);
882 vboxDtVtgConvAttr(&DtAttrs.dtpa_args, &pDesc->AttrArguments);
883
884 /* Note! DTrace may call us back before dtrace_register returns, so we
885 have to point it to pCore->TracerData.DTrace.idProvider. */
886 AssertCompile(sizeof(dtrace_provider_id_t) == sizeof(pCore->TracerData.DTrace.idProvider));
887 int rc = dtrace_register(pCore->pszName,
888 &DtAttrs,
889 DTRACE_PRIV_KERNEL,
890 NULL /* cred */,
891 &g_vboxDtVtgProvOps,
892 pCore,
893 &pCore->TracerData.DTrace.idProvider);
894 if (!rc)
895 {
896 LOG_DTRACE(("%s: idProvider=%p\n", __FUNCTION__, pCore->TracerData.DTrace.idProvider));
897 AssertPtr(pCore->TracerData.DTrace.idProvider);
898 rc = VINF_SUCCESS;
899 }
900 else
901 {
902 pCore->TracerData.DTrace.idProvider = 0;
903 rc = RTErrConvertFromErrno(rc);
904 }
905
906 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
907 return rc;
908}
909
910
911/**
912 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregister}
913 */
914static DECLCALLBACK(int) vboxDtTOps_ProviderDeregister(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
915{
916 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
917 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
918 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
919
920 dtrace_invalidate(idProvider);
921 int rc = dtrace_unregister(idProvider);
922 if (!rc)
923 {
924 pCore->TracerData.DTrace.idProvider = 0;
925 rc = VINF_SUCCESS;
926 }
927 else
928 {
929 AssertMsg(rc == EBUSY, ("%d\n", rc));
930 pCore->TracerData.DTrace.fZombie = true;
931 rc = VERR_TRY_AGAIN;
932 }
933
934 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
935 return rc;
936}
937
938
939/**
940 * interface_method_impl{SUPDRVTRACERREG,pfnProviderDeregisterZombie}
941 */
942static DECLCALLBACK(int) vboxDtTOps_ProviderDeregisterZombie(PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)
943{
944 uintptr_t idProvider = pCore->TracerData.DTrace.idProvider;
945 LOG_DTRACE(("%s: %p / %p\n", __FUNCTION__, pThis, idProvider));
946 AssertPtrReturn(idProvider, VERR_INTERNAL_ERROR_3);
947 Assert(pCore->TracerData.DTrace.fZombie);
948
949 int rc = dtrace_unregister(idProvider);
950 if (!rc)
951 {
952 pCore->TracerData.DTrace.idProvider = 0;
953 rc = VINF_SUCCESS;
954 }
955 else
956 {
957 AssertMsg(rc == EBUSY, ("%d\n", rc));
958 rc = VERR_TRY_AGAIN;
959 }
960
961 LOG_DTRACE(("%s: returns %Rrc\n", __FUNCTION__, rc));
962 return rc;
963}
964
965
966
967/**
968 * The tracer registration record of the VBox DTrace implementation
969 */
970static SUPDRVTRACERREG g_VBoxDTraceReg =
971{
972 SUPDRVTRACERREG_MAGIC,
973 SUPDRVTRACERREG_VERSION,
974 vboxDtTOps_ProbeFireKernel,
975 vboxDtTOps_ProbeFireUser,
976 vboxDtTOps_TracerOpen,
977 vboxDtTOps_TracerIoCtl,
978 vboxDtTOps_TracerClose,
979 vboxDtTOps_ProviderRegister,
980 vboxDtTOps_ProviderDeregister,
981 vboxDtTOps_ProviderDeregisterZombie,
982 SUPDRVTRACERREG_MAGIC
983};
984
985
986
987/**
988 * Module initialization code.
989 *
990 * @param hMod Opque module handle.
991 */
992const SUPDRVTRACERREG * VBOXCALL supdrvDTraceInit(void)
993{
994#ifdef RT_OS_DARWIN
995 /*
996 * Resolve the kernel symbols we need.
997 */
998 RTDBGKRNLINFO hKrnlInfo;
999 int rc = RTR0DbgKrnlInfoOpen(&hKrnlInfo, 0);
1000 if (RT_FAILURE(rc))
1001 {
1002 SUPR0Printf("supdrvDTraceInit: RTR0DbgKrnlInfoOpen failed with rc=%d.\n", rc);
1003 return NULL;
1004 }
1005
1006 static const struct
1007 {
1008 const char *pszName;
1009 PFNRT *ppfn;
1010 } s_aDTraceFunctions[] =
1011 {
1012 { "dtrace_probe", (PFNRT*)&dtrace_probe },
1013 { "dtrace_probe_create", (PFNRT*)&dtrace_probe_create },
1014 { "dtrace_probe_lookup", (PFNRT*)&dtrace_probe_lookup },
1015 { "dtrace_register", (PFNRT*)&dtrace_register },
1016 { "dtrace_invalidate", (PFNRT*)&dtrace_invalidate },
1017 { "dtrace_unregister", (PFNRT*)&dtrace_unregister },
1018 };
1019 for (unsigned i = 0; i < RT_ELEMENTS(s_aDTraceFunctions); i++)
1020 {
1021 rc = RTR0DbgKrnlInfoQuerySymbol(hKrnlInfo, NULL, s_aDTraceFunctions[i].pszName,
1022 (void **)s_aDTraceFunctions[i].ppfn);
1023 if (RT_FAILURE(rc))
1024 {
1025 SUPR0Printf("supdrvDTraceInit: Failed to resolved '%s' (rc=%Rrc, i=%u).\n", s_aDTraceFunctions[i].pszName, rc, i);
1026 break;
1027 }
1028 }
1029
1030 RTR0DbgKrnlInfoRelease(hKrnlInfo);
1031 if (RT_FAILURE(rc))
1032 return NULL;
1033#endif
1034
1035 return &g_VBoxDTraceReg;
1036}
1037
1038#ifndef VBOX_WITH_NATIVE_DTRACE
1039# error "VBOX_WITH_NATIVE_DTRACE is not defined as it should"
1040#endif
1041
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