VirtualBox

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

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

SUPDrv: tracing infastructure coding...

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