VirtualBox

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

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

SUPDrv: Added three new IOCtls for talking to the tracer.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 45.6 KB
Line 
1/* $Id: SUPDrvTracer.cpp 40819 2012-04-07 20:53:40Z 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.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 /** 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 uintptr_t cProviders;
153 int rc;
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 and tracer opens.
439 */
440 for (i = 0; ; i++)
441 {
442 bool fEmpty;
443
444 RTSemFastMutexRequest(pDevExt->mtxTracer);
445
446 /* Zombies */
447 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
448 {
449 int rc;
450 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
451 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
452
453 if (pDevExt->pTracerOps)
454 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
455 else
456 rc = VINF_SUCCESS;
457 if (!rc)
458 {
459 RTListNodeRemove(&pProv->ListEntry);
460 supdrvTracerFreeProvider(pProv);
461 }
462 else if (!(i & 0xf))
463 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
464 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
465 else
466 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
467 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
468 }
469
470 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
471
472 /* Tracer opens. */
473 if ( pDevExt->cTracerOpens
474 && pDevExt->pTracerOps)
475 {
476 fEmpty = false;
477 if (!(i & 0xf))
478 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens);
479 else
480 LOG_TRACER(("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens));
481 }
482
483 RTSemFastMutexRelease(pDevExt->mtxTracer);
484
485 if (fEmpty)
486 break;
487
488 /* Delay...*/
489 RTThreadSleep(1000);
490 }
491}
492
493
494/**
495 * Registers the VTG tracepoint providers of a driver.
496 *
497 * @returns VBox status code.
498 * @param pszName The driver name.
499 * @param pVtgHdr The VTG object header.
500 * @param pVtgObj The size of the VTG object.
501 * @param pImage The image if applicable.
502 * @param pSession The session if applicable.
503 * @param pszModName The module name.
504 */
505static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
506 PSUPDRVSESSION pSession, const char *pszModName)
507{
508 int rc;
509 uintptr_t i;
510 PSUPDRVTPPROVIDER pProv;
511
512 /*
513 * Validate input.
514 */
515 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
516 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
517 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
518 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
519 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
520
521 if (pImage)
522 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
523 else
524 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
525 if (RT_FAILURE(rc))
526 return rc;
527
528 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
529 if (RT_FAILURE(rc))
530 return rc;
531 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
532 {
533 if (pProv->Core.pHdr == pVtgHdr)
534 {
535 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
536 break;
537 }
538 if ( pProv->pSession == pSession
539 && pProv->pImage == pImage)
540 {
541 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
542 break;
543 }
544 }
545 RTSemFastMutexRelease(pDevExt->mtxTracer);
546 if (RT_FAILURE(rc))
547 return rc;
548
549 /*
550 * Register the providers.
551 */
552 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
553 while (i-- > 0)
554 {
555 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
556 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
557 size_t const cchName = strlen(pszName);
558 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1]));
559 if (pProv)
560 {
561 pProv->Core.pDesc = pDesc;
562 pProv->Core.pHdr = pVtgHdr;
563 pProv->Core.pszName = &pProv->szName[0];
564 pProv->Core.pszModName = pszModName;
565 pProv->pImage = pImage;
566 pProv->pSession = pSession;
567 pProv->fZombie = false;
568 pProv->fRegistered = true;
569 memcpy(&pProv->szName[0], pszName, cchName + 1);
570
571 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
572 if (RT_SUCCESS(rc))
573 {
574 if ( pDevExt->pTracerOps
575 && !pDevExt->fTracerUnloading)
576 rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
577 else
578 {
579 pProv->fRegistered = false;
580 rc = VINF_SUCCESS;
581 }
582 if (RT_SUCCESS(rc))
583 {
584 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
585 RTSemFastMutexRelease(pDevExt->mtxTracer);
586 LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
587 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
588 }
589 else
590 {
591 RTSemFastMutexRelease(pDevExt->mtxTracer);
592 RTMemFree(pProv);
593 }
594 }
595 }
596 else
597 rc = VERR_NO_MEMORY;
598
599 if (RT_FAILURE(rc))
600 {
601 PSUPDRVTPPROVIDER pProvNext;
602 supdrvTracerFreeProvider(pProv);
603
604 RTSemFastMutexRequest(pDevExt->mtxTracer);
605 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
606 {
607 if (pProv->Core.pHdr == pVtgHdr)
608 {
609 RTListNodeRemove(&pProv->ListEntry);
610 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
611 }
612 }
613 RTSemFastMutexRelease(pDevExt->mtxTracer);
614 return rc;
615 }
616 }
617
618 return VINF_SUCCESS;
619}
620
621
622/**
623 * Registers the VTG tracepoint providers of a driver.
624 *
625 * @returns VBox status code.
626 * @param pSession The support driver session handle.
627 * @param pVtgHdr The VTG header.
628 * @param pszName The driver name.
629 */
630SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
631{
632 int rc;
633
634 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
635 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
636 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
637 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
638
639 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
640
641 /*
642 * Try unregister zombies while we have a chance.
643 */
644 supdrvTracerProcessZombies(pSession->pDevExt);
645
646 return rc;
647}
648
649
650/**
651 * Deregister the VTG tracepoint providers of a driver.
652 *
653 * @param pSession The support driver session handle.
654 * @param pVtgHdr The VTG header.
655 */
656SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
657{
658 PSUPDRVTPPROVIDER pProv, pProvNext;
659 PSUPDRVDEVEXT pDevExt;
660 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
661 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
662
663 pDevExt = pSession->pDevExt;
664
665 /*
666 * Search for providers belonging to this driver session.
667 */
668 RTSemFastMutexRequest(pDevExt->mtxTracer);
669 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
670 {
671 if (pProv->pSession == pSession)
672 {
673 RTListNodeRemove(&pProv->ListEntry);
674 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
675 }
676 }
677 RTSemFastMutexRelease(pDevExt->mtxTracer);
678
679 /*
680 * Try unregister zombies while we have a chance.
681 */
682 supdrvTracerProcessZombies(pDevExt);
683}
684
685
686/**
687 * Registers the VTG tracepoint providers of a module loaded by
688 * the support driver.
689 *
690 * This should be called from the ModuleInit code.
691 *
692 * @returns VBox status code.
693 * @param hMod The module handle.
694 * @param pVtgHdr The VTG header.
695 */
696SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
697{
698 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
699 PSUPDRVDEVEXT pDevExt;
700 uintptr_t cbVtgObj;
701 int rc;
702
703 LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
704
705 /*
706 * Validate input and context.
707 */
708 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
709 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
710
711 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
712 pDevExt = pImage->pDevExt;
713 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
714 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
715 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
716
717 /*
718 * Calculate the max VTG object size and hand it over to the common code.
719 */
720 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
721 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
722 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
723 VERR_INVALID_PARAMETER);
724 cbVtgObj = pImage->cbImageBits - cbVtgObj;
725
726 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
727 LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
728
729 /*
730 * Try unregister zombies while we have a chance.
731 */
732 supdrvTracerProcessZombies(pDevExt);
733
734 return rc;
735}
736
737
738/**
739 * Registers the tracer implementation.
740 *
741 * This should be called from the ModuleInit code or from a ring-0 session.
742 *
743 * @returns VBox status code.
744 * @param hMod The module handle.
745 * @param pSession Ring-0 session handle.
746 * @param pReg Pointer to the tracer registration structure.
747 * @param ppHlp Where to return the tracer helper method table.
748 */
749SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
750{
751 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
752 PSUPDRVDEVEXT pDevExt;
753 PSUPDRVTPPROVIDER pProv;
754 int rc;
755
756 /*
757 * Validate input and context.
758 */
759 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
760 *ppHlp = NULL;
761 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
762
763 if (pImage)
764 {
765 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
766 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
767 pDevExt = pImage->pDevExt;
768 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
769 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
770 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
771 }
772 else
773 {
774 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
775 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
776 pDevExt = pSession->pDevExt;
777 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
778 }
779
780 AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
781 AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
782 AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
783 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
784 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
785 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
786 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
787 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
788 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
789 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
790 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
791
792 /*
793 * Do the job.
794 */
795 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
796 if (RT_SUCCESS(rc))
797 {
798 if (!pDevExt->pTracerOps)
799 {
800 LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
801 pDevExt->pTracerOps = pReg;
802 pDevExt->pTracerSession = pSession;
803 pDevExt->pTracerImage = pImage;
804
805 *ppHlp = &pDevExt->TracerHlp;
806
807 rc = VINF_SUCCESS;
808
809 /*
810 * Iterate the already loaded modules and register their providers.
811 */
812 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
813 {
814 Assert(!pProv->fRegistered);
815 pProv->fRegistered = true;
816 int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
817 if (RT_FAILURE(rc2))
818 {
819 pProv->fRegistered = false;
820 SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
821 pProv->Core.pszModName, pProv->szName, rc2);
822 }
823 }
824 }
825 else
826 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
827 RTSemFastMutexRelease(pDevExt->mtxTracer);
828 }
829
830 return rc;
831
832}
833
834
835/**
836 * Common tracer implementation deregistration code.
837 *
838 * The caller sets fTracerUnloading prior to calling this function.
839 *
840 * @param pDevExt The device extension structure.
841 */
842static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
843{
844 uint32_t i;
845 PSUPDRVTPPROVIDER pProv;
846 PSUPDRVTPPROVIDER pProvNext;
847
848 RTSemFastMutexRequest(pDevExt->mtxTracer);
849
850 /*
851 * Disassociate the tracer implementation from all providers.
852 * We will have to wait on busy providers.
853 */
854 for (i = 0; ; i++)
855 {
856 uint32_t cZombies = 0;
857
858 /* Live providers. */
859 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
860 {
861 int rc;
862 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p...\n",
863 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
864
865 if (!pProv->fRegistered)
866 continue;
867 if (!pProv->fZombie)
868 {
869 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
870 if (RT_FAILURE(rc))
871 pProv->fZombie = true;
872 }
873 else
874 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
875 if (RT_SUCCESS(rc))
876 pProv->fZombie = pProv->fRegistered = false;
877 else
878 {
879 cZombies++;
880 if (!(i & 0xf))
881 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
882 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
883 else
884 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
885 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
886 }
887 }
888
889 /* Zombies providers. */
890 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
891 {
892 int rc;
893 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p (zombie)...\n",
894 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
895
896 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
897 if (RT_SUCCESS(rc))
898 {
899 RTListNodeRemove(&pProv->ListEntry);
900 supdrvTracerFreeProvider(pProv);
901 }
902 else
903 {
904 cZombies++;
905 if (!(i & 0xf))
906 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
907 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
908 else
909 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
910 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
911 }
912 }
913
914 /* Tracer opens. */
915 if (pDevExt->cTracerOpens)
916 {
917 cZombies++;
918 if (!(i & 0xf))
919 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens);
920 else
921 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens));
922 }
923
924 /* Done? */
925 if (cZombies == 0)
926 break;
927
928 /* Delay...*/
929 RTSemFastMutexRelease(pDevExt->mtxTracer);
930 RTThreadSleep(1000);
931 RTSemFastMutexRequest(pDevExt->mtxTracer);
932 }
933
934 /*
935 * Deregister the tracer implementation.
936 */
937 pDevExt->pTracerImage = NULL;
938 pDevExt->pTracerSession = NULL;
939 pDevExt->pTracerOps = NULL;
940 pDevExt->fTracerUnloading = false;
941
942 RTSemFastMutexRelease(pDevExt->mtxTracer);
943}
944
945
946/**
947 * Deregister a tracer implementation.
948 *
949 * This should be called from the ModuleTerm code or from a ring-0 session.
950 *
951 * @returns VBox status code.
952 * @param hMod The module handle.
953 * @param pSession Ring-0 session handle.
954 */
955SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
956{
957 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
958 PSUPDRVDEVEXT pDevExt;
959 int rc;
960
961 /*
962 * Validate input and context.
963 */
964 if (pImage)
965 {
966 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
967 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
968 pDevExt = pImage->pDevExt;
969 }
970 else
971 {
972 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
973 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
974 pDevExt = pSession->pDevExt;
975 }
976 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
977
978 /*
979 * Do the job.
980 */
981 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
982 if (RT_SUCCESS(rc))
983 {
984 if ( pImage
985 ? pDevExt->pTracerImage == pImage
986 : pDevExt->pTracerSession == pSession)
987 {
988 LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
989 pDevExt->fTracerUnloading = true;
990 RTSemFastMutexRelease(pDevExt->mtxTracer);
991 supdrvTracerCommonDeregisterImpl(pDevExt);
992 LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
993 }
994 else
995 {
996 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
997 RTSemFastMutexRelease(pDevExt->mtxTracer);
998 }
999 }
1000
1001 return rc;
1002}
1003
1004
1005/*
1006 * The probe function is a bit more fun since we need tail jump optimizating.
1007 *
1008 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
1009 * rebuilding of the kernel module from scratch at install time, we have to
1010 * deploy some ugly gcc inline assembly here.
1011 */
1012#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
1013__asm__("\
1014 .section .text \n\
1015 \n\
1016 .p2align 2,,3 \n\
1017 .global SUPR0TracerFireProbe \n\
1018SUPR0TracerFireProbe: \n\
1019");
1020# if defined(RT_ARCH_AMD64)
1021__asm__(" \
1022 movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
1023 jmp *%rax \n\
1024");
1025# elif defined(RT_ARCH_X86)
1026__asm__("\
1027 movl g_pfnSupdrvProbeFireKernel, %eax \n\
1028 jmp *%eax \n\
1029");
1030# else
1031# error "Which arch is this?"
1032#endif
1033__asm__("\
1034 \n\
1035 .type supdrvTracerProbeFireStub,@function \n\
1036 .global supdrvTracerProbeFireStub \n\
1037supdrvTracerProbeFireStub: \n\
1038 ret \n\
1039 \n\
1040 .previous \n\
1041");
1042# if 0 /* Slickedit on windows highlighting fix */
1043 )
1044# endif
1045#endif
1046
1047
1048/**
1049 * Module unloading hook, called after execution in the module have ceased.
1050 *
1051 * @param pDevExt The device extension structure.
1052 * @param pImage The image being unloaded.
1053 */
1054void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1055{
1056 PSUPDRVTPPROVIDER pProv, pProvNext;
1057 AssertPtrReturnVoid(pImage); /* paranoia */
1058
1059 RTSemFastMutexRequest(pDevExt->mtxTracer);
1060
1061 /*
1062 * If it is the tracer image, we have to unload all the providers.
1063 */
1064 if (pDevExt->pTracerImage == pImage)
1065 {
1066 LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
1067 pDevExt->fTracerUnloading = true;
1068 RTSemFastMutexRelease(pDevExt->mtxTracer);
1069 supdrvTracerCommonDeregisterImpl(pDevExt);
1070 LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
1071 }
1072 else
1073 {
1074 /*
1075 * Unregister all providers belonging to this image.
1076 */
1077 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1078 {
1079 if (pProv->pImage == pImage)
1080 {
1081 RTListNodeRemove(&pProv->ListEntry);
1082 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1083 }
1084 }
1085
1086 RTSemFastMutexRelease(pDevExt->mtxTracer);
1087
1088 /*
1089 * Try unregister zombies while we have a chance.
1090 */
1091 supdrvTracerProcessZombies(pDevExt);
1092 }
1093}
1094
1095
1096/**
1097 * Called when a session is being cleaned up.
1098 *
1099 * @param pDevExt The device extension structure.
1100 * @param pSession The session that is being torn down.
1101 */
1102void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1103{
1104 /*
1105 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
1106 */
1107 if (pSession->R0Process == NIL_RTR0PROCESS)
1108 {
1109 SUPDRVTPPROVIDER *pProvNext;
1110 SUPDRVTPPROVIDER *pProv;
1111
1112 RTSemFastMutexRequest(pDevExt->mtxTracer);
1113 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1114 {
1115 if (pProv->pSession == pSession)
1116 {
1117 RTListNodeRemove(&pProv->ListEntry);
1118 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1119 }
1120 }
1121 RTSemFastMutexRelease(pDevExt->mtxTracer);
1122
1123 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
1124 }
1125
1126 /*
1127 * Clean up instance data the trace may have associated with the session.
1128 */
1129 if (pSession->uTracerData)
1130 {
1131 RTSemFastMutexRequest(pDevExt->mtxTracer);
1132 if ( pSession->uTracerData
1133 && pDevExt->pTracerOps)
1134 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, pSession->uTracerData);
1135 pSession->uTracerData = 0;
1136 RTSemFastMutexRelease(pDevExt->mtxTracer);
1137 }
1138}
1139
1140
1141/**
1142 * Open the tracer.
1143 *
1144 * @returns VBox status code
1145 * @param pDevExt The device extension structure.
1146 * @param pSession The current session.
1147 * @param uCookie The tracer cookie.
1148 * @param uArg The tracer open argument.
1149 */
1150int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
1151{
1152 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1153 int rc;
1154
1155 RTSemFastMutexRequest(pDevExt->mtxTracer);
1156
1157 if (!pSession->uTracerData)
1158 {
1159 if (pDevExt->pTracerOps)
1160 {
1161 if (pDevExt->pTracerSession != pSession)
1162 {
1163 if (!pDevExt->fTracerUnloading)
1164 {
1165 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1166 {
1167 pDevExt->cTracerOpens++;
1168 pSession->uTracerData = ~(uintptr_t)0;
1169 pSession->hTracerCaller = hNativeSelf;
1170 RTSemFastMutexRelease(pDevExt->mtxTracer);
1171
1172 rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
1173
1174 RTSemFastMutexRequest(pDevExt->mtxTracer);
1175 if (RT_FAILURE(rc))
1176 {
1177 pDevExt->cTracerOpens--;
1178 pSession->uTracerData = 0;
1179 }
1180 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1181 }
1182 else
1183 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1184 }
1185 else
1186 rc = VERR_SUPDRV_TRACER_UNLOADING;
1187 }
1188 else
1189 rc = VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF;
1190 }
1191 else
1192 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1193 }
1194 else
1195 rc = VERR_SUPDRV_TRACER_ALREADY_OPENED;
1196
1197 RTSemFastMutexRelease(pDevExt->mtxTracer);
1198 return rc;
1199}
1200
1201
1202/**
1203 * Closes the tracer.
1204 *
1205 * @returns VBox status code.
1206 * @param pDevExt The device extension structure.
1207 * @param pSession The current session.
1208 */
1209int VBOXCALL supdrvIOCtl_TracerClose(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1210{
1211 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1212 int rc;
1213
1214 RTSemFastMutexRequest(pDevExt->mtxTracer);
1215
1216 if (pSession->uTracerData)
1217 {
1218 Assert(pDevExt->cTracerOpens > 0);
1219
1220 if (pDevExt->pTracerOps)
1221 {
1222 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1223 {
1224 uintptr_t uTracerData = pSession->uTracerData;
1225 pSession->uTracerData = 0;
1226 pSession->hTracerCaller = hNativeSelf;
1227 RTSemFastMutexRelease(pDevExt->mtxTracer);
1228
1229 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, uTracerData);
1230 rc = VINF_SUCCESS;
1231
1232 RTSemFastMutexRequest(pDevExt->mtxTracer);
1233 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1234 Assert(pDevExt->cTracerOpens > 0);
1235 pDevExt->cTracerOpens--;
1236 }
1237 else
1238 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1239 }
1240 else
1241 {
1242 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1243 pSession->uTracerData = 0;
1244 Assert(pDevExt->cTracerOpens > 0);
1245 pDevExt->cTracerOpens--;
1246 }
1247 }
1248 else
1249 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1250
1251 RTSemFastMutexRelease(pDevExt->mtxTracer);
1252 return rc;
1253}
1254
1255
1256/**
1257 * Performs a tracer I/O control request.
1258 *
1259 * @returns VBox status code.
1260 * @param pDevExt The device extension structure.
1261 * @param pSession The current session.
1262 * @param uCmd The tracer command.
1263 * @param uArg The tracer argument.
1264 * @param piRetVal Where to store the tracer specific return value.
1265 */
1266int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1267{
1268 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1269 int rc;
1270
1271 RTSemFastMutexRequest(pDevExt->mtxTracer);
1272
1273 if (pSession->uTracerData)
1274 {
1275 Assert(pDevExt->cTracerOpens > 0);
1276 if (pDevExt->pTracerOps)
1277 {
1278 if (!pDevExt->fTracerUnloading)
1279 {
1280 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1281 {
1282 uintptr_t uTracerData = pSession->uTracerData;
1283 pDevExt->cTracerOpens++;
1284 pSession->hTracerCaller = hNativeSelf;
1285 RTSemFastMutexRelease(pDevExt->mtxTracer);
1286
1287 rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
1288
1289 RTSemFastMutexRequest(pDevExt->mtxTracer);
1290 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1291 Assert(pDevExt->cTracerOpens > 0);
1292 pDevExt->cTracerOpens--;
1293 }
1294 else
1295 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1296 }
1297 else
1298 rc = VERR_SUPDRV_TRACER_UNLOADING;
1299 }
1300 else
1301 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1302 }
1303 else
1304 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1305
1306 RTSemFastMutexRelease(pDevExt->mtxTracer);
1307 return rc;
1308}
1309
1310
1311/**
1312 * Early module initialization hook.
1313 *
1314 * @returns VBox status code.
1315 * @param pDevExt The device extension structure.
1316 */
1317int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
1318{
1319 /*
1320 * Register a provider for this module.
1321 */
1322 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
1323 if (RT_SUCCESS(rc))
1324 {
1325 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
1326 /** @todo */
1327 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
1328 RTListInit(&pDevExt->TracerProviderList);
1329 RTListInit(&pDevExt->TracerProviderZombieList);
1330
1331#ifdef VBOX_WITH_DTRACE_R0DRV
1332 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
1333 if (RT_SUCCESS(rc))
1334#endif
1335 return rc;
1336 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1337 }
1338 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1339 return rc;
1340}
1341
1342
1343/**
1344 * Late module termination hook.
1345 *
1346 * @returns VBox status code.
1347 * @param pDevExt The device extension structure.
1348 */
1349void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
1350{
1351 LOG_TRACER(("supdrvTracerTerm\n"));
1352
1353 supdrvTracerRemoveAllProviders(pDevExt);
1354
1355 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1356 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1357 LOG_TRACER(("supdrvTracerTerm: Done\n"));
1358}
1359
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