VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrvTracer.cpp@ 40813

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

logging adjustments

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 39.3 KB
Line 
1/* $Id: SUPDrvTracer.cpp 40813 2012-04-07 10:23:09Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - 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.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#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 /** Used to indicate that we've called pfnProviderDeregistered already and it
69 * failed because the provider was busy. Next time we must try
70 * pfnProviderDeregisterZombie.
71 *
72 * @remarks This does not necessiarly mean the provider is in the zombie
73 * list. See supdrvTracerCommonDeregisterImpl. */
74 bool fZombie;
75 /** Set if the provider has been successfully registered with the
76 * tracer. */
77 bool fRegistered;
78 /** The provider name (for logging purposes). */
79 char szName[1];
80} SUPDRVTPPROVIDER;
81/** Pointer to the data for a tracepoint provider. */
82typedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
83
84
85/*******************************************************************************
86* Defined Constants And Macros *
87*******************************************************************************/
88#ifdef DEBUG_bird
89# define LOG_TRACER(a_Args) SUPR0Printf a_Args
90#else
91# define LOG_TRACER(a_Args) do { } while (0)
92#endif
93
94
95/*******************************************************************************
96* Global Variables *
97*******************************************************************************/
98/** The address of the current probe fire routine for kernel mode. */
99PFNRT g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
100
101
102
103/**
104 * Validates a VTG string against length and characterset limitations.
105 *
106 * @returns VINF_SUCCESS, VERR_SUPDRV_VTG_BAD_STRING or
107 * VERR_SUPDRV_VTG_STRING_TOO_LONG.
108 * @param psz The string.
109 */
110static int supdrvVtgValidateString(const char *psz)
111{
112 size_t off = 0;
113 while (off < _4K)
114 {
115 char const ch = psz[off++];
116 if (!ch)
117 return VINF_SUCCESS;
118 if ( !RTLocCIsAlNum(ch)
119 && ch != ' '
120 && ch != '_'
121 && ch != '-'
122 && ch != '('
123 && ch != ')'
124 && ch != ','
125 && ch != '*'
126 && ch != '&'
127 )
128 {
129 /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
130 return VERR_SUPDRV_VTG_BAD_STRING;
131 }
132 }
133 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
134}
135
136
137/**
138 * Validates the VTG data.
139 *
140 * @returns VBox status code.
141 * @param pVtgHdr The VTG object header of the data to validate.
142 * @param cbVtgObj The size of the VTG object.
143 * @param pbImage The image base. For validating the probe
144 * locations.
145 * @param cbImage The image size to go with @a pbImage.
146 */
147static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
148{
149 uintptr_t cbTmp;
150 uintptr_t offTmp;
151 uintptr_t i;
152 int rc;
153 uint32_t cProviders;
154
155 if (!pbImage || !cbImage)
156 {
157 pbImage = NULL;
158 cbImage = 0;
159 }
160
161#define MY_VALIDATE_PTR(p, cb, cMin, cMax, cbUnit, rcBase) \
162 do { \
163 if ( (cb) >= cbVtgObj \
164 || (uintptr_t)(p) - (uintptr_t)pVtgHdr > cbVtgObj - (cb) ) \
165 return rcBase ## _PTR; \
166 if ((cb) < (cMin) * (cbUnit)) \
167 return rcBase ## _TOO_FEW; \
168 if ((cb) >= (cMax) * (cbUnit)) \
169 return rcBase ## _TOO_MUCH; \
170 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
171 return rcBase ## _NOT_MULTIPLE; \
172 } while (0)
173#define MY_WITHIN_IMAGE(p, rc) \
174 do { \
175 if (pbImage) \
176 { \
177 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
178 return (rc); \
179 } \
180 else if (!RT_VALID_PTR(p)) \
181 return (rc); \
182 } while (0)
183#define MY_VALIDATE_STR(offStrTab) \
184 do { \
185 if ((offStrTab) >= pVtgHdr->cbStrTab) \
186 return VERR_SUPDRV_VTG_STRTAB_OFF; \
187 rc = supdrvVtgValidateString(pVtgHdr->pachStrTab + (offStrTab)); \
188 if (rc != VINF_SUCCESS) \
189 return rc; \
190 } while (0)
191#define MY_VALIDATE_ATTR(Attr) \
192 do { \
193 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
194 return VERR_SUPDRV_VTG_BAD_ATTR; \
195 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
196 return VERR_SUPDRV_VTG_BAD_ATTR; \
197 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
198 return VERR_SUPDRV_VTG_BAD_ATTR; \
199 } while (0)
200
201 /*
202 * The header.
203 */
204 if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
205 return VERR_SUPDRV_VTG_MAGIC;
206 if (pVtgHdr->cBits != ARCH_BITS)
207 return VERR_SUPDRV_VTG_BITS;
208 if (pVtgHdr->u32Reserved0)
209 return VERR_SUPDRV_VTG_BAD_HDR;
210
211 MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
212 MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
213 MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
214 MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
215 MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
216
217 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs, VERR_SUPDRV_VTG_BAD_HDR_PTR);
218 MY_WITHIN_IMAGE(pVtgHdr->paProbLocsEnd, VERR_SUPDRV_VTG_BAD_HDR_PTR);
219 if ((uintptr_t)pVtgHdr->paProbLocs > (uintptr_t)pVtgHdr->paProbLocsEnd)
220 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
221 cbTmp = (uintptr_t)pVtgHdr->paProbLocsEnd - (uintptr_t)pVtgHdr->paProbLocs;
222 if (cbTmp < sizeof(VTGPROBELOC))
223 return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
224 if (cbTmp >= _128K * sizeof(VTGPROBELOC))
225 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
226 if (cbTmp / sizeof(VTGPROBELOC) * sizeof(VTGPROBELOC) != cbTmp)
227 return VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE;
228
229 if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled)
230 return VERR_SUPDRV_VTG_BAD_HDR;
231
232 /*
233 * Validate the providers.
234 */
235 cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
236 while (i-- > 0)
237 {
238 MY_VALIDATE_STR(pVtgHdr->paProviders[i].offName);
239 if (pVtgHdr->paProviders[i].iFirstProbe >= pVtgHdr->cbProbeEnabled)
240 return VERR_SUPDRV_VTG_BAD_PROVIDER;
241 if (pVtgHdr->paProviders[i].iFirstProbe + pVtgHdr->paProviders[i].cProbes > pVtgHdr->cbProbeEnabled)
242 return VERR_SUPDRV_VTG_BAD_PROVIDER;
243 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrSelf);
244 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrModules);
245 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrFunctions);
246 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrNames);
247 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrArguments);
248 if (pVtgHdr->paProviders[i].bReserved)
249 return VERR_SUPDRV_VTG_BAD_PROVIDER;
250 }
251
252 /*
253 * Validate probes.
254 */
255 i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
256 while (i-- > 0)
257 {
258 PVTGDESCARGLIST pArgList;
259 unsigned iArg;
260
261 MY_VALIDATE_STR(pVtgHdr->paProbes[i].offName);
262 if (pVtgHdr->paProbes[i].offArgList >= pVtgHdr->cbArgLists)
263 return VERR_SUPDRV_VTG_BAD_PROBE;
264 if (pVtgHdr->paProbes[i].offArgList & 3)
265 return VERR_SUPDRV_VTG_BAD_PROBE;
266 if (pVtgHdr->paProbes[i].idxEnabled != i) /* The lists are parallel. */
267 return VERR_SUPDRV_VTG_BAD_PROBE;
268 if (pVtgHdr->paProbes[i].idxProvider >= cProviders)
269 return VERR_SUPDRV_VTG_BAD_PROBE;
270 if ( i - pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].iFirstProbe
271 >= pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].cProbes)
272 return VERR_SUPDRV_VTG_BAD_PROBE;
273 if (pVtgHdr->paProbes[i].u32User)
274 return VERR_SUPDRV_VTG_BAD_PROBE;
275
276 /* The referenced argument list. */
277 pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr->paArgLists + pVtgHdr->paProbes[i].offArgList);
278 if (pArgList->cArgs > 16)
279 return VERR_SUPDRV_VTG_BAD_ARGLIST;
280 if ( pArgList->abReserved[0]
281 || pArgList->abReserved[1]
282 || pArgList->abReserved[2])
283 return VERR_SUPDRV_VTG_BAD_ARGLIST;
284 iArg = pArgList->cArgs;
285 while (iArg-- > 0)
286 {
287 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
288 MY_VALIDATE_STR(pArgList->aArgs[iArg].offName);
289 }
290 }
291
292 /*
293 * Check that pafProbeEnabled is all zero.
294 */
295 i = pVtgHdr->cbProbeEnabled;
296 while (i-- > 0)
297 if (pVtgHdr->pafProbeEnabled[0])
298 return VERR_SUPDRV_VTG_BAD_PROBE_ENABLED;
299
300 /*
301 * Probe locations.
302 */
303 i = pVtgHdr->paProbLocsEnd - pVtgHdr->paProbLocs;
304 while (i-- > 0)
305 {
306 if (pVtgHdr->paProbLocs[i].uLine >= _1G)
307 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
308 if (pVtgHdr->paProbLocs[i].fEnabled)
309 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
310 if (pVtgHdr->paProbLocs[i].idProbe != UINT32_MAX)
311 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
312 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
313 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFile, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
314 offTmp = (uintptr_t)pVtgHdr->paProbLocs[i].pbProbe - (uintptr_t)pVtgHdr->paProbes;
315 if (offTmp >= pVtgHdr->cbProbes)
316 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
317 if (offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) != offTmp)
318 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
319 }
320
321 return VINF_SUCCESS;
322#undef MY_VALIDATE_STR
323#undef MY_VALIDATE_PTR
324#undef MY_WITHIN_IMAGE
325}
326
327
328/**
329 * Gets a string from the string table.
330 *
331 * @returns Pointer to the string.
332 * @param pVtgHdr The VTG object header.
333 * @param offStrTab The string table offset.
334 */
335static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
336{
337 Assert(offStrTab < pVtgHdr->cbStrTab);
338 return &pVtgHdr->pachStrTab[offStrTab];
339}
340
341
342/**
343 * Frees the provider structure and associated resources.
344 *
345 * @param pProv The provider to free.
346 */
347static void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
348{
349 LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
350 pProv->fRegistered = false;
351 pProv->fZombie = true;
352 pProv->Core.pDesc = NULL;
353 pProv->Core.pHdr = NULL;
354 RT_ZERO(pProv->Core.TracerData);
355 RTMemFree(pProv);
356}
357
358
359/**
360 * Deregisters a provider.
361 *
362 * If the provider is still busy, it will be put in the zombie list.
363 *
364 * @param pDevExt The device extension.
365 * @param pProv The provider.
366 *
367 * @remarks The caller owns mtxTracer.
368 */
369static void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
370{
371 int rc;
372 if (!pProv->fRegistered || !pDevExt->pTracerOps)
373 rc = VINF_SUCCESS;
374 else
375 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
376 if (RT_SUCCESS(rc))
377 {
378 supdrvTracerFreeProvider(pProv);
379 return;
380 }
381
382 pProv->fZombie = true;
383 RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
384 LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
385 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
386}
387
388
389/**
390 * Processes the zombie list.
391 *
392 * @param pDevExt The device extension.
393 */
394static void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
395{
396 PSUPDRVTPPROVIDER pProv, pProvNext;
397
398 RTSemFastMutexRequest(pDevExt->mtxTracer);
399 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
400 {
401 int rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
402 if (RT_SUCCESS(rc))
403 {
404 RTListNodeRemove(&pProv->ListEntry);
405 supdrvTracerFreeProvider(pProv);
406 }
407 }
408 RTSemFastMutexRelease(pDevExt->mtxTracer);
409}
410
411
412/**
413 * Unregisters all providers, including zombies, waiting for busy providers to
414 * go idle and unregister smoothly.
415 *
416 * This may block.
417 *
418 * @param pDevExt The device extension.
419 */
420static void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
421{
422 uint32_t i;
423 PSUPDRVTPPROVIDER pProv;
424 PSUPDRVTPPROVIDER pProvNext;
425
426 /*
427 * Unregister all probes (there should only be one).
428 */
429 RTSemFastMutexRequest(pDevExt->mtxTracer);
430 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
431 {
432 RTListNodeRemove(&pProv->ListEntry);
433 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
434 }
435 RTSemFastMutexRelease(pDevExt->mtxTracer);
436
437 /*
438 * Try unregister zombies now, sleep on busy ones.
439 */
440 for (i = 0; ; i++)
441 {
442 bool fEmpty;
443
444 RTSemFastMutexRequest(pDevExt->mtxTracer);
445 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
446 {
447 int rc;
448 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
449 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
450
451 if (pDevExt->pTracerOps)
452 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
453 else
454 rc = VINF_SUCCESS;
455 if (!rc)
456 {
457 RTListNodeRemove(&pProv->ListEntry);
458 supdrvTracerFreeProvider(pProv);
459 }
460 else if (!(i & 0xf))
461 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
462 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
463 else
464 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
465 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
466 }
467
468 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
469 RTSemFastMutexRelease(pDevExt->mtxTracer);
470 if (fEmpty)
471 break;
472
473 /* Delay...*/
474 RTThreadSleep(1000);
475 }
476}
477
478
479/**
480 * Registers the VTG tracepoint providers of a driver.
481 *
482 * @returns VBox status code.
483 * @param pszName The driver name.
484 * @param pVtgHdr The VTG object header.
485 * @param pVtgObj The size of the VTG object.
486 * @param pImage The image if applicable.
487 * @param pSession The session if applicable.
488 * @param pszModName The module name.
489 */
490static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
491 PSUPDRVSESSION pSession, const char *pszModName)
492{
493 int rc;
494 unsigned i;
495 PSUPDRVTPPROVIDER pProv;
496
497 /*
498 * Validate input.
499 */
500 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
501 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
502 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
503 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
504 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
505
506 if (pImage)
507 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
508 else
509 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
510 if (RT_FAILURE(rc))
511 return rc;
512
513 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
514 if (RT_FAILURE(rc))
515 return rc;
516 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
517 {
518 if (pProv->Core.pHdr == pVtgHdr)
519 {
520 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
521 break;
522 }
523 if ( pProv->pSession == pSession
524 && pProv->pImage == pImage)
525 {
526 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
527 break;
528 }
529 }
530 RTSemFastMutexRelease(pDevExt->mtxTracer);
531 if (RT_FAILURE(rc))
532 return rc;
533
534 /*
535 * Register the providers.
536 */
537 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
538 while (i-- > 0)
539 {
540 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
541 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
542 size_t const cchName = strlen(pszName);
543 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1]));
544 if (pProv)
545 {
546 pProv->Core.pDesc = pDesc;
547 pProv->Core.pHdr = pVtgHdr;
548 pProv->Core.pszName = &pProv->szName[0];
549 pProv->Core.pszModName = pszModName;
550 pProv->pImage = pImage;
551 pProv->pSession = pSession;
552 pProv->fZombie = false;
553 pProv->fRegistered = true;
554 memcpy(&pProv->szName[0], pszName, cchName + 1);
555
556 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
557 if (RT_SUCCESS(rc))
558 {
559 if ( pDevExt->pTracerOps
560 && !pDevExt->fTracerUnloading)
561 rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
562 else
563 {
564 pProv->fRegistered = false;
565 rc = VINF_SUCCESS;
566 }
567 if (RT_SUCCESS(rc))
568 {
569 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
570 RTSemFastMutexRelease(pDevExt->mtxTracer);
571 LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
572 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
573 }
574 else
575 {
576 RTSemFastMutexRelease(pDevExt->mtxTracer);
577 RTMemFree(pProv);
578 }
579 }
580 }
581 else
582 rc = VERR_NO_MEMORY;
583
584 if (RT_FAILURE(rc))
585 {
586 PSUPDRVTPPROVIDER pProvNext;
587 supdrvTracerFreeProvider(pProv);
588
589 RTSemFastMutexRequest(pDevExt->mtxTracer);
590 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
591 {
592 if (pProv->Core.pHdr == pVtgHdr)
593 {
594 RTListNodeRemove(&pProv->ListEntry);
595 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
596 }
597 }
598 RTSemFastMutexRelease(pDevExt->mtxTracer);
599 return rc;
600 }
601 }
602
603 return VINF_SUCCESS;
604}
605
606
607/**
608 * Registers the VTG tracepoint providers of a driver.
609 *
610 * @returns VBox status code.
611 * @param pSession The support driver session handle.
612 * @param pVtgHdr The VTG header.
613 * @param pszName The driver name.
614 */
615SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
616{
617 int rc;
618
619 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
620 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
621 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
622 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
623
624 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
625
626 /*
627 * Try unregister zombies while we have a chance.
628 */
629 supdrvTracerProcessZombies(pSession->pDevExt);
630
631 return rc;
632}
633
634
635/**
636 * Deregister the VTG tracepoint providers of a driver.
637 *
638 * @param pSession The support driver session handle.
639 * @param pVtgHdr The VTG header.
640 */
641SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
642{
643 PSUPDRVTPPROVIDER pProv, pProvNext;
644 PSUPDRVDEVEXT pDevExt;
645 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
646 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
647
648 pDevExt = pSession->pDevExt;
649
650 /*
651 * Search for providers belonging to this driver session.
652 */
653 RTSemFastMutexRequest(pDevExt->mtxTracer);
654 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
655 {
656 if (pProv->pSession == pSession)
657 {
658 RTListNodeRemove(&pProv->ListEntry);
659 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
660 }
661 }
662 RTSemFastMutexRelease(pDevExt->mtxTracer);
663
664 /*
665 * Try unregister zombies while we have a chance.
666 */
667 supdrvTracerProcessZombies(pDevExt);
668}
669
670
671/**
672 * Registers the VTG tracepoint providers of a module loaded by
673 * the support driver.
674 *
675 * This should be called from the ModuleInit code.
676 *
677 * @returns VBox status code.
678 * @param hMod The module handle.
679 * @param pVtgHdr The VTG header.
680 */
681SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
682{
683 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
684 PSUPDRVDEVEXT pDevExt;
685 uintptr_t cbVtgObj;
686 int rc;
687
688 LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
689
690 /*
691 * Validate input and context.
692 */
693 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
694 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
695
696 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
697 pDevExt = pImage->pDevExt;
698 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
699 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
700 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
701
702 /*
703 * Calculate the max VTG object size and hand it over to the common code.
704 */
705 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
706 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
707 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
708 VERR_INVALID_PARAMETER);
709 cbVtgObj = pImage->cbImageBits - cbVtgObj;
710
711 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
712 LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
713
714 /*
715 * Try unregister zombies while we have a chance.
716 */
717 supdrvTracerProcessZombies(pDevExt);
718
719 return rc;
720}
721
722
723/**
724 * Registers the tracer implementation.
725 *
726 * This should be called from the ModuleInit code or from a ring-0 session.
727 *
728 * @returns VBox status code.
729 * @param hMod The module handle.
730 * @param pSession Ring-0 session handle.
731 * @param pReg Pointer to the tracer registration structure.
732 * @param ppHlp Where to return the tracer helper method table.
733 */
734SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
735{
736 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
737 PSUPDRVDEVEXT pDevExt;
738 PSUPDRVTPPROVIDER pProv;
739 int rc;
740
741 /*
742 * Validate input and context.
743 */
744 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
745 *ppHlp = NULL;
746 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
747
748 if (pImage)
749 {
750 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
751 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
752 pDevExt = pImage->pDevExt;
753 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
754 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
755 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
756 }
757 else
758 {
759 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
760 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
761 pDevExt = pSession->pDevExt;
762 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
763 }
764
765 AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
766 AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
767 AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
768 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
769 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
770 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
771 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
772 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
773 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
774 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
775 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
776
777 /*
778 * Do the job.
779 */
780 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
781 if (RT_SUCCESS(rc))
782 {
783 if (!pDevExt->pTracerOps)
784 {
785 LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
786 pDevExt->pTracerOps = pReg;
787 pDevExt->pTracerSession = pSession;
788 pDevExt->pTracerImage = pImage;
789
790 *ppHlp = &pDevExt->TracerHlp;
791
792 rc = VINF_SUCCESS;
793
794 /*
795 * Iterate the already loaded modules and register their providers.
796 */
797 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
798 {
799 Assert(!pProv->fRegistered);
800 pProv->fRegistered = true;
801 int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
802 if (RT_FAILURE(rc2))
803 {
804 pProv->fRegistered = false;
805 SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
806 pProv->Core.pszModName, pProv->szName, rc2);
807 }
808 }
809 }
810 else
811 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
812 RTSemFastMutexRelease(pDevExt->mtxTracer);
813 }
814
815 return rc;
816
817}
818
819
820/**
821 * Common tracer implementation deregistration code.
822 *
823 * The caller sets fTracerUnloading prior to calling this function.
824 *
825 * @param pDevExt The device extension structure.
826 */
827static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
828{
829 uint32_t i;
830 PSUPDRVTPPROVIDER pProv;
831 PSUPDRVTPPROVIDER pProvNext;
832
833 RTSemFastMutexRequest(pDevExt->mtxTracer);
834
835 /*
836 * Disassociate the tracer implementation from all providers.
837 * We will have to wait on busy providers.
838 */
839 for (i = 0; ; i++)
840 {
841 uint32_t cZombies = 0;
842
843 /* Live providers. */
844 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
845 {
846 int rc;
847 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
848 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
849
850 if (!pProv->fRegistered)
851 continue;
852 if (!pProv->fZombie)
853 {
854 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
855 if (RT_FAILURE(rc))
856 pProv->fZombie = true;
857 }
858 else
859 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
860 if (RT_SUCCESS(rc))
861 pProv->fZombie = pProv->fRegistered = false;
862 else
863 {
864 cZombies++;
865 if (!(i & 0xf))
866 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
867 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
868 else
869 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
870 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
871 }
872 }
873
874 /* Zombies providers. */
875 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
876 {
877 int rc;
878 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p (zombie)...\n",
879 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
880
881 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
882 if (RT_SUCCESS(rc))
883 {
884 RTListNodeRemove(&pProv->ListEntry);
885 supdrvTracerFreeProvider(pProv);
886 }
887 else
888 {
889 cZombies++;
890 if (!(i & 0xf))
891 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
892 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
893 else
894 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
895 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
896 }
897 }
898
899 if (cZombies == 0)
900 break;
901
902 /* Delay...*/
903 RTSemFastMutexRelease(pDevExt->mtxTracer);
904 RTThreadSleep(1000);
905 RTSemFastMutexRequest(pDevExt->mtxTracer);
906 }
907
908 /*
909 * Deregister the tracer implementation.
910 */
911 pDevExt->pTracerImage = NULL;
912 pDevExt->pTracerSession = NULL;
913 pDevExt->pTracerOps = NULL;
914 pDevExt->fTracerUnloading = false;
915
916 RTSemFastMutexRelease(pDevExt->mtxTracer);
917}
918
919
920/**
921 * Deregister a tracer implementation.
922 *
923 * This should be called from the ModuleTerm code or from a ring-0 session.
924 *
925 * @returns VBox status code.
926 * @param hMod The module handle.
927 * @param pSession Ring-0 session handle.
928 */
929SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
930{
931 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
932 PSUPDRVDEVEXT pDevExt;
933 int rc;
934
935 /*
936 * Validate input and context.
937 */
938 if (pImage)
939 {
940 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
941 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
942 pDevExt = pImage->pDevExt;
943 }
944 else
945 {
946 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
947 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
948 pDevExt = pSession->pDevExt;
949 }
950 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
951
952 /*
953 * Do the job.
954 */
955 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
956 if (RT_SUCCESS(rc))
957 {
958 if ( pImage
959 ? pDevExt->pTracerImage == pImage
960 : pDevExt->pTracerSession == pSession)
961 {
962 LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
963 pDevExt->fTracerUnloading = true;
964 RTSemFastMutexRelease(pDevExt->mtxTracer);
965 supdrvTracerCommonDeregisterImpl(pDevExt);
966 LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
967 }
968 else
969 {
970 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
971 RTSemFastMutexRelease(pDevExt->mtxTracer);
972 }
973 }
974
975 return rc;
976}
977
978
979/*
980 * The probe function is a bit more fun since we need tail jump optimizating.
981 *
982 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
983 * rebuilding of the kernel module from scratch at install time, we have to
984 * deploy some ugly gcc inline assembly here.
985 */
986#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
987__asm__("\
988 .section .text \n\
989 \n\
990 .p2align 2,,3 \n\
991 .global SUPR0TracerFireProbe \n\
992SUPR0TracerFireProbe: \n\
993");
994# if defined(RT_ARCH_AMD64)
995__asm__(" \
996 movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
997 jmp *%rax \n\
998");
999# elif defined(RT_ARCH_X86)
1000__asm__("\
1001 movl g_pfnSupdrvProbeFireKernel, %eax \n\
1002 jmp *%eax \n\
1003");
1004# else
1005# error "Which arch is this?"
1006#endif
1007__asm__("\
1008 \n\
1009 .type supdrvTracerProbeFireStub,@function \n\
1010 .global supdrvTracerProbeFireStub \n\
1011supdrvTracerProbeFireStub: \n\
1012 ret \n\
1013 \n\
1014 .previous \n\
1015");
1016#endif
1017
1018
1019/**
1020 * Module unloading hook, called after execution in the module have ceased.
1021 *
1022 * @param pDevExt The device extension structure.
1023 * @param pImage The image being unloaded.
1024 */
1025void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1026{
1027 PSUPDRVTPPROVIDER pProv, pProvNext;
1028 AssertPtrReturnVoid(pImage); /* paranoia */
1029
1030 RTSemFastMutexRequest(pDevExt->mtxTracer);
1031
1032 /*
1033 * If it is the tracer image, we have to unload all the providers.
1034 */
1035 if (pDevExt->pTracerImage == pImage)
1036 {
1037 LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
1038 pDevExt->fTracerUnloading = true;
1039 RTSemFastMutexRelease(pDevExt->mtxTracer);
1040 supdrvTracerCommonDeregisterImpl(pDevExt);
1041 LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
1042 }
1043 else
1044 {
1045 /*
1046 * Unregister all providers belonging to this image.
1047 */
1048 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1049 {
1050 if (pProv->pImage == pImage)
1051 {
1052 RTListNodeRemove(&pProv->ListEntry);
1053 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1054 }
1055 }
1056
1057 RTSemFastMutexRelease(pDevExt->mtxTracer);
1058
1059 /*
1060 * Try unregister zombies while we have a chance.
1061 */
1062 supdrvTracerProcessZombies(pDevExt);
1063 }
1064}
1065
1066
1067/**
1068 * Called when a session is being cleaned up.
1069 *
1070 * @param pDevExt The device extension structure.
1071 * @param pSession The session that is being torn down.
1072 */
1073void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1074{
1075 /*
1076 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
1077 */
1078 if (pSession->R0Process == NIL_RTR0PROCESS)
1079 {
1080 SUPDRVTPPROVIDER *pProvNext;
1081 SUPDRVTPPROVIDER *pProv;
1082
1083 RTSemFastMutexRequest(pDevExt->mtxTracer);
1084 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1085 {
1086 if (pProv->pSession == pSession)
1087 {
1088 RTListNodeRemove(&pProv->ListEntry);
1089 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1090 }
1091 }
1092 RTSemFastMutexRelease(pDevExt->mtxTracer);
1093
1094 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
1095 }
1096
1097 /*
1098 * Clean up instance data the trace may have associated with the session.
1099 */
1100 if (pSession->uTracerData)
1101 {
1102 RTSemFastMutexRequest(pDevExt->mtxTracer);
1103 if ( pSession->uTracerData
1104 && pDevExt->pTracerOps)
1105 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, pSession->uTracerData);
1106 pSession->uTracerData = 0;
1107 RTSemFastMutexRelease(pDevExt->mtxTracer);
1108 }
1109}
1110
1111
1112/**
1113 * Early module initialization hook.
1114 *
1115 * @returns VBox status code.
1116 * @param pDevExt The device extension structure.
1117 */
1118int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
1119{
1120 /*
1121 * Register a provider for this module.
1122 */
1123 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
1124 if (RT_SUCCESS(rc))
1125 {
1126 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
1127 /** @todo */
1128 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
1129 RTListInit(&pDevExt->TracerProviderList);
1130 RTListInit(&pDevExt->TracerProviderZombieList);
1131
1132#ifdef VBOX_WITH_DTRACE_R0DRV
1133 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
1134 if (RT_SUCCESS(rc))
1135#endif
1136 return rc;
1137 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1138 }
1139 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1140 return rc;
1141}
1142
1143
1144/**
1145 * Late module termination hook.
1146 *
1147 * @returns VBox status code.
1148 * @param pDevExt The device extension structure.
1149 */
1150void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
1151{
1152 LOG_TRACER(("supdrvTracerTerm\n"));
1153
1154 supdrvTracerRemoveAllProviders(pDevExt);
1155
1156 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1157 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1158 LOG_TRACER(("supdrvTracerTerm: Done\n"));
1159}
1160
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette