VirtualBox

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

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

SUPR0VtgFireProbe -> SUPR0TracerFireProbe and other SUPDrv-tracer.cpp changes.

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