VirtualBox

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

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

VBoxDrv: Finished probe creation code.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 30.4 KB
Line 
1/* $Id: SUPDrv-dtrace.cpp 40605 2012-03-24 21:05:30Z 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/list.h>
41#include <iprt/mem.h>
42#include <iprt/semaphore.h>
43
44#ifdef RT_OS_DARWIN /** @todo figure this! */
45# include "/Developer/SDKs/MacOSX10.6.sdk/usr/include/sys/dtrace.h"
46#else
47# include <sys/dtrace.h>
48#endif
49
50
51/*******************************************************************************
52* Structures and Typedefs *
53*******************************************************************************/
54/**
55 * Data for a provider.
56 */
57typedef struct SUPDRVDTPROVIDER
58{
59 /** The entry in the provider list for this image. */
60 RTLISTNODE ListEntry;
61
62 /** The provider descriptor. */
63 PVTGDESCPROVIDER pDesc;
64 /** The VTG header. */
65 PVTGOBJHDR pHdr;
66
67 /** Pointer to the image this provider resides in. NULL if it's a
68 * driver. */
69 PSUPDRVLDRIMAGE pImage;
70 /** The session this provider is associated with if registered via
71 * SUPR0VtgRegisterDrv. NULL if pImage is set. */
72 PSUPDRVSESSION pSession;
73 /** The module name. */
74 const char *pszModName;
75
76 /** Dtrace provider attributes. */
77 dtrace_pattr_t DtAttrs;
78 /** The ID of this provider. */
79 dtrace_provider_id_t idDtProv;
80} SUPDRVDTPROVIDER;
81/** Pointer to the data for a provider. */
82typedef SUPDRVDTPROVIDER *PSUPDRVDTPROVIDER;
83
84/* Seems there is some return code difference here. Keep the return code and
85 case it to whatever the host desires. */
86#ifdef RT_OS_DARWIN
87typedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
88#else
89typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
90#endif
91
92
93/*******************************************************************************
94* Internal Functions *
95*******************************************************************************/
96static void supdrvDTracePOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc);
97static int supdrvDTracePOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
98static void supdrvDTracePOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
99static void supdrvDTracePOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
100 dtrace_argdesc_t *pArgDesc);
101/*static uint64_t supdrvDTracePOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
102 int iArg, int cFrames);*/
103static void supdrvDTracePOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
104
105
106
107/*******************************************************************************
108* Global Variables *
109*******************************************************************************/
110/** The default provider attributes. */
111static dtrace_pattr_t g_DefProvAttrs =
112{ /* .dtat_name, .dtat_data, .dtat_class */
113 /* .dtpa_provider = */ { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA },
114 /* .dtpa_mod = */ { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA },
115 /* .dtpa_func = */ { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA },
116 /* .dtpa_name = */ { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA },
117 /* .dtpa_args = */ { DTRACE_STABILITY_UNSTABLE, DTRACE_STABILITY_UNSTABLE, DTRACE_CLASS_ISA },
118};
119
120/**
121 * DTrace provider method table.
122 */
123static const dtrace_pops_t g_SupDrvDTraceProvOps =
124{
125 /* .dtps_provide = */ supdrvDTracePOps_Provide,
126 /* .dtps_provide_module = */ NULL,
127 /* .dtps_enable = */ (FNPOPS_ENABLE *)supdrvDTracePOps_Enable,
128 /* .dtps_disable = */ supdrvDTracePOps_Disable,
129 /* .dtps_suspend = */ NULL,
130 /* .dtps_resume = */ NULL,
131 /* .dtps_getargdesc = */ supdrvDTracePOps_GetArgDesc,
132 /* .dtps_getargval = */ NULL/*supdrvDTracePOps_GetArgVal*/,
133 /* .dtps_usermode = */ NULL,
134 /* .dtps_destroy = */ supdrvDTracePOps_Destroy
135};
136
137
138#define VERR_SUPDRV_VTG_MAGIC (-3704)
139#define VERR_SUPDRV_VTG_BITS (-3705)
140//#define VERR_SUPDRV_VTG_RESERVED (-3705)
141#define VERR_SUPDRV_VTG_BAD_HDR (-3706)
142#define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3706)
143#define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3707)
144#define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3708)
145#define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3709)
146#define VERR_SUPDRV_VTG_STRTAB_OFF (-3709)
147#define VERR_SUPDRV_VTG_BAD_STRING (-1111)
148#define VERR_SUPDRV_VTG_STRING_TOO_LONG (-1111)
149#define VERR_SUPDRV_VTG_BAD_ATTR (-1111)
150#define VERR_SUPDRV_VTG_BAD_PROVIDER (-1111)
151#define VERR_SUPDRV_VTG_BAD_PROBE (-1111)
152#define VERR_SUPDRV_VTG_BAD_ARGLIST (-3709)
153#define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-1111)
154#define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3709)
155#define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-1111)
156#define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-1111)
157
158
159static int supdrvVtgValidateString(const char *psz)
160{
161 size_t off = 0;
162 while (off < _4K)
163 {
164 char const ch = psz[off++];
165 if (!ch)
166 return VINF_SUCCESS;
167 if ( !RTLocCIsAlNum(ch)
168 && ch != ' '
169 && ch != '('
170 && ch != ')'
171 && ch != ','
172 && ch != '*'
173 && ch != '&'
174 )
175 return VERR_SUPDRV_VTG_BAD_STRING;
176 }
177 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
178}
179
180/**
181 * Validates the VTG data.
182 *
183 * @returns VBox status code.
184 * @param pVtgHdr The VTG object header of the data to validate.
185 * @param cbVtgObj The size of the VTG object.
186 * @param pbImage The image base. For validating the probe
187 * locations.
188 * @param cbImage The image size to go with @a pbImage.
189 */
190static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
191{
192 uintptr_t cbTmp;
193 uintptr_t offTmp;
194 uintptr_t i;
195 int rc;
196 uint32_t cProviders;
197
198 if (!pbImage || !cbImage)
199 {
200 pbImage = NULL;
201 cbImage = 0;
202 }
203
204#define MY_VALIDATE_PTR(p, cb, cMin, cMax, cbUnit, rcBase) \
205 do { \
206 if ( (cb) >= cbVtgObj \
207 || (uintptr_t)(p) - (uintptr_t)pVtgHdr < cbVtgObj - (cb) ) \
208 return rcBase ## _PTR; \
209 if ((cb) < (cMin) * (cbUnit)) \
210 return rcBase ## _TOO_FEW; \
211 if ((cb) >= (cMax) * (cbUnit)) \
212 return rcBase ## _TOO_MUCH; \
213 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
214 return rcBase ## _NOT_MULTIPLE; \
215 } while (0)
216#define MY_WITHIN_IMAGE(p, rc) \
217 do { \
218 if (pbImage) \
219 { \
220 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
221 return (rc); \
222 } \
223 else if (!RT_VALID_PTR(p)) \
224 return (rc); \
225 } while (0)
226#define MY_VALIDATE_STR(offStrTab) \
227 do { \
228 if ((offStrTab) >= pVtgHdr->cbStrTab) \
229 return VERR_SUPDRV_VTG_STRTAB_OFF; \
230 rc = supdrvVtgValidateString(pVtgHdr->pachStrTab + (offStrTab)); \
231 if (rc != VINF_SUCCESS) \
232 return rc; \
233 } while (0)
234#define MY_VALIDATE_ATTR(Attr) \
235 do { \
236 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
237 return VERR_SUPDRV_VTG_BAD_ATTR; \
238 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
239 return VERR_SUPDRV_VTG_BAD_ATTR; \
240 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
241 return VERR_SUPDRV_VTG_BAD_ATTR; \
242 } while (0)
243
244 /*
245 * The header.
246 */
247 if (!memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
248 return VERR_SUPDRV_VTG_MAGIC;
249 if (pVtgHdr->cBits != ARCH_BITS)
250 return VERR_SUPDRV_VTG_BITS;
251 if (pVtgHdr->u32Reserved0)
252 return VERR_SUPDRV_VTG_BAD_HDR;
253
254 MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
255 MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
256 MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
257 MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
258 MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
259 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs, VERR_SUPDRV_VTG_BAD_HDR_PTR);
260 MY_WITHIN_IMAGE(pVtgHdr->paProbLocsEnd, VERR_SUPDRV_VTG_BAD_HDR_PTR);
261 if ((uintptr_t)pVtgHdr->paProbLocs > (uintptr_t)pVtgHdr->paProbLocsEnd)
262 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
263 cbTmp = (uintptr_t)pVtgHdr->paProbLocsEnd - (uintptr_t)pVtgHdr->paProbLocs;
264 MY_VALIDATE_PTR(pVtgHdr->paProbLocs, cbTmp, 1, _128K, sizeof(VTGPROBELOC), VERR_SUPDRV_VTG_BAD_HDR);
265 if (cbTmp < sizeof(VTGPROBELOC))
266 return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
267
268 if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled)
269 return VERR_SUPDRV_VTG_BAD_HDR;
270
271 /*
272 * Validate the providers.
273 */
274 cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
275 while (i-- > 0)
276 {
277 MY_VALIDATE_STR(pVtgHdr->paProviders[i].offName);
278 if (pVtgHdr->paProviders[i].iFirstProbe >= pVtgHdr->cbProbeEnabled)
279 return VERR_SUPDRV_VTG_BAD_PROVIDER;
280 if (pVtgHdr->paProviders[i].iFirstProbe + pVtgHdr->paProviders[i].cProbes > pVtgHdr->cbProbeEnabled)
281 return VERR_SUPDRV_VTG_BAD_PROVIDER;
282 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrSelf);
283 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrModules);
284 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrFunctions);
285 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrNames);
286 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrArguments);
287 if (pVtgHdr->paProviders[i].bReserved)
288 return VERR_SUPDRV_VTG_BAD_PROVIDER;
289 }
290
291 /*
292 * Validate probes.
293 */
294 i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
295 while (i-- > 0)
296 {
297 PVTGDESCARGLIST pArgList;
298 unsigned iArg;
299
300 MY_VALIDATE_STR(pVtgHdr->paProbes[i].offName);
301 if (pVtgHdr->paProbes[i].offArgList >= pVtgHdr->cbArgLists)
302 return VERR_SUPDRV_VTG_BAD_PROBE;
303 if (pVtgHdr->paProbes[i].offArgList & 3)
304 return VERR_SUPDRV_VTG_BAD_PROBE;
305 if (pVtgHdr->paProbes[i].idxEnabled != i) /* The lists are parallel. */
306 return VERR_SUPDRV_VTG_BAD_PROBE;
307 if (pVtgHdr->paProbes[i].idxProvider >= cProviders)
308 return VERR_SUPDRV_VTG_BAD_PROBE;
309 if ( i - pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].iFirstProbe
310 < pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].cProbes)
311 return VERR_SUPDRV_VTG_BAD_PROBE;
312 if (pVtgHdr->paProbes[i].u32User)
313 return VERR_SUPDRV_VTG_BAD_PROBE;
314
315 /* The referenced argument list. */
316 pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr->paArgLists + pVtgHdr->paProbes[i].offArgList);
317 if (pArgList->cArgs > 16)
318 return VERR_SUPDRV_VTG_BAD_ARGLIST;
319 if ( pArgList->abReserved[0]
320 || pArgList->abReserved[1]
321 || pArgList->abReserved[2])
322 return VERR_SUPDRV_VTG_BAD_ARGLIST;
323 iArg = pArgList->cArgs;
324 while (iArg-- > 0)
325 {
326 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
327 MY_VALIDATE_STR(pArgList->aArgs[iArg].offName);
328 }
329 }
330
331 /*
332 * Check that pafProbeEnabled is all zero.
333 */
334 i = pVtgHdr->cbProbeEnabled;
335 while (i-- > 0)
336 if (pVtgHdr->pafProbeEnabled[0])
337 return VERR_SUPDRV_VTG_BAD_PROBE_ENABLED;
338
339 /*
340 * Probe locations.
341 */
342 i = pVtgHdr->paProbLocsEnd - pVtgHdr->paProbLocs;
343 while (i-- > 0)
344 {
345 if (pVtgHdr->paProbLocs[i].uLine >= _1G)
346 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
347 if (pVtgHdr->paProbLocs[i].fEnabled)
348 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
349 if (pVtgHdr->paProbLocs[i].idProbe != UINT32_MAX)
350 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
351 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
352 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFile, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
353 offTmp = (uintptr_t)pVtgHdr->paProbLocs[i].pbProbe - (uintptr_t)pVtgHdr->paProbes;
354 if (offTmp >= pVtgHdr->cbProbes)
355 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
356 if (offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) != offTmp)
357 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
358 }
359
360 return VINF_SUCCESS;
361#undef MY_VALIDATE_STR
362#undef MY_VALIDATE_PTR
363#undef MY_WITHIN_IMAGE
364}
365
366
367/**
368 * Converts an attribute from VTG description speak to DTrace.
369 *
370 * @param pDtAttr The DTrace attribute (dst).
371 * @param pVtgAttr The VTG attribute descriptor (src).
372 */
373static void supdrvVtgConvAttr(dtrace_attribute_t *pDtAttr, PCVTGDESCATTR pVtgAttr)
374{
375 pDtAttr->dtat_name = pVtgAttr->u8Code - 1;
376 pDtAttr->dtat_data = pVtgAttr->u8Data - 1;
377 pDtAttr->dtat_class = pVtgAttr->u8DataDep - 1;
378}
379
380/**
381 * Gets a string from the string table.
382 *
383 * @returns Pointer to the string.
384 * @param pVtgHdr The VTG object header.
385 * @param offStrTab The string table offset.
386 */
387static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
388{
389 Assert(offStrTab < pVtgHdr->cbStrTab);
390 return &pVtgHdr->pachStrTab[offStrTab];
391}
392
393
394/**
395 * Registers the VTG tracepoint providers of a driver.
396 *
397 * @returns VBox status code.
398 * @param pszName The driver name.
399 * @param pVtgHdr The VTG object header.
400 * @param pVtgObj The size of the VTG object.
401 * @param pImage The image if applicable.
402 * @param pSession The session if applicable.
403 * @param pszModName The module name.
404 */
405static int supdrvVtgRegister(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage, PSUPDRVSESSION pSession,
406 const char *pszModName)
407{
408 int rc;
409 unsigned i;
410 PSUPDRVDTPROVIDER pProv;
411
412 /*
413 * Validate input.
414 */
415 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
416 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
417 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
418 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
419 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
420
421 if (pImage)
422 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
423 else
424 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
425 if (RT_FAILURE(rc))
426 return rc;
427
428 rc = RTSemFastMutexRequest(pDevExt->mtxDTrace);
429 if (RT_SUCCESS(rc))
430 {
431 RTListForEach(&pDevExt->DtProviderList, pProv, SUPDRVDTPROVIDER, ListEntry)
432 {
433 if (pProv->pHdr == pVtgHdr)
434 {
435 RTSemFastMutexRelease(pDevExt->mtxDTrace);
436 return VERR_SUPDRV_VTG_ALREADY_REGISTERED;
437 }
438 if (pProv->pSession == pSession && !pProv->pImage)
439 {
440 RTSemFastMutexRelease(pDevExt->mtxDTrace);
441 return VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
442 }
443 }
444 RTSemFastMutexRelease(pDevExt->mtxDTrace);
445 }
446
447 /*
448 * Register the providers.
449 */
450 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
451 while (i-- > 0)
452 {
453 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
454 pProv = (PSUPDRVDTPROVIDER)RTMemAllocZ(sizeof(*pProv));
455 if (pProv)
456 {
457 pProv->pDesc = pDesc;
458 pProv->pHdr = pVtgHdr;
459 pProv->pImage = pImage;
460 pProv->pSession = pSession;
461 pProv->pszModName = pszModName;
462 pProv->idDtProv = 0;
463 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_provider, &pDesc->AttrSelf);
464 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_mod, &pDesc->AttrModules);
465 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_func, &pDesc->AttrFunctions);
466 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_name, &pDesc->AttrNames);
467 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_args, &pDesc->AttrArguments);
468
469 rc = dtrace_register(supdrvVtgGetString(pVtgHdr, pDesc->offName),
470 &pProv->DtAttrs,
471 DTRACE_PRIV_KERNEL,
472 NULL /* cred */,
473 &g_SupDrvDTraceProvOps,
474 pProv,
475 &pProv->idDtProv);
476 if (!rc)
477 {
478 rc = RTSemFastMutexRequest(pDevExt->mtxDTrace);
479 if (RT_SUCCESS(rc))
480 {
481 RTListAppend(&pDevExt->DtProviderList, &pProv->ListEntry);
482 RTSemFastMutexRelease(pDevExt->mtxDTrace);
483 }
484 else
485 dtrace_unregister(pProv->idDtProv);
486 }
487 else
488 rc = RTErrConvertFromErrno(rc);
489 }
490 else
491 rc = VERR_NO_MEMORY;
492
493 if (RT_FAILURE(rc))
494 {
495 PSUPDRVDTPROVIDER pProvNext;
496 RTMemFree(pProv);
497
498 RTSemFastMutexRequest(pDevExt->mtxDTrace);
499 RTListForEachReverseSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
500 {
501 if (pProv->pHdr == pVtgHdr)
502 {
503 RTListNodeRemove(&pProv->ListEntry);
504 RTSemFastMutexRelease(pDevExt->mtxDTrace);
505
506 dtrace_unregister(pProv->idDtProv);
507 RTMemFree(pProv);
508
509 RTSemFastMutexRequest(pDevExt->mtxDTrace);
510 }
511 }
512 RTSemFastMutexRelease(pDevExt->mtxDTrace);
513 return rc;
514 }
515 }
516
517 return VINF_SUCCESS;
518}
519
520
521
522/**
523 * Registers the VTG tracepoint providers of a driver.
524 *
525 * @returns VBox status code.
526 * @param pSession The support driver session handle.
527 * @param pVtgHdr The VTG header.
528 * @param pszName The driver name.
529 */
530SUPR0DECL(int) SUPR0VtgRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
531{
532 AssertReturn(SUP_IS_SESSION_VALID(pSession), NULL);
533 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
534 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
535
536 return supdrvVtgRegister(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
537}
538
539
540
541/**
542 * Deregister the VTG tracepoint providers of a driver.
543 *
544 * @param pSession The support driver session handle.
545 * @param pVtgHdr The VTG header.
546 */
547SUPR0DECL(void) SUPR0VtgDeregisterDrv(PSUPDRVSESSION pSession)
548{
549 PSUPDRVDTPROVIDER pProv, pProvNext;
550 PSUPDRVDEVEXT pDevExt;
551 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
552
553 pDevExt = pSession->pDevExt;
554 RTSemFastMutexRequest(pDevExt->mtxDTrace);
555 RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
556 {
557 if (pProv->pSession == pSession)
558 {
559 RTListNodeRemove(&pProv->ListEntry);
560 RTSemFastMutexRelease(pDevExt->mtxDTrace);
561
562 dtrace_unregister(pProv->idDtProv);
563 RTMemFree(pProv);
564
565 RTSemFastMutexRequest(pDevExt->mtxDTrace);
566 }
567 }
568 RTSemFastMutexRelease(pDevExt->mtxDTrace);
569}
570
571
572
573/**
574 * Early module initialization hook.
575 *
576 * @returns VBox status code.
577 * @param pDevExt The device extension structure.
578 */
579int supdrvDTraceInit(PSUPDRVDEVEXT pDevExt)
580{
581 /*
582 * Register a provider for this module.
583 */
584 int rc = RTSemFastMutexCreate(&pDevExt->mtxDTrace);
585 if (RT_SUCCESS(rc))
586 {
587 RTListInit(&pDevExt->DtProviderList);
588 rc = supdrvVtgRegister(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
589 if (RT_SUCCESS(rc))
590 return rc;
591 RTSemFastMutexDestroy(pDevExt->mtxDTrace);
592 }
593 pDevExt->mtxDTrace = NIL_RTSEMFASTMUTEX;
594 return rc;
595}
596
597
598/**
599 * Late module termination hook.
600 *
601 * @returns VBox status code.
602 * @param pDevExt The device extension structure.
603 */
604int supdrvDTraceTerm(PSUPDRVDEVEXT pDevExt)
605{
606 PSUPDRVDTPROVIDER pProv, pProvNext;
607
608 /*
609 * Unregister all probes (there should only be one).
610 */
611 RTSemFastMutexRequest(pDevExt->mtxDTrace);
612 RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
613 {
614 RTListNodeRemove(&pProv->ListEntry);
615 RTSemFastMutexRelease(pDevExt->mtxDTrace);
616
617 dtrace_unregister(pProv->idDtProv);
618 RTMemFree(pProv);
619
620 RTSemFastMutexRequest(pDevExt->mtxDTrace);
621 }
622 RTSemFastMutexRelease(pDevExt->mtxDTrace);
623 RTSemFastMutexDestroy(pDevExt->mtxDTrace);
624 pDevExt->mtxDTrace = NIL_RTSEMFASTMUTEX;
625 return VINF_SUCCESS;
626}
627
628
629/**
630 * Module loading hook, called before calling into the module.
631 *
632 * @returns VBox status code.
633 * @param pDevExt The device extension structure.
634 */
635int supdrvDTraceModuleLoading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
636{
637 /*
638 * Check for DTrace probes in the module, register a new provider for them
639 * if found.
640 */
641
642 return VINF_SUCCESS;
643}
644
645
646/**
647 * Module unloading hook, called after execution in the module
648 * have ceased.
649 *
650 * @returns VBox status code.
651 * @param pDevExt The device extension structure.
652 */
653int supdrvDTraceModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
654{
655 /*
656 * Undo what we did in supdrvDTraceModuleLoading.
657 */
658 return VINF_SUCCESS;
659}
660
661
662/**
663 * @callback_method_impl{dtrace_pops_t,dtps_provide}
664 */
665static void supdrvDTracePOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
666{
667 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
668 uint16_t const idxProv = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
669 PVTGPROBELOC pProbeLoc;
670 PVTGPROBELOC pProbeLocEnd;
671 char *pszFnNmBuf;
672 size_t const cbFnNmBuf = _4K + _1K;
673
674 if (pDtProbeDesc)
675 return; /* We don't generate probes, so never mind these requests. */
676
677 /* Need a buffer for extracting the function names and mangling them in
678 case of collision. */
679 pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
680 if (!pszFnNmBuf)
681 return;
682
683 /*
684 * Itereate the probe location list and register all probes related to
685 * this provider.
686 */
687 pProbeLoc = pProv->pHdr->paProbLocs;
688 pProbeLocEnd = pProv->pHdr->paProbLocsEnd;
689 while ((uintptr_t)pProbeLoc < (uintptr_t)pProbeLocEnd)
690 {
691 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
692 if (pProbeDesc->idxProvider == idxProv)
693 {
694 /* The function name normally needs to be stripped since we're
695 using C++ compilers for most of the code. ASSUMES nobody are
696 brave/stupid enough to use function pointer returns without
697 typedef'ing properly them. */
698 const char *pszPrbName = supdrvVtgGetString(pProv->pHdr, pProbeDesc->offName);
699 const char *pszFunc = pProbeLoc->pszFunction;
700 const char *psz = strchr(pProbeLoc->pszFunction, '(');
701 size_t cch;
702 if (psz)
703 {
704 /* skip blanks preceeding the parameter parenthesis. */
705 while ( (uintptr_t)psz > (uintptr_t)pProbeLoc->pszFunction
706 && RT_C_IS_BLANK(psz[-1]))
707 psz--;
708
709 /* Find the start of the function name. */
710 pszFunc = psz - 1;
711 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLoc->pszFunction)
712 {
713 char ch = pszFunc[-1];
714 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
715 break;
716 pszFunc--;
717 }
718 cch = psz - pszFunc;
719 }
720 else
721 cch = strlen(pszFunc);
722 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
723
724 /* Look up the probe, if we have one in the same function, mangle
725 the function name a little to avoid having to deal with having
726 multiple location entries with the same probe ID. (lazy bird) */
727 Assert(pProbeLoc->idProbe == UINT32_MAX);
728 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
729 {
730 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLoc->uLine);
731 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
732 {
733 unsigned iOrd = 2;
734 while (iOrd < 128)
735 {
736 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLoc->uLine, iOrd);
737 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
738 break;
739 iOrd++;
740 }
741 if (iOrd >= 128)
742 {
743 LogRel(("VBoxDrv: More than 128 duplicate probe location instances in file %s at line %u, function %s [%s], probe %s\n",
744 pProbeLoc->pszFile, pProbeLoc->uLine, pProbeLoc->pszFunction, pszFnNmBuf, pszPrbName));
745 continue;
746 }
747 }
748 }
749
750 /* Create the probe. */
751 AssertCompile(sizeof(pProbeLoc->idProbe) == sizeof(dtrace_id_t));
752 pProbeLoc->idProbe = dtrace_probe_create(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName,
753 0 /*aframes*/, pProbeLoc);
754 }
755
756 pProbeLoc++;
757 }
758
759 RTMemFree(pszFnNmBuf);
760}
761
762
763/**
764 * @callback_method_impl{dtrace_pops_t,dtps_enable}
765 */
766static int supdrvDTracePOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
767{
768 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
769 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
770
771 if (!pProbeLoc->fEnabled)
772 {
773 pProbeLoc->fEnabled = 1;
774 if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
775 pProbeLoc->fEnabled = 1;
776 }
777
778 NOREF(pvProv);
779 return 0;
780}
781
782
783/**
784 * @callback_method_impl{dtrace_pops_t,dtps_disable}
785 */
786static void supdrvDTracePOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
787{
788 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
789 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
790
791 if (pProbeLoc->fEnabled)
792 {
793 pProbeLoc->fEnabled = 0;
794 if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
795 pProbeLoc->fEnabled = 0;
796 }
797
798 NOREF(pvProv);
799}
800
801
802/**
803 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
804 */
805static void supdrvDTracePOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
806 dtrace_argdesc_t *pArgDesc)
807{
808 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
809 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
810 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
811 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
812
813 Assert(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
814 if (pArgList->cArgs > pArgDesc->dtargd_ndx)
815 {
816 const char *pszType = supdrvVtgGetString(pProv->pHdr, pArgList->aArgs[pArgDesc->dtargd_ndx].offType);
817 size_t cchType = strlen(pszType);
818 if (cchType < sizeof(pArgDesc->dtargd_native))
819 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
820 else
821 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
822 }
823 else
824 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
825}
826
827
828#if 0
829/**
830 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
831 */
832static uint64_t supdrvDTracePOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
833 int iArg, int cFrames)
834{
835 return 0xbeef;
836}
837#endif
838
839
840/**
841 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
842 */
843static void supdrvDTracePOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
844{
845 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
846
847 Assert(!pProbeLoc->fEnabled);
848 Assert(pProbeLoc->idProbe == idProbe); NOREF(idProbe);
849 pProbeLoc->idProbe = UINT32_MAX;
850
851 NOREF(pvProv);
852}
853
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