VirtualBox

source: vbox/trunk/src/VBox/HostDrivers/Support/SUPDrv-tracer.cpp@ 40756

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

SUP: Working on a generic tracer interface.

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