VirtualBox

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

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

Implemented VMMR0 static DTrace probes.

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