VirtualBox

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

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

SUPDrv-dtrace.cpp: Check dtrace_unregister return code, introducing zombie provider list for dealing with failure.

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