VirtualBox

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

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

forgot a stub

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 35.4 KB
Line 
1/* $Id: SUPDrvTracer.cpp 40782 2012-04-05 23:08:21Z vboxsync $ */
2/** @file
3 * VBoxDrv - The VirtualBox Support Driver - Tracer Interface.
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#define LOG_GROUP LOG_GROUP_SUP_DRV
32#define SUPDRV_AGNOSTIC
33#include "SUPDrvInternal.h"
34
35#include <VBox/err.h>
36#include <VBox/log.h>
37#include <VBox/VBoxTpG.h>
38
39#include <iprt/assert.h>
40#include <iprt/ctype.h>
41#include <iprt/list.h>
42#include <iprt/mem.h>
43#include <iprt/semaphore.h>
44#include <iprt/thread.h>
45
46
47/*******************************************************************************
48* Structures and Typedefs *
49*******************************************************************************/
50/**
51 * Data for a tracepoint provider.
52 */
53typedef struct SUPDRVTPPROVIDER
54{
55 /** The entry in the provider list for this image. */
56 RTLISTNODE ListEntry;
57
58 /** The core structure. */
59 SUPDRVVDTPROVIDERCORE Core;
60
61 /** Pointer to the image this provider resides in. NULL if it's a
62 * driver. */
63 PSUPDRVLDRIMAGE pImage;
64 /** The session this provider is associated with if registered via
65 * SUPR0VtgRegisterDrv. NULL if pImage is set. */
66 PSUPDRVSESSION pSession;
67
68 /** 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
682 /*
683 * Validate input and context.
684 */
685 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
686 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
687
688 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
689 pDevExt = pImage->pDevExt;
690 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
691 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
692 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
693
694 /*
695 * Calculate the max VTG object size and hand it over to the common code.
696 */
697 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
698 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
699 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
700 VERR_INVALID_PARAMETER);
701 cbVtgObj = pImage->cbImageBits - cbVtgObj;
702
703 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
704
705 /*
706 * Try unregister zombies while we have a chance.
707 */
708 supdrvTracerProcessZombies(pDevExt);
709
710 return rc;
711}
712
713
714/**
715 * Registers the tracer implementation.
716 *
717 * This should be called from the ModuleInit code or from a ring-0 session.
718 *
719 * @returns VBox status code.
720 * @param hMod The module handle.
721 * @param pSession Ring-0 session handle.
722 * @param pReg Pointer to the tracer registration structure.
723 * @param ppHlp Where to return the tracer helper method table.
724 */
725SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
726{
727 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
728 PSUPDRVDEVEXT pDevExt;
729 int rc;
730
731 /*
732 * Validate input and context.
733 */
734 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
735 *ppHlp = NULL;
736 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
737
738 if (pImage)
739 {
740 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
741 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
742 pDevExt = pImage->pDevExt;
743 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
744 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
745 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
746 }
747 else
748 {
749 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
750 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
751 pDevExt = pSession->pDevExt;
752 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
753 }
754
755 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
756 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
757 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
758 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
759 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
760 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
761 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
762 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
763
764 /*
765 * Do the job.
766 */
767 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
768 if (RT_SUCCESS(rc))
769 {
770 if (!pDevExt->pTracerOps)
771 {
772 pDevExt->pTracerOps = pReg;
773 pDevExt->pTracerSession = pSession;
774 pDevExt->pTracerImage = pImage;
775
776 *ppHlp = &pDevExt->TracerHlp;
777 rc = VINF_SUCCESS;
778 }
779 else
780 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
781 RTSemFastMutexRelease(pDevExt->mtxTracer);
782 }
783
784 return rc;
785
786}
787
788
789/**
790 * Common tracer implementation deregistration code.
791 *
792 * The caller sets fTracerUnloading prior to calling this function.
793 *
794 * @param pDevExt The device extension structure.
795 */
796static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
797{
798 supdrvTracerRemoveAllProviders(pDevExt);
799
800 RTSemFastMutexRequest(pDevExt->mtxTracer);
801 pDevExt->pTracerImage = NULL;
802 pDevExt->pTracerSession = NULL;
803 pDevExt->pTracerOps = NULL;
804 pDevExt->fTracerUnloading = false;
805 RTSemFastMutexRelease(pDevExt->mtxTracer);
806}
807
808
809/**
810 * Deregister a tracer implementation.
811 *
812 * This should be called from the ModuleTerm code or from a ring-0 session.
813 *
814 * @returns VBox status code.
815 * @param hMod The module handle.
816 * @param pSession Ring-0 session handle.
817 */
818SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
819{
820 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
821 PSUPDRVDEVEXT pDevExt;
822 int rc;
823
824 /*
825 * Validate input and context.
826 */
827 if (pImage)
828 {
829 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
830 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
831 pDevExt = pImage->pDevExt;
832 }
833 else
834 {
835 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
836 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
837 pDevExt = pSession->pDevExt;
838 }
839 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
840
841 /*
842 * Do the job.
843 */
844 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
845 if (RT_SUCCESS(rc))
846 {
847 if ( pImage
848 ? pDevExt->pTracerImage == pImage
849 : pDevExt->pTracerSession == pSession)
850 {
851 pDevExt->fTracerUnloading = true;
852 RTSemFastMutexRelease(pDevExt->mtxTracer);
853 supdrvTracerCommonDeregisterImpl(pDevExt);
854 }
855 else
856 {
857 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
858 RTSemFastMutexRelease(pDevExt->mtxTracer);
859 }
860 }
861
862 return rc;
863}
864
865
866/*
867 * The probe function is a bit more fun since we need tail jump optimizating.
868 *
869 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
870 * rebuilding of the kernel module from scratch at install time, we have to
871 * deploy some ugly gcc inline assembly here.
872 */
873#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
874# if 0 /* Need to check this out on linux (on mac now) */
875/*DECLASM(void) supdrvTracerProbeFireStub(void);*/
876__asm__ __volatile__("\
877 .pushsection .text \
878 \
879 .p2align 2,,3 \
880 .type supdrvTracerProbeFireStub,@function \
881 .global supdrvTracerProbeFireStub \
882supdrvTracerProbeFireStub: \
883 ret \
884supdrvTracerProbeFireStub_End: \
885 .size supdrvTracerProbeFireStub_End - supdrvTracerProbeFireStub \
886 \
887 .p2align 2,,3 \
888 .global SUPR0TracerFireProbe \
889SUPR0TracerFireProbe: \
890");
891# if defined(RT_ARCH_AMD64)
892__asm__ __volatile__(" \
893 mov g_pfnSupdrvProbeFireKernel(%rip), %rax \
894 jmp *%rax \
895");
896# elif defined(RT_ARCH_X86)
897__asm__ __volatile__(" \
898 mov g_pfnSupdrvProbeFireKernel, %eax \
899 jmp *%eax \
900");
901# else
902# error "Which arch is this?"
903#endif
904__asm__ __volatile__(" \
905SUPR0TracerFireProbe_End: \
906 .size SUPR0TracerFireProbe_End - SUPR0TracerFireProbe \
907 .popsection \
908");
909
910# else
911SUPR0DECL(void) SUPR0TracerFireProbe(uint32_t idProbe, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2,
912 uintptr_t uArg3, uintptr_t uArg4)
913{
914 return;
915}
916
917DECLASM(void) supdrvTracerProbeFireStub(void)
918{
919 return;
920}
921# endif
922#endif
923
924
925/**
926 * Module unloading hook, called after execution in the module have ceased.
927 *
928 * @param pDevExt The device extension structure.
929 * @param pImage The image being unloaded.
930 */
931void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
932{
933 PSUPDRVTPPROVIDER pProv, pProvNext;
934 AssertPtrReturnVoid(pImage); /* paranoia */
935
936 RTSemFastMutexRequest(pDevExt->mtxTracer);
937
938 /*
939 * If it is the tracer image, we have to unload all the providers.
940 */
941 if (pDevExt->pTracerImage == pImage)
942 {
943 pDevExt->fTracerUnloading = true;
944 RTSemFastMutexRelease(pDevExt->mtxTracer);
945 supdrvTracerCommonDeregisterImpl(pDevExt);
946 }
947 else
948 {
949 /*
950 * Unregister all providers belonging to this image.
951 */
952 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
953 {
954 if (pProv->pImage == pImage)
955 {
956 RTListNodeRemove(&pProv->ListEntry);
957 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
958 }
959 }
960
961 RTSemFastMutexRelease(pDevExt->mtxTracer);
962
963 /*
964 * Try unregister zombies while we have a chance.
965 */
966 supdrvTracerProcessZombies(pDevExt);
967 }
968}
969
970
971/**
972 * Called when a session is being cleaned up.
973 *
974 * @param pDevExt The device extension structure.
975 * @param pSession The session that is being torn down.
976 */
977void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
978{
979 /*
980 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
981 */
982 if (pSession->R0Process == NIL_RTR0PROCESS)
983 {
984 SUPDRVTPPROVIDER *pProvNext;
985 SUPDRVTPPROVIDER *pProv;
986
987 RTSemFastMutexRequest(pDevExt->mtxTracer);
988 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
989 {
990 if (pProv->pSession == pSession)
991 {
992 RTListNodeRemove(&pProv->ListEntry);
993 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
994 }
995 }
996 RTSemFastMutexRelease(pDevExt->mtxTracer);
997
998 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
999 }
1000
1001 /*
1002 * Clean up instance data the trace may have associated with the session.
1003 */
1004 if (pSession->uTracerData)
1005 {
1006 RTSemFastMutexRequest(pDevExt->mtxTracer);
1007 if ( pSession->uTracerData
1008 && pDevExt->pTracerOps)
1009 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, pSession->uTracerData);
1010 pSession->uTracerData = 0;
1011 RTSemFastMutexRelease(pDevExt->mtxTracer);
1012 }
1013}
1014
1015
1016/**
1017 * Early module initialization hook.
1018 *
1019 * @returns VBox status code.
1020 * @param pDevExt The device extension structure.
1021 */
1022int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
1023{
1024 /*
1025 * Register a provider for this module.
1026 */
1027 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
1028 if (RT_SUCCESS(rc))
1029 {
1030 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
1031 /** @todo */
1032 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
1033 RTListInit(&pDevExt->TracerProviderList);
1034 RTListInit(&pDevExt->TracerProviderZombieList);
1035
1036#ifdef VBOX_WITH_DTRACE_R0DRV
1037 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
1038 if (RT_SUCCESS(rc))
1039#endif
1040 return rc;
1041 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1042 }
1043 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1044 return rc;
1045}
1046
1047
1048/**
1049 * Late module termination hook.
1050 *
1051 * @returns VBox status code.
1052 * @param pDevExt The device extension structure.
1053 */
1054void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
1055{
1056 LOG_TRACER(("supdrvTracerTerm\n"));
1057
1058 supdrvTracerRemoveAllProviders(pDevExt);
1059
1060 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1061 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1062 LOG_TRACER(("supdrvTracerTerm: Done\n"));
1063}
1064
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