VirtualBox

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

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

SUPDrv-dtrace.cpp: bugfixes and working around solaris bugs.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 36.5 KB
Line 
1/* $Id: SUPDrv-dtrace.cpp 40704 2012-03-28 19:29:49Z 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 /** The provider name (for logging purposes). */
86 char szName[1];
87} SUPDRVDTPROVIDER;
88/** Pointer to the data for a provider. */
89typedef SUPDRVDTPROVIDER *PSUPDRVDTPROVIDER;
90
91/* Seems there is some return code difference here. Keep the return code and
92 case it to whatever the host desires. */
93#ifdef RT_OS_DARWIN
94typedef void FNPOPS_ENABLE(void *, dtrace_id_t, void *);
95#else
96typedef int FNPOPS_ENABLE(void *, dtrace_id_t, void *);
97#endif
98
99
100/*******************************************************************************
101* Defined Constants And Macros *
102*******************************************************************************/
103#if 0
104# define LOG_DTRACE(a_Args) SUPR0Printf a_Args
105#else
106# define LOG_DTRACE(a_Args) do { } while (0)
107#endif
108
109/*******************************************************************************
110* Internal Functions *
111*******************************************************************************/
112static void supdrvDTracePOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc);
113static int supdrvDTracePOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
114static void supdrvDTracePOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
115static void supdrvDTracePOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
116 dtrace_argdesc_t *pArgDesc);
117#ifdef RT_OS_SOLARIS
118static uint64_t supdrvDTracePOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
119 int iArg, int cFrames);
120#endif
121static void supdrvDTracePOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe);
122
123
124
125/*******************************************************************************
126* Global Variables *
127*******************************************************************************/
128/**
129 * DTrace provider method table.
130 */
131static const dtrace_pops_t g_SupDrvDTraceProvOps =
132{
133 /* .dtps_provide = */ supdrvDTracePOps_Provide,
134 /* .dtps_provide_module = */ NULL,
135 /* .dtps_enable = */ (FNPOPS_ENABLE *)supdrvDTracePOps_Enable,
136 /* .dtps_disable = */ supdrvDTracePOps_Disable,
137 /* .dtps_suspend = */ NULL,
138 /* .dtps_resume = */ NULL,
139 /* .dtps_getargdesc = */ supdrvDTracePOps_GetArgDesc,
140#ifdef RT_OS_SOLARIS
141 /* .dtps_getargval = */ supdrvDTracePOps_GetArgVal,
142#else
143 /* .dtps_getargval = */ NULL/*supdrvDTracePOps_GetArgVal*/,
144#endif
145 /* .dtps_usermode = */ NULL,
146 /* .dtps_destroy = */ supdrvDTracePOps_Destroy
147};
148
149
150static int supdrvVtgValidateString(const char *psz)
151{
152 size_t off = 0;
153 while (off < _4K)
154 {
155 char const ch = psz[off++];
156 if (!ch)
157 return VINF_SUCCESS;
158 if ( !RTLocCIsAlNum(ch)
159 && ch != ' '
160 && ch != '_'
161 && ch != '-'
162 && ch != '('
163 && ch != ')'
164 && ch != ','
165 && ch != '*'
166 && ch != '&'
167 )
168 {
169 /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
170 return VERR_SUPDRV_VTG_BAD_STRING;
171 }
172 }
173 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
174}
175
176/**
177 * Validates the VTG data.
178 *
179 * @returns VBox status code.
180 * @param pVtgHdr The VTG object header of the data to validate.
181 * @param cbVtgObj The size of the VTG object.
182 * @param pbImage The image base. For validating the probe
183 * locations.
184 * @param cbImage The image size to go with @a pbImage.
185 */
186static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
187{
188 uintptr_t cbTmp;
189 uintptr_t offTmp;
190 uintptr_t i;
191 int rc;
192 uint32_t cProviders;
193
194 if (!pbImage || !cbImage)
195 {
196 pbImage = NULL;
197 cbImage = 0;
198 }
199
200#define MY_VALIDATE_PTR(p, cb, cMin, cMax, cbUnit, rcBase) \
201 do { \
202 if ( (cb) >= cbVtgObj \
203 || (uintptr_t)(p) - (uintptr_t)pVtgHdr > cbVtgObj - (cb) ) \
204 return rcBase ## _PTR; \
205 if ((cb) < (cMin) * (cbUnit)) \
206 return rcBase ## _TOO_FEW; \
207 if ((cb) >= (cMax) * (cbUnit)) \
208 return rcBase ## _TOO_MUCH; \
209 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
210 return rcBase ## _NOT_MULTIPLE; \
211 } while (0)
212#define MY_WITHIN_IMAGE(p, rc) \
213 do { \
214 if (pbImage) \
215 { \
216 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
217 return (rc); \
218 } \
219 else if (!RT_VALID_PTR(p)) \
220 return (rc); \
221 } while (0)
222#define MY_VALIDATE_STR(offStrTab) \
223 do { \
224 if ((offStrTab) >= pVtgHdr->cbStrTab) \
225 return VERR_SUPDRV_VTG_STRTAB_OFF; \
226 rc = supdrvVtgValidateString(pVtgHdr->pachStrTab + (offStrTab)); \
227 if (rc != VINF_SUCCESS) \
228 return rc; \
229 } while (0)
230#define MY_VALIDATE_ATTR(Attr) \
231 do { \
232 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
233 return VERR_SUPDRV_VTG_BAD_ATTR; \
234 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
235 return VERR_SUPDRV_VTG_BAD_ATTR; \
236 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
237 return VERR_SUPDRV_VTG_BAD_ATTR; \
238 } while (0)
239
240 /*
241 * The header.
242 */
243 if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
244 return VERR_SUPDRV_VTG_MAGIC;
245 if (pVtgHdr->cBits != ARCH_BITS)
246 return VERR_SUPDRV_VTG_BITS;
247 if (pVtgHdr->u32Reserved0)
248 return VERR_SUPDRV_VTG_BAD_HDR;
249
250 MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
251 MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
252 MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
253 MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
254 MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
255
256 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs, VERR_SUPDRV_VTG_BAD_HDR_PTR);
257 MY_WITHIN_IMAGE(pVtgHdr->paProbLocsEnd, VERR_SUPDRV_VTG_BAD_HDR_PTR);
258 if ((uintptr_t)pVtgHdr->paProbLocs > (uintptr_t)pVtgHdr->paProbLocsEnd)
259 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
260 cbTmp = (uintptr_t)pVtgHdr->paProbLocsEnd - (uintptr_t)pVtgHdr->paProbLocs;
261 if (cbTmp < sizeof(VTGPROBELOC))
262 return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
263 if (cbTmp >= _128K * sizeof(VTGPROBELOC))
264 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
265 if (cbTmp / sizeof(VTGPROBELOC) * sizeof(VTGPROBELOC) != cbTmp)
266 return VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE;
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 * Frees the provider structure and associated resources.
396 *
397 * @param pProv The provider to free.
398 */
399static void supdrvVtgFreeProvider(PSUPDRVDTPROVIDER pProv)
400{
401 LOG_DTRACE(("Freeing DTrace provider '%s' / %p\n", pProv->szName, pProv->idDtProv));
402 pProv->fZombie = true;
403 pProv->pDesc = NULL;
404 pProv->pHdr = NULL;
405 RTMemFree(pProv);
406}
407
408
409/**
410 * Deregisters a provider.
411 *
412 * If the provider is still busy, it will be put in the zombie list.
413 *
414 * @param pDevExt The device extension.
415 * @param pProv The provider.
416 *
417 * @remarks The caller owns mtxDTrace.
418 */
419static void supdrvVtgDeregister(PSUPDRVDEVEXT pDevExt, PSUPDRVDTPROVIDER pProv)
420{
421 int rc;
422
423 dtrace_invalidate(pProv->idDtProv);
424 rc = dtrace_unregister(pProv->idDtProv);
425 if (!rc)
426 {
427 supdrvVtgFreeProvider(pProv);
428 return;
429 }
430
431 pProv->fZombie = true;
432 RTListAppend(&pDevExt->DtProviderZombieList, &pProv->ListEntry);
433 LOG_DTRACE(("Invalidate DTrace provider '%s' / %p and put it on the zombie list\n", pProv->szName, pProv->idDtProv));
434}
435
436
437/**
438 * Processes the zombie list.
439 *
440 * @param pDevExt The device extension.
441 */
442static void supdrvVtgProcessZombies(PSUPDRVDEVEXT pDevExt)
443{
444 PSUPDRVDTPROVIDER pProv, pProvNext;
445
446 RTSemFastMutexRequest(pDevExt->mtxDTrace);
447 RTListForEachSafe(&pDevExt->DtProviderZombieList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
448 {
449 int rc = dtrace_unregister(pProv->idDtProv);
450 if (!rc)
451 {
452 RTListNodeRemove(&pProv->ListEntry);
453 supdrvVtgFreeProvider(pProv);
454 }
455 }
456 RTSemFastMutexRelease(pDevExt->mtxDTrace);
457}
458
459
460/**
461 * Registers the VTG tracepoint providers of a driver.
462 *
463 * @returns VBox status code.
464 * @param pszName The driver name.
465 * @param pVtgHdr The VTG object header.
466 * @param pVtgObj The size of the VTG object.
467 * @param pImage The image if applicable.
468 * @param pSession The session if applicable.
469 * @param pszModName The module name.
470 */
471static int supdrvVtgRegister(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
472 PSUPDRVSESSION pSession, const char *pszModName)
473{
474 int rc;
475 unsigned i;
476 PSUPDRVDTPROVIDER pProv;
477
478 /*
479 * Validate input.
480 */
481 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
482 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
483 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
484 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
485 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
486
487 if (pImage)
488 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
489 else
490 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
491 if (RT_FAILURE(rc))
492 return rc;
493
494 rc = RTSemFastMutexRequest(pDevExt->mtxDTrace);
495 if (RT_FAILURE(rc))
496 return rc;
497 RTListForEach(&pDevExt->DtProviderList, pProv, SUPDRVDTPROVIDER, ListEntry)
498 {
499 if (pProv->pHdr == pVtgHdr)
500 {
501 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
502 break;
503 }
504 if ( pProv->pSession == pSession
505 && pProv->pImage == pImage)
506 {
507 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
508 break;
509 }
510 }
511 RTSemFastMutexRelease(pDevExt->mtxDTrace);
512 if (RT_FAILURE(rc))
513 return rc;
514
515 /*
516 * Register the providers.
517 */
518 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
519 while (i-- > 0)
520 {
521 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
522 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
523 size_t const cchName = strlen(pszName);
524 pProv = (PSUPDRVDTPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVDTPROVIDER, szName[cchName + 1]));
525 if (pProv)
526 {
527 pProv->pDesc = pDesc;
528 pProv->pHdr = pVtgHdr;
529 pProv->pImage = pImage;
530 pProv->pSession = pSession;
531 pProv->pszModName = pszModName;
532 pProv->idDtProv = 0;
533 pProv->cProvidedProbes = 0;
534 pProv->fZombie = false;
535 memcpy(pProv->szName, pszName, cchName + 1);
536 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_provider, &pDesc->AttrSelf);
537 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_mod, &pDesc->AttrModules);
538 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_func, &pDesc->AttrFunctions);
539 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_name, &pDesc->AttrNames);
540 supdrvVtgConvAttr(&pProv->DtAttrs.dtpa_args, &pDesc->AttrArguments);
541
542 rc = dtrace_register(pProv->szName,
543 &pProv->DtAttrs,
544 DTRACE_PRIV_KERNEL,
545 NULL /* cred */,
546 &g_SupDrvDTraceProvOps,
547 pProv,
548 &pProv->idDtProv);
549 if (!rc)
550 {
551 rc = RTSemFastMutexRequest(pDevExt->mtxDTrace);
552 if (RT_SUCCESS(rc))
553 {
554 RTListAppend(&pDevExt->DtProviderList, &pProv->ListEntry);
555 RTSemFastMutexRelease(pDevExt->mtxDTrace);
556 LOG_DTRACE(("Registered DTrace provider '%s' in '%s' -> %p\n", pProv->szName, pszModName, pProv->idDtProv));
557 }
558 else
559 dtrace_unregister(pProv->idDtProv);
560 }
561 else
562 rc = RTErrConvertFromErrno(rc);
563 }
564 else
565 rc = VERR_NO_MEMORY;
566
567 if (RT_FAILURE(rc))
568 {
569 PSUPDRVDTPROVIDER pProvNext;
570 supdrvVtgFreeProvider(pProv);
571
572 RTSemFastMutexRequest(pDevExt->mtxDTrace);
573 RTListForEachReverseSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
574 {
575 if (pProv->pHdr == pVtgHdr)
576 {
577 RTListNodeRemove(&pProv->ListEntry);
578 supdrvVtgDeregister(pDevExt, pProv);
579 }
580 }
581 RTSemFastMutexRelease(pDevExt->mtxDTrace);
582 return rc;
583 }
584 }
585
586 return VINF_SUCCESS;
587}
588
589
590/**
591 * Registers the VTG tracepoint providers of a driver.
592 *
593 * @returns VBox status code.
594 * @param pSession The support driver session handle.
595 * @param pVtgHdr The VTG header.
596 * @param pszName The driver name.
597 */
598SUPR0DECL(int) SUPR0VtgRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
599{
600 int rc;
601
602 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
603 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
604 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
605 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
606
607 rc = supdrvVtgRegister(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
608
609 /*
610 * Try unregister zombies while we have a chance.
611 */
612 supdrvVtgProcessZombies(pSession->pDevExt);
613
614 return rc;
615}
616
617
618/**
619 * Deregister the VTG tracepoint providers of a driver.
620 *
621 * @param pSession The support driver session handle.
622 * @param pVtgHdr The VTG header.
623 */
624SUPR0DECL(void) SUPR0VtgDeregisterDrv(PSUPDRVSESSION pSession)
625{
626 PSUPDRVDTPROVIDER pProv, pProvNext;
627 PSUPDRVDEVEXT pDevExt;
628 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
629 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
630
631 pDevExt = pSession->pDevExt;
632
633 /*
634 * Search for providers belonging to this driver session.
635 */
636 RTSemFastMutexRequest(pDevExt->mtxDTrace);
637 RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
638 {
639 if (pProv->pSession == pSession)
640 {
641 RTListNodeRemove(&pProv->ListEntry);
642 supdrvVtgDeregister(pDevExt, pProv);
643 }
644 }
645 RTSemFastMutexRelease(pDevExt->mtxDTrace);
646
647 /*
648 * Try unregister zombies while we have a chance.
649 */
650 supdrvVtgProcessZombies(pDevExt);
651}
652
653
654/**
655 * Registers the VTG tracepoint providers of a module loaded by
656 * the support driver.
657 *
658 * This should be called from the ModuleInit code.
659 *
660 * @returns VBox status code.
661 * @param hMod The module handle.
662 * @param pVtgHdr The VTG header.
663 */
664SUPR0DECL(int) SUPR0VtgRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
665{
666 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
667 PSUPDRVDEVEXT pDevExt;
668 uintptr_t cbVtgObj;
669 int rc;
670
671 /*
672 * Validate input and context.
673 */
674 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
675 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
676
677 pDevExt = pImage->pDevExt;
678 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
679 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
680 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
681
682 /*
683 * Calculate the max VTG object size and hand it over to the common code.
684 */
685 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
686 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
687 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
688 VERR_INVALID_PARAMETER);
689 cbVtgObj = pImage->cbImageBits - cbVtgObj;
690
691 rc = supdrvVtgRegister(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
692
693 /*
694 * Try unregister zombies while we have a chance.
695 */
696 supdrvVtgProcessZombies(pDevExt);
697
698 return rc;
699}
700
701
702/**
703 * Module unloading hook, called after execution in the module have ceased.
704 *
705 * @param pDevExt The device extension structure.
706 * @param pImage The image being unloaded.
707 */
708void VBOXCALL supdrvVtgModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
709{
710 PSUPDRVDTPROVIDER pProv, pProvNext;
711
712 /*
713 * Unregister all providers belonging to this image.
714 */
715 RTSemFastMutexRequest(pDevExt->mtxDTrace);
716 RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
717 {
718 if (pProv->pImage == pImage)
719 {
720 RTListNodeRemove(&pProv->ListEntry);
721 supdrvVtgDeregister(pDevExt, pProv);
722 }
723 }
724 RTSemFastMutexRelease(pDevExt->mtxDTrace);
725
726 /*
727 * Try unregister zombies while we have a chance.
728 */
729 supdrvVtgProcessZombies(pDevExt);
730}
731
732
733/**
734 * Early module initialization hook.
735 *
736 * @returns VBox status code.
737 * @param pDevExt The device extension structure.
738 * @param pVtgFireProbe Pointer to the SUPR0VtgFireProbe entry.
739 */
740int VBOXCALL supdrvVtgInit(PSUPDRVDEVEXT pDevExt, PSUPFUNC pVtgFireProbe)
741{
742 Assert(!strcmp(pVtgFireProbe->szName, "SUPR0VtgFireProbe"));
743
744 /*
745 * Register a provider for this module.
746 */
747 int rc = RTSemFastMutexCreate(&pDevExt->mtxDTrace);
748 if (RT_SUCCESS(rc))
749 {
750#ifdef RT_OS_SOLARIS
751 pVtgFireProbe->pfn = (void *)(uintptr_t)dtrace_probe;
752#endif
753 RTListInit(&pDevExt->DtProviderList);
754 RTListInit(&pDevExt->DtProviderZombieList);
755 rc = supdrvVtgRegister(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
756 if (RT_SUCCESS(rc))
757 return rc;
758 RTSemFastMutexDestroy(pDevExt->mtxDTrace);
759 }
760 pDevExt->mtxDTrace = NIL_RTSEMFASTMUTEX;
761 return rc;
762}
763
764
765/**
766 * Late module termination hook.
767 *
768 * @returns VBox status code.
769 * @param pDevExt The device extension structure.
770 */
771void VBOXCALL supdrvVtgTerm(PSUPDRVDEVEXT pDevExt)
772{
773 PSUPDRVDTPROVIDER pProv, pProvNext;
774 uint32_t i;
775 LOG_DTRACE(("supdrvVtgTerm\n"));
776
777 /*
778 * Unregister all probes (there should only be one).
779 */
780 RTSemFastMutexRequest(pDevExt->mtxDTrace);
781 RTListForEachSafe(&pDevExt->DtProviderList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
782 {
783 RTListNodeRemove(&pProv->ListEntry);
784 supdrvVtgDeregister(pDevExt, pProv);
785 }
786 RTSemFastMutexRelease(pDevExt->mtxDTrace);
787
788 /*
789 * Try unregister zombies now, sleep on busy ones.
790 */
791 for (i = 0; ; i++)
792 {
793 bool fEmpty;
794
795 RTSemFastMutexRequest(pDevExt->mtxDTrace);
796 RTListForEachSafe(&pDevExt->DtProviderZombieList, pProv, pProvNext, SUPDRVDTPROVIDER, ListEntry)
797 {
798 int rc;
799 LOG_DTRACE(("supdrvVtgTerm: Attemting to unregister '%s' / %p...\n", pProv->szName, pProv->idDtProv));
800 rc = dtrace_unregister(pProv->idDtProv);
801 if (!rc)
802 {
803 RTListNodeRemove(&pProv->ListEntry);
804 supdrvVtgFreeProvider(pProv);
805 }
806 else if (!(i & 0xf))
807 SUPR0Printf("supdrvVtgTerm: Waiting on busy provider '%s' / %p (rc=%d)\n", pProv->szName, pProv->idDtProv, rc);
808 else
809 LOG_DTRACE(("supdrvVtgTerm: Failed to unregister provider '%s' / %p - rc=%d\n", pProv->szName, pProv->idDtProv, rc));
810 }
811
812 fEmpty = RTListIsEmpty(&pDevExt->DtProviderZombieList);
813 RTSemFastMutexRelease(pDevExt->mtxDTrace);
814 if (fEmpty)
815 break;
816
817 /* Delay...*/
818 RTThreadSleep(1000);
819 }
820
821 RTSemFastMutexDestroy(pDevExt->mtxDTrace);
822 pDevExt->mtxDTrace = NIL_RTSEMFASTMUTEX;
823 LOG_DTRACE(("supdrvVtgTerm: Done\n"));
824}
825
826
827/**
828 * @callback_method_impl{dtrace_pops_t,dtps_provide}
829 */
830static void supdrvDTracePOps_Provide(void *pvProv, const dtrace_probedesc_t *pDtProbeDesc)
831{
832 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
833 uint16_t idxProv;
834 PVTGPROBELOC pProbeLoc;
835 PVTGPROBELOC pProbeLocEnd;
836 char *pszFnNmBuf;
837 size_t const cbFnNmBuf = _4K + _1K;
838
839 if (pDtProbeDesc)
840 return; /* We don't generate probes, so never mind these requests. */
841
842 if (pProv->fZombie)
843 return;
844
845 if (pProv->cProvidedProbes >= pProv->pDesc->cProbes)
846 return;
847
848 /* Need a buffer for extracting the function names and mangling them in
849 case of collision. */
850 pszFnNmBuf = (char *)RTMemAlloc(cbFnNmBuf);
851 if (!pszFnNmBuf)
852 return;
853
854 /*
855 * Itereate the probe location list and register all probes related to
856 * this provider.
857 */
858 idxProv = (uint16_t)(&pProv->pHdr->paProviders[0] - pProv->pDesc);
859 pProbeLoc = pProv->pHdr->paProbLocs;
860 pProbeLocEnd = pProv->pHdr->paProbLocsEnd;
861 while ((uintptr_t)pProbeLoc < (uintptr_t)pProbeLocEnd)
862 {
863 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
864 if ( pProbeDesc->idxProvider == idxProv
865 && pProbeLoc->idProbe == UINT32_MAX)
866 {
867 /* The function name normally needs to be stripped since we're
868 using C++ compilers for most of the code. ASSUMES nobody are
869 brave/stupid enough to use function pointer returns without
870 typedef'ing properly them. */
871 const char *pszPrbName = supdrvVtgGetString(pProv->pHdr, pProbeDesc->offName);
872 const char *pszFunc = pProbeLoc->pszFunction;
873 const char *psz = strchr(pProbeLoc->pszFunction, '(');
874 size_t cch;
875 if (psz)
876 {
877 /* skip blanks preceeding the parameter parenthesis. */
878 while ( (uintptr_t)psz > (uintptr_t)pProbeLoc->pszFunction
879 && RT_C_IS_BLANK(psz[-1]))
880 psz--;
881
882 /* Find the start of the function name. */
883 pszFunc = psz - 1;
884 while ((uintptr_t)pszFunc > (uintptr_t)pProbeLoc->pszFunction)
885 {
886 char ch = pszFunc[-1];
887 if (!RT_C_IS_ALNUM(ch) && ch != '_' && ch != ':')
888 break;
889 pszFunc--;
890 }
891 cch = psz - pszFunc;
892 }
893 else
894 cch = strlen(pszFunc);
895 RTStrCopyEx(pszFnNmBuf, cbFnNmBuf, pszFunc, cch);
896
897 /* Look up the probe, if we have one in the same function, mangle
898 the function name a little to avoid having to deal with having
899 multiple location entries with the same probe ID. (lazy bird) */
900 Assert(pProbeLoc->idProbe == UINT32_MAX);
901 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
902 {
903 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u", pProbeLoc->uLine);
904 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) != DTRACE_IDNONE)
905 {
906 unsigned iOrd = 2;
907 while (iOrd < 128)
908 {
909 RTStrPrintf(pszFnNmBuf+cch, cbFnNmBuf - cch, "-%u-%u", pProbeLoc->uLine, iOrd);
910 if (dtrace_probe_lookup(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName) == DTRACE_IDNONE)
911 break;
912 iOrd++;
913 }
914 if (iOrd >= 128)
915 {
916 LogRel(("VBoxDrv: More than 128 duplicate probe location instances in file %s at line %u, function %s [%s], probe %s\n",
917 pProbeLoc->pszFile, pProbeLoc->uLine, pProbeLoc->pszFunction, pszFnNmBuf, pszPrbName));
918 continue;
919 }
920 }
921 }
922
923 /* Create the probe. */
924 AssertCompile(sizeof(pProbeLoc->idProbe) == sizeof(dtrace_id_t));
925 pProbeLoc->idProbe = dtrace_probe_create(pProv->idDtProv, pProv->pszModName, pszFnNmBuf, pszPrbName,
926 0 /*aframes*/, pProbeLoc);
927 pProv->cProvidedProbes++;
928 }
929
930 pProbeLoc++;
931 }
932
933 RTMemFree(pszFnNmBuf);
934}
935
936
937/**
938 * @callback_method_impl{dtrace_pops_t,dtps_enable}
939 */
940static int supdrvDTracePOps_Enable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
941{
942 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
943 if (!pProv->fZombie)
944 {
945 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
946 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
947
948 if (!pProbeLoc->fEnabled)
949 {
950 pProbeLoc->fEnabled = 1;
951 if (ASMAtomicIncU32(&pProbeDesc->u32User) == 1)
952 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
953 }
954 }
955
956 return 0;
957}
958
959
960/**
961 * @callback_method_impl{dtrace_pops_t,dtps_disable}
962 */
963static void supdrvDTracePOps_Disable(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
964{
965 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
966 if (!pProv->fZombie)
967 {
968 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
969 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
970
971 if (pProbeLoc->fEnabled)
972 {
973 pProbeLoc->fEnabled = 0;
974 if (ASMAtomicDecU32(&pProbeDesc->u32User) == 0)
975 pProv->pHdr->pafProbeEnabled[pProbeDesc->idxEnabled] = 1;
976 }
977 }
978}
979
980
981/**
982 * @callback_method_impl{dtrace_pops_t,dtps_getargdesc}
983 */
984static void supdrvDTracePOps_GetArgDesc(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
985 dtrace_argdesc_t *pArgDesc)
986{
987 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
988 unsigned uArg = pArgDesc->dtargd_ndx;
989
990 if (!pProv->fZombie)
991 {
992 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
993 PVTGDESCPROBE pProbeDesc = (PVTGDESCPROBE)pProbeLoc->pbProbe;
994 PVTGDESCARGLIST pArgList = (PVTGDESCARGLIST)((uintptr_t)pProv->pHdr->paArgLists + pProbeDesc->offArgList);
995
996 Assert(pProbeDesc->offArgList < pProv->pHdr->cbArgLists);
997 if (pArgList->cArgs > uArg)
998 {
999 const char *pszType = supdrvVtgGetString(pProv->pHdr, pArgList->aArgs[uArg].offType);
1000 size_t cchType = strlen(pszType);
1001 if (cchType < sizeof(pArgDesc->dtargd_native))
1002 {
1003 memcpy(pArgDesc->dtargd_native, pszType, cchType + 1);
1004 /** @todo mapping */
1005 return;
1006 }
1007 }
1008 }
1009
1010 pArgDesc->dtargd_ndx = DTRACE_ARGNONE;
1011}
1012
1013
1014#ifdef RT_OS_SOLARIS
1015
1016# ifdef __cplusplus
1017extern "C"
1018#endif
1019uint64_t dtrace_getarg(int iArg, int cFrames);
1020
1021/**
1022 * @callback_method_impl{dtrace_pops_t,dtps_getargval}
1023 */
1024static uint64_t supdrvDTracePOps_GetArgVal(void *pvProv, dtrace_id_t idProbe, void *pvProbe,
1025 int iArg, int cFrames)
1026{
1027 /* dtrace_getarg on AMD64 has a different opinion about how to use the
1028 cFrames argument than dtrace_caller() and/or dtrace_getpcstack(), at
1029 least when the probe is fired by dtrace_probe() the way we do.
1030
1031 Setting aframes to 1 when calling dtrace_probe_create gives me the right
1032 arguments, but the wrong 'caller'. Since I cannot do anything about
1033 'caller', the only solution is this hack.
1034
1035 Not sure why the Solaris guys hasn't seen this issue before, but maybe
1036 there isn't anyone using the default argument getter path for ring-0
1037 dtrace_probe() calls, SDT surely isn't.
1038
1039 WARNING! This code is subject to dtrace_getarg interface unstability! */
1040 /** @todo File a solaris bug on dtrace_probe() + dtrace_getarg(). */
1041 return dtrace_getarg(iArg, cFrames + 1);
1042}
1043
1044#endif /* RT_OS_SOLARIS */
1045
1046
1047/**
1048 * @callback_method_impl{dtrace_pops_t,dtps_destroy}
1049 */
1050static void supdrvDTracePOps_Destroy(void *pvProv, dtrace_id_t idProbe, void *pvProbe)
1051{
1052 PSUPDRVDTPROVIDER pProv = (PSUPDRVDTPROVIDER)pvProv;
1053 if (!pProv->fZombie)
1054 {
1055 PVTGPROBELOC pProbeLoc = (PVTGPROBELOC)pvProbe;
1056 Assert(!pProbeLoc->fEnabled);
1057 Assert(pProbeLoc->idProbe == idProbe); NOREF(idProbe);
1058 pProbeLoc->idProbe = UINT32_MAX;
1059 }
1060 pProv->cProvidedProbes--;
1061}
1062
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