VirtualBox

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

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

Working on the 64-bit probe argument issue for 32-bit hosts...

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 49.3 KB
Line 
1/* $Id: SUPDrvTracer.cpp 40878 2012-04-11 20:44:41Z 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 /** Used to indicate that we've called pfnProviderDeregistered already and it
69 * failed because the provider was busy. Next time we must try
70 * pfnProviderDeregisterZombie.
71 *
72 * @remarks This does not necessiarly mean the provider is in the zombie
73 * list. See supdrvTracerCommonDeregisterImpl. */
74 bool fZombie;
75 /** Set if the provider has been successfully registered with the
76 * tracer. */
77 bool fRegistered;
78 /** The provider name (for logging purposes). */
79 char szName[1];
80} SUPDRVTPPROVIDER;
81/** Pointer to the data for a tracepoint provider. */
82typedef SUPDRVTPPROVIDER *PSUPDRVTPPROVIDER;
83
84
85/*******************************************************************************
86* Defined Constants And Macros *
87*******************************************************************************/
88/** Simple SUPR0Printf-style logging. */
89#ifdef DEBUG_bird
90# define LOG_TRACER(a_Args) SUPR0Printf a_Args
91#else
92# define LOG_TRACER(a_Args) do { } while (0)
93#endif
94
95
96/*******************************************************************************
97* Global Variables *
98*******************************************************************************/
99/** The address of the current probe fire routine for kernel mode. */
100PFNRT g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
101
102
103
104/**
105 * Validates a VTG string against length and characterset limitations.
106 *
107 * @returns VINF_SUCCESS, VERR_SUPDRV_VTG_BAD_STRING or
108 * VERR_SUPDRV_VTG_STRING_TOO_LONG.
109 * @param psz The string.
110 */
111static int supdrvVtgValidateString(const char *psz)
112{
113 size_t off = 0;
114 while (off < _4K)
115 {
116 char const ch = psz[off++];
117 if (!ch)
118 return VINF_SUCCESS;
119 if ( !RTLocCIsAlNum(ch)
120 && ch != ' '
121 && ch != '_'
122 && ch != '-'
123 && ch != '('
124 && ch != ')'
125 && ch != ','
126 && ch != '*'
127 && ch != '&'
128 )
129 {
130 /*RTAssertMsg2("off=%u '%s'\n", off, psz);*/
131 return VERR_SUPDRV_VTG_BAD_STRING;
132 }
133 }
134 return VERR_SUPDRV_VTG_STRING_TOO_LONG;
135}
136
137
138/**
139 * Validates the VTG data.
140 *
141 * @returns VBox status code.
142 * @param pVtgHdr The VTG object header of the data to validate.
143 * @param cbVtgObj The size of the VTG object.
144 * @param pbImage The image base. For validating the probe
145 * locations.
146 * @param cbImage The image size to go with @a pbImage.
147 */
148static int supdrvVtgValidate(PVTGOBJHDR pVtgHdr, size_t cbVtgObj, const uint8_t *pbImage, size_t cbImage)
149{
150 uintptr_t cbTmp;
151 uintptr_t offTmp;
152 uintptr_t i;
153 uintptr_t cProviders;
154 int rc;
155
156 if (!pbImage || !cbImage)
157 {
158 pbImage = NULL;
159 cbImage = 0;
160 }
161
162#define MY_VALIDATE_PTR(p, cb, cMin, cMax, cbUnit, rcBase) \
163 do { \
164 if ( (cb) >= cbVtgObj \
165 || (uintptr_t)(p) - (uintptr_t)pVtgHdr > cbVtgObj - (cb) ) \
166 { \
167 SUPR0Printf("supdrvVtgValidate: " #rcBase "_TOO_PTR - p=%p cb=%#zx pVtgHdr=%p cbVtgHdr=%#zu line=%u %s\n", \
168 p, (size_t)(cb), pVtgHdr, cbVtgObj, __LINE__, #p); \
169 return rcBase ## _PTR; \
170 } \
171 if ((cb) < (cMin) * (cbUnit)) \
172 { \
173 SUPR0Printf("supdrvVtgValidate: " #rcBase "_TOO_FEW - cb=%#zx cMin=%#zx cbUnit=%#zx line=%u %s\n", \
174 (size_t)(cb), (size_t)(cMin), (size_t)cbUnit, __LINE__, #p); \
175 return rcBase ## _TOO_FEW; \
176 } \
177 if ((cb) >= (cMax) * (cbUnit)) \
178 { \
179 SUPR0Printf("supdrvVtgValidate: " #rcBase "_TOO_MUCH - cb=%#zx cMax=%#zx cbUnit=%#zx line=%u %s\n", \
180 (size_t)(cb), (size_t)(cMax), (size_t)cbUnit, __LINE__, #p); \
181 return rcBase ## _TOO_MUCH; \
182 } \
183 if ((cb) / (cbUnit) * (cbUnit) != (cb)) \
184 { \
185 SUPR0Printf("supdrvVtgValidate: " #rcBase "_NOT_MULTIPLE - cb=%#zx cbUnit=%#zx line=%u %s\n", \
186 (size_t)(cb), (size_t)cbUnit, __LINE__, #p); \
187 return rcBase ## _NOT_MULTIPLE; \
188 } \
189 } while (0)
190#define MY_WITHIN_IMAGE(p, rc) \
191 do { \
192 if (pbImage) \
193 { \
194 if ((uintptr_t)(p) - (uintptr_t)pbImage > cbImage) \
195 { \
196 SUPR0Printf("supdrvVtgValidate: " #rc " - p=%p pbImage=%p cbImage=%#zxline=%u %s\n", \
197 p, pbImage, cbImage, #p); \
198 return (rc); \
199 } \
200 } \
201 else if (!RT_VALID_PTR(p)) \
202 return (rc); \
203 } while (0)
204#define MY_VALIDATE_STR(offStrTab) \
205 do { \
206 if ((offStrTab) >= pVtgHdr->cbStrTab) \
207 return VERR_SUPDRV_VTG_STRTAB_OFF; \
208 rc = supdrvVtgValidateString(pVtgHdr->pachStrTab + (offStrTab)); \
209 if (rc != VINF_SUCCESS) \
210 return rc; \
211 } while (0)
212#define MY_VALIDATE_ATTR(Attr) \
213 do { \
214 if ((Attr).u8Code <= (uint8_t)kVTGStability_Invalid || (Attr).u8Code >= (uint8_t)kVTGStability_End) \
215 return VERR_SUPDRV_VTG_BAD_ATTR; \
216 if ((Attr).u8Data <= (uint8_t)kVTGStability_Invalid || (Attr).u8Data >= (uint8_t)kVTGStability_End) \
217 return VERR_SUPDRV_VTG_BAD_ATTR; \
218 if ((Attr).u8DataDep <= (uint8_t)kVTGClass_Invalid || (Attr).u8DataDep >= (uint8_t)kVTGClass_End) \
219 return VERR_SUPDRV_VTG_BAD_ATTR; \
220 } while (0)
221
222 /*
223 * The header.
224 */
225 if (memcmp(pVtgHdr->szMagic, VTGOBJHDR_MAGIC, sizeof(pVtgHdr->szMagic)))
226 return VERR_SUPDRV_VTG_MAGIC;
227 if (pVtgHdr->cBits != ARCH_BITS)
228 return VERR_SUPDRV_VTG_BITS;
229 if (pVtgHdr->u32Reserved0)
230 return VERR_SUPDRV_VTG_BAD_HDR;
231
232 MY_VALIDATE_PTR(pVtgHdr->paProviders, pVtgHdr->cbProviders, 1, 16, sizeof(VTGDESCPROVIDER), VERR_SUPDRV_VTG_BAD_HDR);
233 MY_VALIDATE_PTR(pVtgHdr->paProbes, pVtgHdr->cbProbes, 1, _32K, sizeof(VTGDESCPROBE), VERR_SUPDRV_VTG_BAD_HDR);
234 MY_VALIDATE_PTR(pVtgHdr->pafProbeEnabled, pVtgHdr->cbProbeEnabled, 1, _32K, sizeof(bool), VERR_SUPDRV_VTG_BAD_HDR);
235 MY_VALIDATE_PTR(pVtgHdr->pachStrTab, pVtgHdr->cbStrTab, 4, _1M, sizeof(char), VERR_SUPDRV_VTG_BAD_HDR);
236 MY_VALIDATE_PTR(pVtgHdr->paArgLists, pVtgHdr->cbArgLists, 1, _32K, sizeof(uint32_t), VERR_SUPDRV_VTG_BAD_HDR);
237
238 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs, VERR_SUPDRV_VTG_BAD_HDR_PTR);
239 MY_WITHIN_IMAGE(pVtgHdr->paProbLocsEnd, VERR_SUPDRV_VTG_BAD_HDR_PTR);
240 if ((uintptr_t)pVtgHdr->paProbLocs > (uintptr_t)pVtgHdr->paProbLocsEnd)
241 {
242 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_HDR_PTR - paProbeLocs=%p > paProbLocsEnd=%p\n",
243 pVtgHdr->paProbLocs, pVtgHdr->paProbLocsEnd);
244 return VERR_SUPDRV_VTG_BAD_HDR_PTR;
245 }
246 cbTmp = (uintptr_t)pVtgHdr->paProbLocsEnd - (uintptr_t)pVtgHdr->paProbLocs;
247 if (cbTmp < sizeof(VTGPROBELOC))
248 {
249 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW - cbTmp=%#zx paProbeLocs=%p paProbLocsEnd=%p\n",
250 cbTmp, pVtgHdr->paProbLocs, pVtgHdr->paProbLocsEnd);
251 return VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW;
252 }
253 if (cbTmp >= _128K * sizeof(VTGPROBELOC))
254 {
255 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH - cbTmp=%#zx paProbeLocs=%p paProbLocsEnd=%p\n",
256 cbTmp, pVtgHdr->paProbLocs, pVtgHdr->paProbLocsEnd);
257 return VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH;
258 }
259 if (cbTmp / sizeof(VTGPROBELOC) * sizeof(VTGPROBELOC) != cbTmp)
260 {
261 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE - cbTmp=%#zx cbUnit=%#zx paProbeLocs=%p paProbLocsEnd=%p\n",
262 cbTmp, sizeof(VTGPROBELOC), pVtgHdr->paProbLocs, pVtgHdr->paProbLocsEnd);
263 return VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE;
264 }
265
266 if (pVtgHdr->cbProbes / sizeof(VTGDESCPROBE) != pVtgHdr->cbProbeEnabled)
267 {
268 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_VTG_BAD_HDR - cbProbeEnabled=%#zx cbProbes=%#zx\n",
269 pVtgHdr->cbProbeEnabled, pVtgHdr->cbProbes);
270 return VERR_SUPDRV_VTG_BAD_HDR;
271 }
272
273 /*
274 * Validate the providers.
275 */
276 cProviders = i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
277 while (i-- > 0)
278 {
279 MY_VALIDATE_STR(pVtgHdr->paProviders[i].offName);
280 if (pVtgHdr->paProviders[i].iFirstProbe >= pVtgHdr->cbProbeEnabled)
281 return VERR_SUPDRV_VTG_BAD_PROVIDER;
282 if (pVtgHdr->paProviders[i].iFirstProbe + pVtgHdr->paProviders[i].cProbes > pVtgHdr->cbProbeEnabled)
283 return VERR_SUPDRV_VTG_BAD_PROVIDER;
284 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrSelf);
285 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrModules);
286 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrFunctions);
287 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrNames);
288 MY_VALIDATE_ATTR(pVtgHdr->paProviders[i].AttrArguments);
289 if (pVtgHdr->paProviders[i].bReserved)
290 return VERR_SUPDRV_VTG_BAD_PROVIDER;
291 }
292
293 /*
294 * Validate probes.
295 */
296 i = pVtgHdr->cbProbes / sizeof(VTGDESCPROBE);
297 while (i-- > 0)
298 {
299 PVTGDESCARGLIST pArgList;
300 unsigned iArg;
301 bool fHaveLargeArgs;
302
303 MY_VALIDATE_STR(pVtgHdr->paProbes[i].offName);
304 if (pVtgHdr->paProbes[i].offArgList >= pVtgHdr->cbArgLists)
305 return VERR_SUPDRV_VTG_BAD_PROBE;
306 if (pVtgHdr->paProbes[i].offArgList & 3)
307 return VERR_SUPDRV_VTG_BAD_PROBE;
308 if (pVtgHdr->paProbes[i].idxEnabled != i) /* The lists are parallel. */
309 return VERR_SUPDRV_VTG_BAD_PROBE;
310 if (pVtgHdr->paProbes[i].idxProvider >= cProviders)
311 return VERR_SUPDRV_VTG_BAD_PROBE;
312 if ( i - pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].iFirstProbe
313 >= pVtgHdr->paProviders[pVtgHdr->paProbes[i].idxProvider].cProbes)
314 return VERR_SUPDRV_VTG_BAD_PROBE;
315 if (pVtgHdr->paProbes[i].u32User)
316 return VERR_SUPDRV_VTG_BAD_PROBE;
317
318 /* The referenced argument list. */
319 pArgList = (PVTGDESCARGLIST)((uintptr_t)pVtgHdr->paArgLists + pVtgHdr->paProbes[i].offArgList);
320 if (pArgList->cArgs > 16)
321 return VERR_SUPDRV_VTG_BAD_ARGLIST;
322 if (pArgList->fHaveLargeArgs >= 2)
323 return VERR_SUPDRV_VTG_BAD_ARGLIST;
324 if ( pArgList->abReserved[0]
325 || pArgList->abReserved[1])
326 return VERR_SUPDRV_VTG_BAD_ARGLIST;
327 fHaveLargeArgs = false;
328 iArg = pArgList->cArgs;
329 while (iArg-- > 0)
330 {
331 rc = VINF_SUCCESS;
332 MY_VALIDATE_STR(pArgList->aArgs[iArg].offType);
333 switch (pArgList->aArgs[iArg].fType & VTG_TYPE_SIZE_MASK)
334 {
335 case 0:
336 if (!(pArgList->aArgs[iArg].fType & VTG_TYPE_FIXED_SIZED))
337 rc = VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
338 break;
339 case 1: case 2: case 4: case 8:
340 break;
341 default:
342 rc = VERR_SUPDRV_TRACER_BAD_ARG_FLAGS;
343 }
344 if (RT_FAILURE(rc))
345 {
346 SUPR0Printf("supdrvVtgValidate: VERR_SUPDRV_TRACER_BAD_ARG_FLAGS - fType=%#x iArg=%u iProbe=%u\n",
347 pArgList->aArgs[iArg].fType, iArg, i);
348 return rc;
349 }
350 if (VTG_TYPE_IS_LARGE(pArgList->aArgs[iArg].fType))
351 fHaveLargeArgs = true;
352 }
353 if ((uint8_t)fHaveLargeArgs != pArgList->fHaveLargeArgs)
354 return VERR_SUPDRV_VTG_BAD_PROBE;
355 }
356
357 /*
358 * Check that pafProbeEnabled is all zero.
359 */
360 i = pVtgHdr->cbProbeEnabled;
361 while (i-- > 0)
362 if (pVtgHdr->pafProbeEnabled[0])
363 return VERR_SUPDRV_VTG_BAD_PROBE_ENABLED;
364
365 /*
366 * Probe locations.
367 */
368 i = pVtgHdr->paProbLocsEnd - pVtgHdr->paProbLocs;
369 while (i-- > 0)
370 {
371 if (pVtgHdr->paProbLocs[i].uLine >= _1G)
372 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
373 if (pVtgHdr->paProbLocs[i].fEnabled)
374 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
375 if (pVtgHdr->paProbLocs[i].idProbe != UINT32_MAX)
376 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
377 MY_WITHIN_IMAGE(pVtgHdr->paProbLocs[i].pszFunction, VERR_SUPDRV_VTG_BAD_PROBE_LOC);
378 offTmp = (uintptr_t)pVtgHdr->paProbLocs[i].pbProbe - (uintptr_t)pVtgHdr->paProbes;
379 if (offTmp >= pVtgHdr->cbProbes)
380 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
381 if (offTmp / sizeof(VTGDESCPROBE) * sizeof(VTGDESCPROBE) != offTmp)
382 return VERR_SUPDRV_VTG_BAD_PROBE_LOC;
383 }
384
385 return VINF_SUCCESS;
386#undef MY_VALIDATE_STR
387#undef MY_VALIDATE_PTR
388#undef MY_WITHIN_IMAGE
389}
390
391
392/**
393 * Gets a string from the string table.
394 *
395 * @returns Pointer to the string.
396 * @param pVtgHdr The VTG object header.
397 * @param offStrTab The string table offset.
398 */
399static const char *supdrvVtgGetString(PVTGOBJHDR pVtgHdr, uint32_t offStrTab)
400{
401 Assert(offStrTab < pVtgHdr->cbStrTab);
402 return &pVtgHdr->pachStrTab[offStrTab];
403}
404
405
406/**
407 * Frees the provider structure and associated resources.
408 *
409 * @param pProv The provider to free.
410 */
411static void supdrvTracerFreeProvider(PSUPDRVTPPROVIDER pProv)
412{
413 LOG_TRACER(("Freeing tracepoint provider '%s' / %p\n", pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
414 pProv->fRegistered = false;
415 pProv->fZombie = true;
416 pProv->Core.pDesc = NULL;
417 pProv->Core.pHdr = NULL;
418 RT_ZERO(pProv->Core.TracerData);
419 RTMemFree(pProv);
420}
421
422
423/**
424 * Deregisters a provider.
425 *
426 * If the provider is still busy, it will be put in the zombie list.
427 *
428 * @param pDevExt The device extension.
429 * @param pProv The provider.
430 *
431 * @remarks The caller owns mtxTracer.
432 */
433static void supdrvTracerDeregisterVtgObj(PSUPDRVDEVEXT pDevExt, PSUPDRVTPPROVIDER pProv)
434{
435 int rc;
436 if (!pProv->fRegistered || !pDevExt->pTracerOps)
437 rc = VINF_SUCCESS;
438 else
439 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
440 if (RT_SUCCESS(rc))
441 {
442 supdrvTracerFreeProvider(pProv);
443 return;
444 }
445
446 pProv->fZombie = true;
447 RTListAppend(&pDevExt->TracerProviderZombieList, &pProv->ListEntry);
448 LOG_TRACER(("Invalidated provider '%s' / %p and put it on the zombie list (rc=%Rrc)\n",
449 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
450}
451
452
453/**
454 * Processes the zombie list.
455 *
456 * @param pDevExt The device extension.
457 */
458static void supdrvTracerProcessZombies(PSUPDRVDEVEXT pDevExt)
459{
460 PSUPDRVTPPROVIDER pProv, pProvNext;
461
462 RTSemFastMutexRequest(pDevExt->mtxTracer);
463 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
464 {
465 int rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
466 if (RT_SUCCESS(rc))
467 {
468 RTListNodeRemove(&pProv->ListEntry);
469 supdrvTracerFreeProvider(pProv);
470 }
471 }
472 RTSemFastMutexRelease(pDevExt->mtxTracer);
473}
474
475
476/**
477 * Unregisters all providers, including zombies, waiting for busy providers to
478 * go idle and unregister smoothly.
479 *
480 * This may block.
481 *
482 * @param pDevExt The device extension.
483 */
484static void supdrvTracerRemoveAllProviders(PSUPDRVDEVEXT pDevExt)
485{
486 uint32_t i;
487 PSUPDRVTPPROVIDER pProv;
488 PSUPDRVTPPROVIDER pProvNext;
489
490 /*
491 * Unregister all probes (there should only be one).
492 */
493 RTSemFastMutexRequest(pDevExt->mtxTracer);
494 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
495 {
496 RTListNodeRemove(&pProv->ListEntry);
497 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
498 }
499 RTSemFastMutexRelease(pDevExt->mtxTracer);
500
501 /*
502 * Try unregister zombies now, sleep on busy ones and tracer opens.
503 */
504 for (i = 0; ; i++)
505 {
506 bool fEmpty;
507
508 RTSemFastMutexRequest(pDevExt->mtxTracer);
509
510 /* Zombies */
511 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
512 {
513 int rc;
514 LOG_TRACER(("supdrvTracerRemoveAllProviders: Attemting to unregister '%s' / %p...\n",
515 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
516
517 if (pDevExt->pTracerOps)
518 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
519 else
520 rc = VINF_SUCCESS;
521 if (!rc)
522 {
523 RTListNodeRemove(&pProv->ListEntry);
524 supdrvTracerFreeProvider(pProv);
525 }
526 else if (!(i & 0xf))
527 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on busy provider '%s' / %p (rc=%d)\n",
528 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
529 else
530 LOG_TRACER(("supdrvTracerRemoveAllProviders: Failed to unregister provider '%s' / %p - rc=%d\n",
531 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
532 }
533
534 fEmpty = RTListIsEmpty(&pDevExt->TracerProviderZombieList);
535
536 /* Tracer opens. */
537 if ( pDevExt->cTracerOpens
538 && pDevExt->pTracerOps)
539 {
540 fEmpty = false;
541 if (!(i & 0xf))
542 SUPR0Printf("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens);
543 else
544 LOG_TRACER(("supdrvTracerRemoveAllProviders: Waiting on %u opens\n", pDevExt->cTracerOpens));
545 }
546
547 RTSemFastMutexRelease(pDevExt->mtxTracer);
548
549 if (fEmpty)
550 break;
551
552 /* Delay...*/
553 RTThreadSleep(1000);
554 }
555}
556
557
558/**
559 * Registers the VTG tracepoint providers of a driver.
560 *
561 * @returns VBox status code.
562 * @param pszName The driver name.
563 * @param pVtgHdr The VTG object header.
564 * @param pVtgObj The size of the VTG object.
565 * @param pImage The image if applicable.
566 * @param pSession The session if applicable.
567 * @param pszModName The module name.
568 */
569static int supdrvTracerRegisterVtgObj(PSUPDRVDEVEXT pDevExt, PVTGOBJHDR pVtgHdr, size_t cbVtgObj, PSUPDRVLDRIMAGE pImage,
570 PSUPDRVSESSION pSession, const char *pszModName)
571{
572 int rc;
573 uintptr_t i;
574 PSUPDRVTPPROVIDER pProv;
575
576 /*
577 * Validate input.
578 */
579 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
580 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
581 AssertPtrNullReturn(pImage, VERR_INVALID_POINTER);
582 AssertPtrNullReturn(pSession, VERR_INVALID_POINTER);
583 AssertPtrReturn(pszModName, VERR_INVALID_POINTER);
584
585 if (pImage)
586 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, (const uint8_t *)pImage->pvImage, pImage->cbImageBits);
587 else
588 rc = supdrvVtgValidate(pVtgHdr, cbVtgObj, NULL, 0);
589 if (RT_FAILURE(rc))
590 return rc;
591
592 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
593 if (RT_FAILURE(rc))
594 return rc;
595 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
596 {
597 if (pProv->Core.pHdr == pVtgHdr)
598 {
599 rc = VERR_SUPDRV_VTG_ALREADY_REGISTERED;
600 break;
601 }
602 if ( pProv->pSession == pSession
603 && pProv->pImage == pImage)
604 {
605 rc = VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION;
606 break;
607 }
608 }
609 RTSemFastMutexRelease(pDevExt->mtxTracer);
610 if (RT_FAILURE(rc))
611 return rc;
612
613 /*
614 * Register the providers.
615 */
616 i = pVtgHdr->cbProviders / sizeof(VTGDESCPROVIDER);
617 while (i-- > 0)
618 {
619 PVTGDESCPROVIDER pDesc = &pVtgHdr->paProviders[i];
620 const char *pszName = supdrvVtgGetString(pVtgHdr, pDesc->offName);
621 size_t const cchName = strlen(pszName);
622 pProv = (PSUPDRVTPPROVIDER)RTMemAllocZ(RT_OFFSETOF(SUPDRVTPPROVIDER, szName[cchName + 1]));
623 if (pProv)
624 {
625 pProv->Core.pDesc = pDesc;
626 pProv->Core.pHdr = pVtgHdr;
627 pProv->Core.pszName = &pProv->szName[0];
628 pProv->Core.pszModName = pszModName;
629 pProv->pImage = pImage;
630 pProv->pSession = pSession;
631 pProv->fZombie = false;
632 pProv->fRegistered = true;
633 memcpy(&pProv->szName[0], pszName, cchName + 1);
634
635 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
636 if (RT_SUCCESS(rc))
637 {
638 if ( pDevExt->pTracerOps
639 && !pDevExt->fTracerUnloading)
640 rc = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
641 else
642 {
643 pProv->fRegistered = false;
644 rc = VINF_SUCCESS;
645 }
646 if (RT_SUCCESS(rc))
647 {
648 RTListAppend(&pDevExt->TracerProviderList, &pProv->ListEntry);
649 RTSemFastMutexRelease(pDevExt->mtxTracer);
650 LOG_TRACER(("Registered tracepoint provider '%s' in '%s' -> %p\n",
651 pProv->szName, pszModName, pProv->Core.TracerData.DTrace.idProvider));
652 }
653 else
654 {
655 RTSemFastMutexRelease(pDevExt->mtxTracer);
656 LOG_TRACER(("Failed to register tracepoint provider '%s' in '%s' -> %Rrc\n",
657 pProv->szName, pszModName, rc));
658 RTMemFree(pProv);
659 }
660 }
661 }
662 else
663 rc = VERR_NO_MEMORY;
664
665 if (RT_FAILURE(rc))
666 {
667 PSUPDRVTPPROVIDER pProvNext;
668 supdrvTracerFreeProvider(pProv);
669
670 RTSemFastMutexRequest(pDevExt->mtxTracer);
671 RTListForEachReverseSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
672 {
673 if (pProv->Core.pHdr == pVtgHdr)
674 {
675 RTListNodeRemove(&pProv->ListEntry);
676 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
677 }
678 }
679 RTSemFastMutexRelease(pDevExt->mtxTracer);
680 return rc;
681 }
682 }
683
684 return VINF_SUCCESS;
685}
686
687
688/**
689 * Registers the VTG tracepoint providers of a driver.
690 *
691 * @returns VBox status code.
692 * @param pSession The support driver session handle.
693 * @param pVtgHdr The VTG header.
694 * @param pszName The driver name.
695 */
696SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, PVTGOBJHDR pVtgHdr, const char *pszName)
697{
698 int rc;
699
700 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
701 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
702 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
703 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
704 LOG_TRACER(("SUPR0TracerRegisterDrv: pSession=%p pVtgHdr=%p pszName=%s\n", pSession, pVtgHdr, pszName));
705
706 rc = supdrvTracerRegisterVtgObj(pSession->pDevExt, pVtgHdr, _1M, NULL /*pImage*/, pSession, pszName);
707
708 /*
709 * Try unregister zombies while we have a chance.
710 */
711 supdrvTracerProcessZombies(pSession->pDevExt);
712
713 return rc;
714}
715
716
717/**
718 * Deregister the VTG tracepoint providers of a driver.
719 *
720 * @param pSession The support driver session handle.
721 * @param pVtgHdr The VTG header.
722 */
723SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession)
724{
725 PSUPDRVTPPROVIDER pProv, pProvNext;
726 PSUPDRVDEVEXT pDevExt;
727 AssertReturnVoid(SUP_IS_SESSION_VALID(pSession));
728 AssertReturnVoid(pSession->R0Process == NIL_RTR0PROCESS);
729 LOG_TRACER(("SUPR0TracerDeregisterDrv: pSession=%p\n", pSession));
730
731 pDevExt = pSession->pDevExt;
732
733 /*
734 * Search for providers belonging to this driver session.
735 */
736 RTSemFastMutexRequest(pDevExt->mtxTracer);
737 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
738 {
739 if (pProv->pSession == pSession)
740 {
741 RTListNodeRemove(&pProv->ListEntry);
742 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
743 }
744 }
745 RTSemFastMutexRelease(pDevExt->mtxTracer);
746
747 /*
748 * Try unregister zombies while we have a chance.
749 */
750 supdrvTracerProcessZombies(pDevExt);
751}
752
753
754/**
755 * Registers the VTG tracepoint providers of a module loaded by
756 * the support driver.
757 *
758 * This should be called from the ModuleInit code.
759 *
760 * @returns VBox status code.
761 * @param hMod The module handle.
762 * @param pVtgHdr The VTG header.
763 */
764SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, PVTGOBJHDR pVtgHdr)
765{
766 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
767 PSUPDRVDEVEXT pDevExt;
768 uintptr_t cbVtgObj;
769 int rc;
770
771 LOG_TRACER(("SUPR0TracerRegisterModule: %p\n", pVtgHdr));
772
773 /*
774 * Validate input and context.
775 */
776 AssertPtrReturn(pImage, VERR_INVALID_HANDLE);
777 AssertPtrReturn(pVtgHdr, VERR_INVALID_POINTER);
778
779 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
780 pDevExt = pImage->pDevExt;
781 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
782 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
783 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
784
785 /*
786 * Calculate the max VTG object size and hand it over to the common code.
787 */
788 cbVtgObj = (uintptr_t)pVtgHdr - (uintptr_t)pImage->pvImage;
789 AssertMsgReturn(cbVtgObj /*off*/ < pImage->cbImageBits,
790 ("pVtgHdr=%p offVtgObj=%p cbImageBits=%p\n", pVtgHdr, cbVtgObj, pImage->cbImageBits),
791 VERR_INVALID_PARAMETER);
792 cbVtgObj = pImage->cbImageBits - cbVtgObj;
793
794 rc = supdrvTracerRegisterVtgObj(pDevExt, pVtgHdr, cbVtgObj, pImage, NULL, pImage->szName);
795 LOG_TRACER(("SUPR0TracerRegisterModule: rc=%d\n", rc));
796
797 /*
798 * Try unregister zombies while we have a chance.
799 */
800 supdrvTracerProcessZombies(pDevExt);
801
802 return rc;
803}
804
805
806/**
807 * Registers the tracer implementation.
808 *
809 * This should be called from the ModuleInit code or from a ring-0 session.
810 *
811 * @returns VBox status code.
812 * @param hMod The module handle.
813 * @param pSession Ring-0 session handle.
814 * @param pReg Pointer to the tracer registration structure.
815 * @param ppHlp Where to return the tracer helper method table.
816 */
817SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp)
818{
819 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
820 PSUPDRVDEVEXT pDevExt;
821 PSUPDRVTPPROVIDER pProv;
822 int rc;
823
824 /*
825 * Validate input and context.
826 */
827 AssertPtrReturn(ppHlp, VERR_INVALID_POINTER);
828 *ppHlp = NULL;
829 AssertPtrReturn(pReg, VERR_INVALID_HANDLE);
830
831 if (pImage)
832 {
833 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
834 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
835 pDevExt = pImage->pDevExt;
836 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
837 AssertReturn(pDevExt->pLdrInitImage == pImage, VERR_WRONG_ORDER);
838 AssertReturn(pDevExt->hLdrInitThread == RTThreadNativeSelf(), VERR_WRONG_ORDER);
839 }
840 else
841 {
842 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
843 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
844 pDevExt = pSession->pDevExt;
845 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
846 }
847
848 AssertReturn(pReg->u32Magic == SUPDRVTRACERREG_MAGIC, VERR_INVALID_MAGIC);
849 AssertReturn(pReg->u32Version == SUPDRVTRACERREG_VERSION, VERR_VERSION_MISMATCH);
850 AssertReturn(pReg->uEndMagic == SUPDRVTRACERREG_MAGIC, VERR_VERSION_MISMATCH);
851 AssertPtrReturn(pReg->pfnProbeFireKernel, VERR_INVALID_POINTER);
852 AssertPtrReturn(pReg->pfnProbeFireUser, VERR_INVALID_POINTER);
853 AssertPtrReturn(pReg->pfnTracerOpen, VERR_INVALID_POINTER);
854 AssertPtrReturn(pReg->pfnTracerIoCtl, VERR_INVALID_POINTER);
855 AssertPtrReturn(pReg->pfnTracerClose, VERR_INVALID_POINTER);
856 AssertPtrReturn(pReg->pfnProviderRegister, VERR_INVALID_POINTER);
857 AssertPtrReturn(pReg->pfnProviderDeregister, VERR_INVALID_POINTER);
858 AssertPtrReturn(pReg->pfnProviderDeregisterZombie, VERR_INVALID_POINTER);
859
860 /*
861 * Do the job.
862 */
863 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
864 if (RT_SUCCESS(rc))
865 {
866 if (!pDevExt->pTracerOps)
867 {
868 LOG_TRACER(("SUPR0TracerRegisterImpl: pReg=%p\n", pReg));
869 pDevExt->pTracerOps = pReg;
870 pDevExt->pTracerSession = pSession;
871 pDevExt->pTracerImage = pImage;
872
873 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
874
875 *ppHlp = &pDevExt->TracerHlp;
876 rc = VINF_SUCCESS;
877
878 /*
879 * Iterate the already loaded modules and register their providers.
880 */
881 RTListForEach(&pDevExt->TracerProviderList, pProv, SUPDRVTPPROVIDER, ListEntry)
882 {
883 Assert(!pProv->fRegistered);
884 pProv->fRegistered = true;
885 int rc2 = pDevExt->pTracerOps->pfnProviderRegister(pDevExt->pTracerOps, &pProv->Core);
886 if (RT_FAILURE(rc2))
887 {
888 pProv->fRegistered = false;
889 SUPR0Printf("SUPR0TracerRegisterImpl: Failed to register provider %s::%s - rc=%d\n",
890 pProv->Core.pszModName, pProv->szName, rc2);
891 }
892 }
893 }
894 else
895 rc = VERR_SUPDRV_TRACER_ALREADY_REGISTERED;
896 RTSemFastMutexRelease(pDevExt->mtxTracer);
897 }
898
899 return rc;
900
901}
902
903
904/**
905 * Common tracer implementation deregistration code.
906 *
907 * The caller sets fTracerUnloading prior to calling this function.
908 *
909 * @param pDevExt The device extension structure.
910 */
911static void supdrvTracerCommonDeregisterImpl(PSUPDRVDEVEXT pDevExt)
912{
913 uint32_t i;
914 PSUPDRVTPPROVIDER pProv;
915 PSUPDRVTPPROVIDER pProvNext;
916
917 RTSemFastMutexRequest(pDevExt->mtxTracer);
918
919 /*
920 * Reinstall the stub probe-fire function.
921 */
922 g_pfnSupdrvProbeFireKernel = supdrvTracerProbeFireStub;
923
924 /*
925 * Disassociate the tracer implementation from all providers.
926 * We will have to wait on busy providers.
927 */
928 for (i = 0; ; i++)
929 {
930 uint32_t cZombies = 0;
931
932 /* Live providers. */
933 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
934 {
935 int rc;
936 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p...\n",
937 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
938
939 if (!pProv->fRegistered)
940 continue;
941 if (!pProv->fZombie)
942 {
943 rc = pDevExt->pTracerOps->pfnProviderDeregister(pDevExt->pTracerOps, &pProv->Core);
944 if (RT_FAILURE(rc))
945 pProv->fZombie = true;
946 }
947 else
948 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
949 if (RT_SUCCESS(rc))
950 pProv->fZombie = pProv->fRegistered = false;
951 else
952 {
953 cZombies++;
954 if (!(i & 0xf))
955 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
956 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
957 else
958 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
959 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
960 }
961 }
962
963 /* Zombies providers. */
964 RTListForEachSafe(&pDevExt->TracerProviderZombieList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
965 {
966 int rc;
967 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Attemting to unregister '%s' / %p (zombie)...\n",
968 pProv->szName, pProv->Core.TracerData.DTrace.idProvider));
969
970 rc = pDevExt->pTracerOps->pfnProviderDeregisterZombie(pDevExt->pTracerOps, &pProv->Core);
971 if (RT_SUCCESS(rc))
972 {
973 RTListNodeRemove(&pProv->ListEntry);
974 supdrvTracerFreeProvider(pProv);
975 }
976 else
977 {
978 cZombies++;
979 if (!(i & 0xf))
980 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on busy provider '%s' / %p (rc=%d)\n",
981 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc);
982 else
983 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Failed to unregister provider '%s' / %p - rc=%d\n",
984 pProv->szName, pProv->Core.TracerData.DTrace.idProvider, rc));
985 }
986 }
987
988 /* Tracer opens. */
989 if (pDevExt->cTracerOpens)
990 {
991 cZombies++;
992 if (!(i & 0xf))
993 SUPR0Printf("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens);
994 else
995 LOG_TRACER(("supdrvTracerCommonDeregisterImpl: Waiting on %u opens\n", pDevExt->cTracerOpens));
996 }
997
998 /* Done? */
999 if (cZombies == 0)
1000 break;
1001
1002 /* Delay...*/
1003 RTSemFastMutexRelease(pDevExt->mtxTracer);
1004 RTThreadSleep(1000);
1005 RTSemFastMutexRequest(pDevExt->mtxTracer);
1006 }
1007
1008 /*
1009 * Deregister the tracer implementation.
1010 */
1011 pDevExt->pTracerImage = NULL;
1012 pDevExt->pTracerSession = NULL;
1013 pDevExt->pTracerOps = NULL;
1014 pDevExt->fTracerUnloading = false;
1015
1016 RTSemFastMutexRelease(pDevExt->mtxTracer);
1017}
1018
1019
1020/**
1021 * Deregister a tracer implementation.
1022 *
1023 * This should be called from the ModuleTerm code or from a ring-0 session.
1024 *
1025 * @returns VBox status code.
1026 * @param hMod The module handle.
1027 * @param pSession Ring-0 session handle.
1028 */
1029SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession)
1030{
1031 PSUPDRVLDRIMAGE pImage = (PSUPDRVLDRIMAGE)hMod;
1032 PSUPDRVDEVEXT pDevExt;
1033 int rc;
1034
1035 /*
1036 * Validate input and context.
1037 */
1038 if (pImage)
1039 {
1040 AssertPtrReturn(pImage, VERR_INVALID_POINTER);
1041 AssertReturn(pSession == NULL, VERR_INVALID_PARAMETER);
1042 pDevExt = pImage->pDevExt;
1043 }
1044 else
1045 {
1046 AssertReturn(SUP_IS_SESSION_VALID(pSession), VERR_INVALID_PARAMETER);
1047 AssertReturn(pSession->R0Process == NIL_RTR0PROCESS, VERR_INVALID_PARAMETER);
1048 pDevExt = pSession->pDevExt;
1049 }
1050 AssertPtrReturn(pDevExt, VERR_INVALID_POINTER);
1051
1052 /*
1053 * Do the job.
1054 */
1055 rc = RTSemFastMutexRequest(pDevExt->mtxTracer);
1056 if (RT_SUCCESS(rc))
1057 {
1058 if ( pImage
1059 ? pDevExt->pTracerImage == pImage
1060 : pDevExt->pTracerSession == pSession)
1061 {
1062 LOG_TRACER(("SUPR0TracerDeregisterImpl: Unloading ...\n"));
1063 pDevExt->fTracerUnloading = true;
1064 RTSemFastMutexRelease(pDevExt->mtxTracer);
1065 supdrvTracerCommonDeregisterImpl(pDevExt);
1066 LOG_TRACER(("SUPR0TracerDeregisterImpl: ... done.\n"));
1067 }
1068 else
1069 {
1070 rc = VERR_SUPDRV_TRACER_NOT_REGISTERED;
1071 RTSemFastMutexRelease(pDevExt->mtxTracer);
1072 }
1073 }
1074
1075 return rc;
1076}
1077
1078
1079/*
1080 * The probe function is a bit more fun since we need tail jump optimizating.
1081 *
1082 * Since we cannot ship yasm sources for linux and freebsd, owing to the cursed
1083 * rebuilding of the kernel module from scratch at install time, we have to
1084 * deploy some ugly gcc inline assembly here.
1085 */
1086#if defined(__GNUC__) && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX))
1087__asm__("\
1088 .section .text \n\
1089 \n\
1090 .p2align 2,,3 \n\
1091 .global SUPR0TracerFireProbe \n\
1092SUPR0TracerFireProbe: \n\
1093");
1094# if defined(RT_ARCH_AMD64)
1095__asm__(" \
1096 movq g_pfnSupdrvProbeFireKernel(%rip), %rax \n\
1097 jmp *%rax \n\
1098");
1099# elif defined(RT_ARCH_X86)
1100__asm__("\
1101 movl g_pfnSupdrvProbeFireKernel, %eax \n\
1102 jmp *%eax \n\
1103");
1104# else
1105# error "Which arch is this?"
1106# endif
1107__asm__("\
1108 \n\
1109 .type supdrvTracerProbeFireStub,@function \n\
1110 .global supdrvTracerProbeFireStub \n\
1111supdrvTracerProbeFireStub: \n\
1112 ret \n\
1113 \n\
1114 .previous \n\
1115");
1116# if 0 /* Slickedit on windows highlighting fix */
1117 )
1118# endif
1119#endif
1120
1121
1122/**
1123 * Module unloading hook, called after execution in the module have ceased.
1124 *
1125 * @param pDevExt The device extension structure.
1126 * @param pImage The image being unloaded.
1127 */
1128void VBOXCALL supdrvTracerModuleUnloading(PSUPDRVDEVEXT pDevExt, PSUPDRVLDRIMAGE pImage)
1129{
1130 PSUPDRVTPPROVIDER pProv, pProvNext;
1131 AssertPtrReturnVoid(pImage); /* paranoia */
1132
1133 RTSemFastMutexRequest(pDevExt->mtxTracer);
1134
1135 /*
1136 * If it is the tracer image, we have to unload all the providers.
1137 */
1138 if (pDevExt->pTracerImage == pImage)
1139 {
1140 LOG_TRACER(("supdrvTracerModuleUnloading: Unloading tracer ...\n"));
1141 pDevExt->fTracerUnloading = true;
1142 RTSemFastMutexRelease(pDevExt->mtxTracer);
1143 supdrvTracerCommonDeregisterImpl(pDevExt);
1144 LOG_TRACER(("supdrvTracerModuleUnloading: ... done.\n"));
1145 }
1146 else
1147 {
1148 /*
1149 * Unregister all providers belonging to this image.
1150 */
1151 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1152 {
1153 if (pProv->pImage == pImage)
1154 {
1155 RTListNodeRemove(&pProv->ListEntry);
1156 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1157 }
1158 }
1159
1160 RTSemFastMutexRelease(pDevExt->mtxTracer);
1161
1162 /*
1163 * Try unregister zombies while we have a chance.
1164 */
1165 supdrvTracerProcessZombies(pDevExt);
1166 }
1167}
1168
1169
1170/**
1171 * Called when a session is being cleaned up.
1172 *
1173 * @param pDevExt The device extension structure.
1174 * @param pSession The session that is being torn down.
1175 */
1176void VBOXCALL supdrvTracerCleanupSession(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1177{
1178 /*
1179 * If ring-0 session, make sure it has deregistered VTG objects and the tracer.
1180 */
1181 if (pSession->R0Process == NIL_RTR0PROCESS)
1182 {
1183 SUPDRVTPPROVIDER *pProvNext;
1184 SUPDRVTPPROVIDER *pProv;
1185
1186 RTSemFastMutexRequest(pDevExt->mtxTracer);
1187 RTListForEachSafe(&pDevExt->TracerProviderList, pProv, pProvNext, SUPDRVTPPROVIDER, ListEntry)
1188 {
1189 if (pProv->pSession == pSession)
1190 {
1191 RTListNodeRemove(&pProv->ListEntry);
1192 supdrvTracerDeregisterVtgObj(pDevExt, pProv);
1193 }
1194 }
1195 RTSemFastMutexRelease(pDevExt->mtxTracer);
1196
1197 (void)SUPR0TracerDeregisterImpl(NULL, pSession);
1198 }
1199
1200 /*
1201 * Clean up instance data the trace may have associated with the session.
1202 */
1203 if (pSession->uTracerData)
1204 supdrvIOCtl_TracerClose(pDevExt, pSession);
1205}
1206
1207
1208/**
1209 * Open the tracer.
1210 *
1211 * @returns VBox status code
1212 * @param pDevExt The device extension structure.
1213 * @param pSession The current session.
1214 * @param uCookie The tracer cookie.
1215 * @param uArg The tracer open argument.
1216 */
1217int VBOXCALL supdrvIOCtl_TracerOpen(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg)
1218{
1219 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1220 int rc;
1221
1222 RTSemFastMutexRequest(pDevExt->mtxTracer);
1223
1224 if (!pSession->uTracerData)
1225 {
1226 if (pDevExt->pTracerOps)
1227 {
1228 if (pDevExt->pTracerSession != pSession)
1229 {
1230 if (!pDevExt->fTracerUnloading)
1231 {
1232 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1233 {
1234 pDevExt->cTracerOpens++;
1235 pSession->uTracerData = ~(uintptr_t)0;
1236 pSession->hTracerCaller = hNativeSelf;
1237 RTSemFastMutexRelease(pDevExt->mtxTracer);
1238
1239 rc = pDevExt->pTracerOps->pfnTracerOpen(pDevExt->pTracerOps, pSession, uCookie, uArg, &pSession->uTracerData);
1240
1241 RTSemFastMutexRequest(pDevExt->mtxTracer);
1242 if (RT_FAILURE(rc))
1243 {
1244 pDevExt->cTracerOpens--;
1245 pSession->uTracerData = 0;
1246 }
1247 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1248 }
1249 else
1250 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1251 }
1252 else
1253 rc = VERR_SUPDRV_TRACER_UNLOADING;
1254 }
1255 else
1256 rc = VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF;
1257 }
1258 else
1259 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1260 }
1261 else
1262 rc = VERR_SUPDRV_TRACER_ALREADY_OPENED;
1263
1264 RTSemFastMutexRelease(pDevExt->mtxTracer);
1265 return rc;
1266}
1267
1268
1269/**
1270 * Closes the tracer.
1271 *
1272 * @returns VBox status code.
1273 * @param pDevExt The device extension structure.
1274 * @param pSession The current session.
1275 */
1276int VBOXCALL supdrvIOCtl_TracerClose(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession)
1277{
1278 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1279 int rc;
1280
1281 RTSemFastMutexRequest(pDevExt->mtxTracer);
1282
1283 if (pSession->uTracerData)
1284 {
1285 Assert(pDevExt->cTracerOpens > 0);
1286
1287 if (pDevExt->pTracerOps)
1288 {
1289 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1290 {
1291 uintptr_t uTracerData = pSession->uTracerData;
1292 pSession->uTracerData = 0;
1293 pSession->hTracerCaller = hNativeSelf;
1294 RTSemFastMutexRelease(pDevExt->mtxTracer);
1295
1296 pDevExt->pTracerOps->pfnTracerClose(pDevExt->pTracerOps, pSession, uTracerData);
1297 rc = VINF_SUCCESS;
1298
1299 RTSemFastMutexRequest(pDevExt->mtxTracer);
1300 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1301 Assert(pDevExt->cTracerOpens > 0);
1302 pDevExt->cTracerOpens--;
1303 }
1304 else
1305 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1306 }
1307 else
1308 {
1309 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1310 pSession->uTracerData = 0;
1311 Assert(pDevExt->cTracerOpens > 0);
1312 pDevExt->cTracerOpens--;
1313 }
1314 }
1315 else
1316 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1317
1318 RTSemFastMutexRelease(pDevExt->mtxTracer);
1319 return rc;
1320}
1321
1322
1323/**
1324 * Performs a tracer I/O control request.
1325 *
1326 * @returns VBox status code.
1327 * @param pDevExt The device extension structure.
1328 * @param pSession The current session.
1329 * @param uCmd The tracer command.
1330 * @param uArg The tracer argument.
1331 * @param piRetVal Where to store the tracer specific return value.
1332 */
1333int VBOXCALL supdrvIOCtl_TracerIOCtl(PSUPDRVDEVEXT pDevExt, PSUPDRVSESSION pSession, uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)
1334{
1335 RTNATIVETHREAD hNativeSelf = RTThreadNativeSelf();
1336 int rc;
1337
1338 *piRetVal = 0;
1339 RTSemFastMutexRequest(pDevExt->mtxTracer);
1340
1341 if (pSession->uTracerData)
1342 {
1343 Assert(pDevExt->cTracerOpens > 0);
1344 if (pDevExt->pTracerOps)
1345 {
1346 if (!pDevExt->fTracerUnloading)
1347 {
1348 if (pSession->hTracerCaller == NIL_RTNATIVETHREAD)
1349 {
1350 uintptr_t uTracerData = pSession->uTracerData;
1351 pDevExt->cTracerOpens++;
1352 pSession->hTracerCaller = hNativeSelf;
1353 RTSemFastMutexRelease(pDevExt->mtxTracer);
1354
1355 rc = pDevExt->pTracerOps->pfnTracerIoCtl(pDevExt->pTracerOps, pSession, uTracerData, uCmd, uArg, piRetVal);
1356
1357 RTSemFastMutexRequest(pDevExt->mtxTracer);
1358 pSession->hTracerCaller = NIL_RTNATIVETHREAD;
1359 Assert(pDevExt->cTracerOpens > 0);
1360 pDevExt->cTracerOpens--;
1361 }
1362 else
1363 rc = VERR_SUPDRV_TRACER_SESSION_BUSY;
1364 }
1365 else
1366 rc = VERR_SUPDRV_TRACER_UNLOADING;
1367 }
1368 else
1369 rc = VERR_SUPDRV_TRACER_NOT_PRESENT;
1370 }
1371 else
1372 rc = VERR_SUPDRV_TRACER_NOT_OPENED;
1373
1374 RTSemFastMutexRelease(pDevExt->mtxTracer);
1375 return rc;
1376}
1377
1378
1379/**
1380 * Early module initialization hook.
1381 *
1382 * @returns VBox status code.
1383 * @param pDevExt The device extension structure.
1384 */
1385int VBOXCALL supdrvTracerInit(PSUPDRVDEVEXT pDevExt)
1386{
1387 /*
1388 * Initialize the tracer.
1389 */
1390 int rc = RTSemFastMutexCreate(&pDevExt->mtxTracer);
1391 if (RT_SUCCESS(rc))
1392 {
1393 pDevExt->TracerHlp.uVersion = SUPDRVTRACERHLP_VERSION;
1394 /** @todo */
1395 pDevExt->TracerHlp.uEndVersion = SUPDRVTRACERHLP_VERSION;
1396 RTListInit(&pDevExt->TracerProviderList);
1397 RTListInit(&pDevExt->TracerProviderZombieList);
1398
1399#ifdef VBOX_WITH_NATIVE_DTRACE_R0DRV
1400 pDevExt->pTracerOps = supdrvDTraceInit();
1401 if (pDevExt->pTracerOps)
1402 g_pfnSupdrvProbeFireKernel = (PFNRT)pDevExt->pTracerOps->pfnProbeFireKernel;
1403#endif
1404
1405 /*
1406 * Register the provider for this module, if compiled in.
1407 */
1408#ifdef VBOX_WITH_DTRACE_R0DRV
1409 rc = supdrvTracerRegisterVtgObj(pDevExt, &g_VTGObjHeader, _1M, NULL /*pImage*/, NULL /*pSession*/, "vboxdrv");
1410 if (RT_SUCCESS(rc))
1411 return rc;
1412 SUPR0Printf("supdrvTracerInit: supdrvTracerRegisterVtgObj failed with rc=%d\n", rc);
1413 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1414#else
1415
1416 return VINF_SUCCESS;
1417#endif
1418 }
1419 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1420 return rc;
1421}
1422
1423
1424/**
1425 * Late module termination hook.
1426 *
1427 * @returns VBox status code.
1428 * @param pDevExt The device extension structure.
1429 */
1430void VBOXCALL supdrvTracerTerm(PSUPDRVDEVEXT pDevExt)
1431{
1432 LOG_TRACER(("supdrvTracerTerm\n"));
1433
1434 supdrvTracerRemoveAllProviders(pDevExt);
1435
1436 RTSemFastMutexDestroy(pDevExt->mtxTracer);
1437 pDevExt->mtxTracer = NIL_RTSEMFASTMUTEX;
1438 LOG_TRACER(("supdrvTracerTerm: Done\n"));
1439}
1440
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