VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv-tracer.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: 31.8 KB
Line 
1/* $Id: SUPDrv-tracer.cpp 40763 2012-04-04 14:40:09Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Generic Tracer Interface.
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.215389.xyz. 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#define SUPDRV_AGNOSTIC
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
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Data for a tracepoint provider.
52 */
53typedef struct SUPDRVTPPROVIDER
54{
55 /** The entry in the provider list for this image. */
56 RTLISTNODE ListEntry;
57
58 /** The core structure. */
59 SUPDRVVDTPROVIDERCORE Core;
60
61 /** Pointer to the image this provider resides in. NULL if it's a
62 * driver. */
63 PSUPDRVLDRIMAGE pImage;
64 /** The session this provider is associated with if registered via
65 * SUPR0VtgRegisterDrv. NULL if pImage is set. */
66 PSUPDRVSESSION pSession;
67
68 /** Set when the module is unloaded or the driver deregisters its probes. */
69 bool fZombie;
70 /** Set if the provider has been successfully registered with the
71 * tracer. */
72 bool fRegistered;
73 /** The provider name (for logging purposes). */
74 char szName[1];
75} SUPDRVTPPROVIDER;
76/** Pointer to the data for a tracepoint provider. */
77typedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
78
79
80/*******************************************************************************
81* Defined Constants And Macros *
82*******************************************************************************/
83#if 0
84# define LOG_TRACER(a_Args) SUPR0Printf a_Args
85#else
86# define LOG_TRACER(a_Args) do { } while (0)
87#endif
88
89
90/*******************************************************************************
91* Global Variables *
92*******************************************************************************/
93
94
95
96/**
97 * Validates a VTG string against length and characterset limitations.
98 *
99 * @returns VINF_SUCCESS, VERR_SUPDRV_VTG_BAD_STRING or
100 * VERR_SUPDRV_VTG_STRING_TOO_LONG.
101 * @param psz The string.
102 */
103static int supdrvVtgValidateString(const char *psz)
104{
105 size_t off = 0;
106 while (off < _4K)
107 {
108 char const ch = psz[off++];
109 if (!ch)
110 return VINF_SUCCESS;
111 if ( !RTLocCIsAlNum(ch)
112 && ch != ' '
113 && ch != '_'
114 && ch != '-'
115 && ch != '('
116 && ch != ')'
117 && ch != ','
118 && ch != '*'
119 && ch != '&'
120 )
121 {
122 /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
123 return VERR_SUPDRV_VTG_BAD_STRING;
124 }
125 }
126 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
127}
128
129
130/**
131 * Validates the VTG data.
132 *
133 * @returns VBox status code.
134 * @param pVtgHdr The VTG object header of the data to validate.
135 * @param cbVtgObj The size of the VTG object.
136 * @param pbImage The image base. For validating the probe
137 * locations.
138 * @param cbImage The image size to go with @a pbImage.
139 */
140static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
141{
142 uintptr_t cbTmp;
143 uintptr_t offTmp;
144 uintptr_t i;
145 int rc;
146 uint32_t cProviders;
147
148 if (!pbImage || !cbImage)
149 {
150 pbImage = NULL;
151 cbImage = 0;
152 }
153
154#define MY_VALIDATE_PTR(p, cb, cMin, cMax, cbUnit, rcBase) \
155 do { \
156 if ( (cb) >= cbVtgObj \
157 || (uintptr_t)(p) - (uintptr_t)pVtgHdr > cbVtgObj - (cb) ) \
158 return rcBase ## _PTR; \
159 if ((cb) < (cMin) * (cbUnit)) \
160 return rcBase ## _TOO_FEW; \
161 if ((cb) >= (cMax) * (cbUnit)) \
162 return rcBase ## _TOO_MUCH; \
163 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
164 return rcBase ## _NOT_MULTIPLE; \
165 } while (0)
166#define MY_WITHIN_IMAGE(p, rc) \
167 do { \
168 if (pbImage) \
169 { \
170 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
171 return (rc); \
172 } \
173 else if (!RT_VALID_PTR(p)) \
174 return (rc); \
175 } while (0)
176#define MY_VALIDATE_STR(offStrTab) \
177 do { \
178 if ((offStrTab) >= pVtgHdr->cbStrTab) \
179 return VERR_SUPDRV_VTG_STRTAB_OFF; \
180 rc = supdrvVtgValidateString(pVtgHdr->pachStrTab + (offStrTab)); \
181 if (rc != VINF_SUCCESS) \
182 return rc; \
183 } while (0)
184#define MY_VALIDATE_ATTR(Attr) \
185 do { \
186 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
187 return VERR_SUPDRV_VTG_BAD_ATTR; \
188 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
189 return VERR_SUPDRV_VTG_BAD_ATTR; \
190 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
191 return VERR_SUPDRV_VTG_BAD_ATTR; \
192 } while (0)
193
194 /*
195 * The header.
196 */
197 if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
198 return VERR_SUPDRV_VTG_MAGIC;
199 if (pVtgHdr->cBits != ARCH_BITS)
200 return VERR_SUPDRV_VTG_BITS;
201 if (pVtgHdr->u32Reserved0)
202 return VERR_SUPDRV_VTG_BAD_HDR;
203
204 MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
205 MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
206 MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
207 MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
208 MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
209
210 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs, VERR_SUPDRV_VTG_BAD_HDR_PTR);
211 MY_WITHIN_IMAGE(pVtgHdr->paProbLocsEnd, VERR_SUPDRV_VTG_BAD_HDR_PTR);
212 if ((uintptr_t)pVtgHdr->paProbLocs > (uintptr_t)pVtgHdr->paProbLocsEnd)
213 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
214 cbTmp = (uintptr_t)pVtgHdr->paProbLocsEnd - (uintptr_t)pVtgHdr->paProbLocs;
215 if (cbTmp < sizeof(VTGPROBELOC))
216 return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
217 if (cbTmp >= _128K * sizeof(VTGPROBELOC))
218 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
219 if (cbTmp / sizeof(VTGPROBELOC) * sizeof(VTGPROBELOC) != cbTmp)
220 return VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE;
221
222 if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled)
223 return VERR_SUPDRV_VTG_BAD_HDR;
224
225 /*
226 * Validate the providers.
227 */
228 cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
229 while (i-- > 0)
230 {
231 MY_VALIDATE_STR(pVtgHdr->paProviders[i].offName);
232 if (pVtgHdr->paProviders[i].iFirstProbe >= pVtgHdr->cbProbeEnabled)
233 return VERR_SUPDRV_VTG_BAD_PROVIDER;
234 if (pVtgHdr->paProviders[i].iFirstProbe + pVtgHdr->paProviders[i].cProbes > pVtgHdr->cbProbeEnabled)
235 return VERR_SUPDRV_VTG_BAD_PROVIDER;
236 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrSelf);
237 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrModules);
238 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrFunctions);
239 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrNames);
240 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrArguments);
241 if (pVtgHdr->paProviders[i].bReserved)
242 return VERR_SUPDRV_VTG_BAD_PROVIDER;
243 }
244
245 /*
246 * Validate probes.
247 */
248 i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
249 while (i-- > 0)
250 {
251 PVTGDESCARGLIST pArgList;
252 unsigned iArg;
253
254 MY_VALIDATE_STR(pVtgHdr->paProbes[i].offName);
255 if (pVtgHdr->paProbes[i].offArgList >= pVtgHdr->cbArgLists)
256 return VERR_SUPDRV_VTG_BAD_PROBE;
257 if (pVtgHdr->paProbes[i].offArgList & 3)
258 return VERR_SUPDRV_VTG_BAD_PROBE;
259 if (pVtgHdr->paProbes[i].idxEnabled != i) /* The lists are parallel. */
260 return VERR_SUPDRV_VTG_BAD_PROBE;
261 if (pVtgHdr->paProbes[i].idxProvider >= cProviders)
262 return VERR_SUPDRV_VTG_BAD_PROBE;
263 if ( i - pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].iFirstProbe
264 >= pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].cProbes)
265 return VERR_SUPDRV_VTG_BAD_PROBE;
266 if (pVtgHdr->paProbes[i].u32User)
267 return VERR_SUPDRV_VTG_BAD_PROBE;
268
269 /* The referenced argument list. */
270 pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr->paArgLists + pVtgHdr->paProbes[i].offArgList);
271 if (pArgList->cArgs > 16)
272 return VERR_SUPDRV_VTG_BAD_ARGLIST;
273 if ( pArgList->abReserved[0]
274 || pArgList->abReserved[1]
275 || pArgList->abReserved[2])
276 return VERR_SUPDRV_VTG_BAD_ARGLIST;
277 iArg = pArgList->cArgs;
278 while (iArg-- > 0)
279 {
280 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
281 MY_VALIDATE_STR(pArgList->aArgs[iArg].offName);
282 }
283 }
284
285 /*
286 * Check that pafProbeEnabled is all zero.
287 */
288 i = pVtgHdr->cbProbeEnabled;
289 while (i-- > 0)
290 if (pVtgHdr->pafProbeEnabled[0])
291 return VERR_SUPDRV_VTG_BAD_PROBE_ENABLED;
292
293 /*
294 * Probe locations.
295 */
296 i = pVtgHdr->paProbLocsEnd - pVtgHdr->paProbLocs;
297 while (i-- > 0)
298 {
299 if (pVtgHdr->paProbLocs[i].uLine >= _1G)
300 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
301 if (pVtgHdr->paProbLocs[i].fEnabled)
302 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
303 if (pVtgHdr->paProbLocs[i].idProbe != UINT32_MAX)
304 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
305 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
306 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFile, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
307 offTmp = (uintptr_t)pVtgHdr->paProbLocs[i].pbProbe - (uintptr_t)pVtgHdr->paProbes;
308 if (offTmp >= pVtgHdr->cbProbes)
309 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
310 if (offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) != offTmp)
311 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
312 }
313
314 return VINF_SUCCESS;
315#undef MY_VALIDATE_STR
316#undef MY_VALIDATE_PTR
317#undef MY_WITHIN_IMAGE
318}
319
320
321/**
322 * Gets a string from the string table.
323 *
324 * @returns Pointer to the string.
325 * @param pVtgHdr The VTG object header.
326 * @param offStrTab The string table offset.
327 */
328static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
329{
330 Assert(offStrTab < pVtgHdr->cbStrTab);
331 return &pVtgHdr->pachStrTab[offStrTab];
332}
333
334
335/**
336 * Frees the provider structure and associated resources.
337 *
338 * @param pProv The provider to free.
339 */
340static void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
341{
342 LOG_TRACER(("Freeing DTrace provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
343 pProv->fRegistered = false;
344 pProv->fZombie = true;
345 pProv->Core.pDesc = NULL;
346 pProv->Core.pHdr = NULL;
347 RT_ZERO(pProv->Core.TracerData);
348 RTMemFree(pProv);
349}
350
351
352/**
353 * Deregisters a provider.
354 *
355 * If the provider is still busy, it will be put in the zombie list.
356 *
357 * @param pDevExt The device extension.
358 * @param pProv The provider.
359 *
360 * @remarks The caller owns mtxTracer.
361 */
362static void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
363{
364 int rc;
365 if (!pProv->fRegistered || !pDevExt->pTracerOps)
366 rc = VINF_SUCCESS;
367 else
368 rc = pDevExt->pTracerOps->pfnDeregisterProvider(pDevExt->pTracerOps, &pProv->Core);
369 if (RT_SUCCESS(rc))
370 {
371 supdrvTracerFreeProvider(pProv);
372 return;
373 }
374
375 pProv->fZombie = true;
376 RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
377 LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
378 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
379}
380
381
382/**
383 * Processes the zombie list.
384 *
385 * @param pDevExt The device extension.
386 */
387static void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
388{
389 PSUPDRVTPPROVIDER pProv, pProvNext;
390
391 RTSemFastMutexRequest(pDevExt->mtxTracer);
392 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
393 {
394 int rc = pDevExt->pTracerOps->pfnDeregisterZombieProvider(pDevExt->pTracerOps, &pProv->Core);
395 if (RT_SUCCESS(rc))
396 {
397 RTListNodeRemove(&pProv->ListEntry);
398 supdrvTracerFreeProvider(pProv);
399 }
400 }
401 RTSemFastMutexRelease(pDevExt->mtxTracer);
402}
403
404
405/**
406 * Unregisters all providers, including zombies, waiting for busy providers to
407 * go idle and unregister smoothly.
408 *
409 * This may block.
410 *
411 * @param pDevExt The device extension.
412 */
413static void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
414{
415 uint32_t i;
416 PSUPDRVTPPROVIDER pProv;
417 PSUPDRVTPPROVIDER pProvNext;
418
419 /*
420 * Unregister all probes (there should only be one).
421 */
422 RTSemFastMutexRequest(pDevExt->mtxTracer);
423 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
424 {
425 RTListNodeRemove(&pProv->ListEntry);
426 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
427 }
428 RTSemFastMutexRelease(pDevExt->mtxTracer);
429
430 /*
431 * Try unregister zombies now, sleep on busy ones.
432 */
433 for (i = 0; ; i++)
434 {
435 bool fEmpty;
436
437 RTSemFastMutexRequest(pDevExt->mtxTracer);
438 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
439 {
440 int rc;
441 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
442 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
443
444 if (pDevExt->pTracerOps)
445 rc = pDevExt->pTracerOps->pfnDeregisterZombieProvider(pDevExt->pTracerOps, &pProv->Core);
446 else
447 rc = VINF_SUCCESS;
448 if (!rc)
449 {
450 RTListNodeRemove(&pProv->ListEntry);
451 supdrvTracerFreeProvider(pProv);
452 }
453 else if (!(i & 0xf))
454 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
455 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
456 else
457 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
458 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
459 }
460
461 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
462 RTSemFastMutexRelease(pDevExt->mtxTracer);
463 if (fEmpty)
464 break;
465
466 /* Delay...*/
467 RTThreadSleep(1000);
468 }
469}
470
471
472/**
473 * Registers the VTG tracepoint providers of a driver.
474 *
475 * @returns VBox status code.
476 * @param pszName The driver name.
477 * @param pVtgHdr The VTG object header.
478 * @param pVtgObj The size of the VTG object.
479 * @param pImage The image if applicable.
480 * @param pSession The session if applicable.
481 * @param pszModName The module name.
482 */
483static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
484 PSUPDRVSESSION pSession, const char *pszModName)
485{
486 int rc;
487 unsigned i;
488 PSUPDRVTPPROVIDER pProv;
489
490 /*
491 * Validate input.
492 */
493 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
494 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
495 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
496 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
497 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
498
499 if (pImage)
500 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
501 else
502 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
503 if (RT_FAILURE(rc))
504 return rc;
505
506 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
507 if (RT_FAILURE(rc))
508 return rc;
509 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
510 {
511 if (pProv->Core.pHdr == pVtgHdr)
512 {
513 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
514 break;
515 }
516 if ( pProv->pSession == pSession
517 && pProv->pImage == pImage)
518 {
519 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
520 break;
521 }
522 }
523 RTSemFastMutexRelease(pDevExt->mtxTracer);
524 if (RT_FAILURE(rc))
525 return rc;
526
527 /*
528 * Register the providers.
529 */
530 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
531 while (i-- > 0)
532 {
533 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
534 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
535 size_t const cchName = strlen(pszName);
536 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1]));
537 if (pProv)
538 {
539 pProv->Core.pDesc = pDesc;
540 pProv->Core.pHdr = pVtgHdr;
541 pProv->Core.pszName = &pProv->szName[0];
542 pProv->Core.pszModName = pszModName;
543 pProv->pImage = pImage;
544 pProv->pSession = pSession;
545 pProv->fZombie = false;
546 pProv->fRegistered = true;
547 memcpy(&pProv->szName[0], pszName, cchName + 1);
548
549 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
550 if (RT_SUCCESS(rc))
551 {
552 if (pDevExt->pTracerOps)
553 rc = pDevExt->pTracerOps->pfnRegisterProvider(pDevExt->pTracerOps, &pProv->Core);
554 else
555 {
556 pProv->fRegistered = false;
557 rc = VINF_SUCCESS;
558 }
559 if (RT_SUCCESS(rc))
560 {
561 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
562 RTSemFastMutexRelease(pDevExt->mtxTracer);
563 LOG_TRACER(("Registered DTrace provider '%s' in '%s' -> %p\n",
564 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
565 }
566 else
567 {
568 RTSemFastMutexRelease(pDevExt->mtxTracer);
569 RTMemFree(pProv);
570 }
571 }
572 }
573 else
574 rc = VERR_NO_MEMORY;
575
576 if (RT_FAILURE(rc))
577 {
578 PSUPDRVTPPROVIDER pProvNext;
579 supdrvTracerFreeProvider(pProv);
580
581 RTSemFastMutexRequest(pDevExt->mtxTracer);
582 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
583 {
584 if (pProv->Core.pHdr == pVtgHdr)
585 {
586 RTListNodeRemove(&pProv->ListEntry);
587 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
588 }
589 }
590 RTSemFastMutexRelease(pDevExt->mtxTracer);
591 return rc;
592 }
593 }
594
595 return VINF_SUCCESS;
596}
597
598
599/**
600 * Registers the VTG tracepoint providers of a driver.
601 *
602 * @returns VBox status code.
603 * @param pSession The support driver session handle.
604 * @param pVtgHdr The VTG header.
605 * @param pszName The driver name.
606 */
607SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
608{
609 int rc;
610
611 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
612 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
613 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
614 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
615
616 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
617
618 /*
619 * Try unregister zombies while we have a chance.
620 */
621 supdrvTracerProcessZombies(pSession->pDevExt);
622
623 return rc;
624}
625
626
627/**
628 * Deregister the VTG tracepoint providers of a driver.
629 *
630 * @param pSession The support driver session handle.
631 * @param pVtgHdr The VTG header.
632 */
633SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
634{
635 PSUPDRVTPPROVIDER pProv, pProvNext;
636 PSUPDRVDEVEXT pDevExt;
637 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
638 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
639
640 pDevExt = pSession->pDevExt;
641
642 /*
643 * Search for providers belonging to this driver session.
644 */
645 RTSemFastMutexRequest(pDevExt->mtxTracer);
646 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
647 {
648 if (pProv->pSession == pSession)
649 {
650 RTListNodeRemove(&pProv->ListEntry);
651 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
652 }
653 }
654 RTSemFastMutexRelease(pDevExt->mtxTracer);
655
656 /*
657 * Try unregister zombies while we have a chance.
658 */
659 supdrvTracerProcessZombies(pDevExt);
660}
661
662
663/**
664 * Registers the VTG tracepoint providers of a module loaded by
665 * the support driver.
666 *
667 * This should be called from the ModuleInit code.
668 *
669 * @returns VBox status code.
670 * @param hMod The module handle.
671 * @param pVtgHdr The VTG header.
672 */
673SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
674{
675 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
676 PSUPDRVDEVEXT pDevExt;
677 uintptr_t cbVtgObj;
678 int rc;
679
680 /*
681 * Validate input and context.
682 */
683 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
684 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
685
686 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
687 pDevExt = pImage->pDevExt;
688 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
689 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
690 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
691
692 /*
693 * Calculate the max VTG object size and hand it over to the common code.
694 */
695 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
696 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
697 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
698 VERR_INVALID_PARAMETER);
699 cbVtgObj = pImage->cbImageBits - cbVtgObj;
700
701 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
702
703 /*
704 * Try unregister zombies while we have a chance.
705 */
706 supdrvTracerProcessZombies(pDevExt);
707
708 return rc;
709}
710
711
712/**
713 * Registers the tracer implementation.
714 *
715 * This should be called from the ModuleInit code or from a ring-0 session.
716 *
717 * @returns VBox status code.
718 * @param hMod The module handle.
719 * @param pSession Ring-0 session handle.
720 * @param pReg Pointer to the tracer registration structure.
721 * @param ppHlp Where to return the tracer helper method table.
722 */
723SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
724{
725 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
726 PSUPDRVDEVEXT pDevExt;
727 int rc;
728
729 /*
730 * Validate input and context.
731 */
732 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
733 *ppHlp = NULL;
734 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
735
736 if (pImage)
737 {
738 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
739 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
740 pDevExt = pImage->pDevExt;
741 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
742 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
743 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
744 }
745 else
746 {
747 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
748 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
749 pDevExt = pSession->pDevExt;
750 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
751 }
752
753 AssertPtrReturn(pReg->pfnRegisterProvider, VERR_INVALID_POINTER);
754 AssertPtrReturn(pReg->pfnDeregisterProvider, VERR_INVALID_POINTER);
755 AssertPtrReturn(pReg->pfnDeregisterZombieProvider, VERR_INVALID_POINTER);
756
757 /*
758 * Do the job.
759 */
760 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
761 if (RT_SUCCESS(rc))
762 {
763 if (!pDevExt->pTracerOps)
764 {
765 pDevExt->pTracerOps = pReg;
766 pDevExt->pTracerSession = pSession;
767 pDevExt->pTracerImage = pImage;
768
769 *ppHlp = &pDevExt->TracerHlp;
770 rc = VINF_SUCCESS;
771 }
772 else
773 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
774 RTSemFastMutexRelease(pDevExt->mtxTracer);
775 }
776
777 return rc;
778
779}
780
781
782/**
783 * Deregister a tracer implementation associated with a ring-0 session.
784 *
785 * @returns VBox status code.
786 * @param pSession Ring-0 session handle.
787 */
788SUPR0DECL(int) SUPR0TracerDeregisterImpl(PSUPDRVSESSION pSession)
789{
790 PSUPDRVDEVEXT pDevExt;
791 int rc;
792
793 /*
794 * Validate input and context.
795 */
796 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
797 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
798 pDevExt = pSession->pDevExt;
799 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
800
801 /*
802 * Do the job.
803 */
804 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
805 if (RT_SUCCESS(rc))
806 {
807 if (pDevExt->pTracerSession == pSession)
808 {
809 pDevExt->fTracerUnloading = true;
810 RTSemFastMutexRelease(pDevExt->mtxTracer);
811
812 supdrvTracerRemoveAllProviders(pDevExt);
813
814 RTSemFastMutexRequest(pDevExt->mtxTracer);
815 pDevExt->pTracerImage = NULL;
816 pDevExt->pTracerSession = NULL;
817 pDevExt->pTracerOps = NULL;
818 pDevExt->fTracerUnloading = false;
819 }
820 else
821 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
822 RTSemFastMutexRelease(pDevExt->mtxTracer);
823 }
824
825 return rc;
826}
827
828
829/**
830 * Module unloading hook, called after execution in the module have ceased.
831 *
832 * @param pDevExt The device extension structure.
833 * @param pImage The image being unloaded.
834 */
835void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
836{
837 PSUPDRVTPPROVIDER pProv, pProvNext;
838 AssertPtrReturnVoid(pImage); /* paranoia */
839
840 RTSemFastMutexRequest(pDevExt->mtxTracer);
841
842 /*
843 * If it is the tracer image, we have to unload all the providers.
844 */
845 if (pDevExt->pTracerImage == pImage)
846 {
847 pDevExt->fTracerUnloading = true;
848 RTSemFastMutexRelease(pDevExt->mtxTracer);
849
850 supdrvTracerRemoveAllProviders(pDevExt);
851
852 RTSemFastMutexRequest(pDevExt->mtxTracer);
853 pDevExt->pTracerImage = NULL;
854 pDevExt->pTracerSession = NULL;
855 pDevExt->pTracerOps = NULL;
856 pDevExt->fTracerUnloading = false;
857 RTSemFastMutexRelease(pDevExt->mtxTracer);
858 }
859 else
860 {
861 /*
862 * Unregister all providers belonging to this image.
863 */
864 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
865 {
866 if (pProv->pImage == pImage)
867 {
868 RTListNodeRemove(&pProv->ListEntry);
869 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
870 }
871 }
872
873 RTSemFastMutexRelease(pDevExt->mtxTracer);
874
875 /*
876 * Try unregister zombies while we have a chance.
877 */
878 supdrvTracerProcessZombies(pDevExt);
879 }
880}
881
882
883/**
884 * Called when a session is being cleaned up.
885 *
886 * @param pDevExt The device extension structure.
887 * @param pSession The session that is being torn down.
888 */
889void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
890{
891 /*
892 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
893 */
894 if (pSession->R0Process == NIL_RTR0PROCESS)
895 {
896 SUPDRVTPPROVIDER *pNextProv;
897 SUPDRVTPPROVIDER *pProv;
898
899 RTSemFastMutexRequest(pDevExt->mtxTracer);
900 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
901 {
902 if (pProv->pSession == pSession)
903 {
904 RTListNodeRemove(&pProv->ListEntry);
905 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
906 }
907 }
908 RTSemFastMutexRelease(pDevExt->mtxTracer);
909
910 (void)SUPR0TracerDeregister(pSession);
911 }
912
913 /*
914 * Clean up instance data the trace may have associated with the session.
915 */
916 if (pSession->uTracerData)
917 {
918 RTSemFastMutexRequest(pDevExt->mtxTracer);
919 if ( pSession->uTracerData
920 && pDevExt->pTracerOps)
921 pSession->pTracerOps->pfnCloseTrace(pSession->pTracerOps, pSession, pSession->uTracerData);
922 pSession->uTracerData = 0;
923 RTSemFastMutexRelease(pDevExt->mtxTracer);
924 }
925}
926
927
928/**
929 * Early module initialization hook.
930 *
931 * @returns VBox status code.
932 * @param pDevExt The device extension structure.
933 */
934int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
935{
936 /*
937 * Register a provider for this module.
938 */
939 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
940 if (RT_SUCCESS(rc))
941 {
942 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
943 /** @todo */
944 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
945 RTListInit(&pDevExt->TracerProviderList);
946 RTListInit(&pDevExt->TracerProviderZombieList);
947
948 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
949 if (RT_SUCCESS(rc))
950 return rc;
951 RTSemFastMutexDestroy(pDevExt->mtxTracer);
952 }
953 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
954 return rc;
955}
956
957
958/**
959 * Late module termination hook.
960 *
961 * @returns VBox status code.
962 * @param pDevExt The device extension structure.
963 */
964void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
965{
966 LOG_TRACER(("supdrvTracerTerm\n"));
967
968 supdrvTracerRemoveAllProviders(pDevExt);
969
970 RTSemFastMutexDestroy(pDevExt->mtxTracer);
971 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
972 LOG_TRACER(("supdrvTracerTerm: Done\n"));
973}
974
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