VirtualBox

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

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

build fix

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