VirtualBox

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

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

tstSupLoadModule: new trick

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